SBT configuration vs Ivy module configuration - configuration

This appears similar to sbt Configuration vs Ivy configuration, though it doesn't seem like this question is asked:
What is the difference between
libraryDependencies += "com.example" % "foo" % "1.0" % "test"
and
libraryDependencies in Test += "com.example" % "foo" % "1.0"
(And a similar question for IntegrationTest / "it".)
Should I always use SBT configuration, or Ivy configuration? Or does it depend on the particular case?
I have seen the former more often, though it seems that the latter is more consistent with the rest of my build.sbt.

update task and libraryDependencies are a bit odd ones because when you're downloading JARs you probably don't want to download Compile JARs and Test JARs independently or in parallel. For update task to handle all configurations, libraryDependencies needs to handle all configurations too.
libraryDependencies += "com.example" % "foo" % "1.0" % Test
means your project's Test configuration depends on the default configuration of "com.example" % "foo" % "1.0".
libraryDependencies in Test, I don't think would work.
Should I always use SBT configuration, or Ivy configuration? Or does it depend on the particular case?
There are notational differences, but conceptually sbt's configuration and Ivy configuration is the same thing.

Related

Trying to understand why a dependency's JAR file is not added to classpath

I'm trying to set up a Scala project which builds on the libGDX game engine using sbt. After adding the necessary dependencies and trying to instantiate LwjglApplication, it fails to load the shared library libgdx64.dylib, which contains some native code for my platform (macOS 10.13.6).
These are the dependencies I've declared:
libraryDependencies += "com.badlogicgames.gdx" % "gdx" % "1.9.14"
libraryDependencies += "com.badlogicgames.gdx" % "gdx-backend-lwjgl" % "1.9.14"
libraryDependencies += "com.badlogicgames.gdx" % "gdx-platform" % "1.9.14" % "natives-desktop"
This is the exception I get:
sbt:test_libgdx> run
[info] Compiling 1 Scala source to /Users/michi/Documents/Projects/Slick2D/test_libgdx/target/scala-2.13/classes ...
[info] running Main
[error] (run-main-3) com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load shared library 'libgdx64.dylib' for target: Mac OS X, 64-bit
[error] com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load shared library 'libgdx64.dylib' for target: Mac OS X, 64-bit
[error] at com.badlogic.gdx.utils.SharedLibraryLoader.load(SharedLibraryLoader.java:120)
[...]
With my limited knowledge of sbt, ivy and Maven artifacts I've investigated a bit and noticed that the JAR file containing libgdx64.dylib (gdx-platform-1.9.14-natives-desktop.jar) is not added to the classpath of the running application. I've narrowed it down to a minimal project setup which shows this problem:
$ ls
build.sbt project target
$ cat build.sbt
libraryDependencies += "com.badlogicgames.gdx" % "gdx-platform" % "1.9.14" % "natives-desktop"
$ sbt
[info] welcome to sbt 1.4.9 (AdoptOpenJDK Java 1.8.0_282)
[info] loading global plugins from [...]/.sbt/1.0/plugins
[info] loading project definition from [...]/test/project
[info] loading settings for project test from build.sbt ...
[info] set current project to test (in build file:[...]/test/)
[info] sbt server started at local://[...]/.sbt/1.0/server/dd1267d773c22c32c889/sock
[info] started sbt server
sbt:test> show compile:dependencyClasspath
[info] * Attributed([...]/.sbt/boot/scala-2.12.12/lib/scala-library.jar)
[success] Total time: 0 s, completed Mar 31, 2021 10:47:54 AM
sbt:test>
If I look in the maven repository at https://repo.maven.apache.org/... manually, I can see that JAR file.
What do I need to do to get that JAR file on the classpath so that the shared library can be loaded from it? Where's my mistake?
I have encountered the same issue - for sbt to comprehend an artifact with multiple builds (in this case, native binaries), instead of % you have to use a classifier:
libraryDependencies += "com.badlogicgames.gdx" % "gdx-platform" % "1.11.0" classifier "natives-desktop"

MySql driver not found for Scala program

I'm a newbie on Scala, am trying to use Spark to read from a mysql database. I'm facing a class-not-found exception whatever I do. I tried to connect without Spark, using Squeryl, Scalike, etc. Always the same problem.
Here's one example I tried :
logger.info("Write part")
val dataframe_mysql = spark.sqlContext
.read.format("jdbc")
.option("url", s"jdbc:mysql://${datamart_server}:3306/vol")
.option("driver", "com.mysql.jdbc.Driver")
.option("dbtable", "company")
.option("user", datamart_user).option("password", datamart_pwd)
.load()
dataframe_mysql.show()
I tried to put the driver classname in a src/main/resources/application.conf:
db.default.driver="com.mysql.jdbc.Driver"
But it didn't help. I've got :
java.sql.SQLException: No suitable driver
I also share the sbt file to show how I add the dependencies :
name := "commercial-api-datamart-feed"
version := "0.1"
scalaVersion := "2.11.6"
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.0"
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.1.3" % Runtime
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.0"
libraryDependencies += "org.apache.spark" %% "spark-core" % "2.3.0"
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.3.0"
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.24" % Runtime
Spark is not mandatory but I think it's better for performance.
How are you running this code? You'll need to pass the MySQL JAR as --jars; something like --jars /path/to/mysql.jar if starting up spark-shell or spark-submit.
If you prefer running a single JAR, you'll need to ensure that the MySQL JAR is embedded as part of your uber JAR. I've never used SBT but you'll need to check whether the final JAR created has the MySQL classes inside it -- if not, use the relevant SBT flags to make that happen.
You have to make sure the mysql dependencies exist on all of the executors. In my environment, I use maven and specify the dependency like this inside of my pom.xml:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
I then ensure that this dependency is bundled in my application jar (using the maven shade plugin), so that I don't have to place the jar on all of the executors.
Whether you use spark or not to access mysql over jdbc, you need to make sure the mysql-connector is available on your classpath, wherever you are executing mysql queries from.

Can't connect to mysql database with play-slick 1.0.1/slick 3.0 : configuration error

I'm trying to migrate from anorm to slick, using play 2.4.2, and getting a configuration error:
play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [dethcs]]
at play.api.Configuration$.configError(Configuration.scala:178) ~[play_2.11-2.4.0.jar:2.4.0]
...
Caused by: slick.SlickException: Error getting instance of Slick driver "slick.driver.MySQLDriver"
...
Caused by: java.lang.NoSuchMethodException: slick.driver.MySQLDriver.<init>()
Previous answers I've found on SO have focused on having the right MySQL driver and other dependencies. I believe my build.sbt covers the relevant bases, including:
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.36"
libraryDependencies += "com.typesafe.play" %% "play-slick" % "1.0.1"
libraryDependencies += "com.typesafe.play" %% "play-slick-evolutions" % "1.0.1"
The relevant lines in my application.conf are:
slick.dbs.dethcs.db.driver="com.mysql.jdbc.Driver"
slick.dbs.dethcs.driver="slick.driver.MySQLDriver"
slick.dbs.dethcs.user="redacted"
slick.dbs.dethcs.db.url="jdbc:mysql://localhost/mydb"
slick.dbs.dethcs.password="redacted"
I'd be grateful for any suggestions as to how to fix this -- I'm guessing it's something silly but I've found it very difficult to get documentation and examples that are specific to more recent versions of slick -- and could provide additional info if that would help.
I haven't tried myself, but it looks like you are referencing the MySQLDriver class instead of the corresponding object. Put a trailing $ in it and you should be good to go:
slick.dbs.dethcs.driver="slick.driver.MySQLDriver$"

"play test" classpath differs from "sbt test" classpath

Situation:
I want to execute JUnit test cases for my Play! 2.0 application on a Jenkins Server.
To build and test my app on the server I want to use SBT (with command sequence: clean compile test).
Problem:
Regardless of Jenkins, the command play test uses a different classpath than the command java -jar "sbt-launch.jar" test (both commands executed in the root directory of my play project, both commands use the same sbt version 0.12.2). My test cases can be compiled with play test but with java -jar "sbt-launch.jar" test the compiler complains that some JUnit classes (e.g., org.junit.rules.TestWatcher) are missing.
Analysis:
The command show test:full-classpath reveals that the classpathes indeed differ:
play test classpath contains: Attributed(<playhome>\repository\local\junit\junit-dep\4.10\jars\junit-dep.jar)
java -jar "sbt-launch.jar test classpath contains: Attributed(<userhome>\.ivy2\cache\junit\junit-dep\jars\junit-dep-4.8.2.jar)
Question:
Any ideas how to ensure that java -jar "sbt-launch.jar test uses the same classpath as play test?
Build.scala:
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "my app"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
// Play framework dependencies
javaCore, javaJdbc, javaEbean,
// Add your project dependencies here
"com.typesafe" %% "play-plugins-mailer" % "2.1.0",
"com.feth" %% "play-authenticate" % "0.2.5-SNAPSHOT",
"org.mongodb" % "mongo-java-driver" % "2.10.1",
"com.embedly" % "embedly-api" % "0.1.5",
"org.mockito" % "mockito-all" % "1.9.5",
"org.mongojack" % "mongojack" % "2.0.0-RC5",
"commons-io" % "commons-io" % "2.3"
)
val main = play.Project(appName, appVersion, appDependencies).settings(
resolvers += Resolver.url("play-easymail (release)", url("http://joscha.github.com/play-easymail/repo/releases/"))(Resolver.ivyStylePatterns),
resolvers += Resolver.url("play-easymail (snapshot)", url("http://joscha.github.com/play-easymail/repo/snapshots/"))(Resolver.ivyStylePatterns),
resolvers += Resolver.url("play-authenticate (release)", url("http://joscha.github.com/play-authenticate/repo/releases/"))(Resolver.ivyStylePatterns),
resolvers += Resolver.url("play-authenticate (snapshot)", url("http://joscha.github.com/play-authenticate/repo/snapshots/"))(Resolver.ivyStylePatterns)
)
}
The play script rewires sbt to use a local JUnit file repository in addition to any remote you've used. This is why the download is so large. Ivy, by default, will not copy local files into its local cache, as it assumes they are stable.
SO, what you're seeing is the sbt script which downloaded the file vs. the Play script which has its own local repo that takes priority over the downloaded file.
Now the fun part is around versioning. Ivy has interesting version conflict resolution.
If you paste you look in your target/resolution-cache/reports directory, you may get some insight into the difference between the two commands and why the one junit is chosen over another. My guess is there's a dynamic version range which is looking in the local repository for the play script and not finding the newer version of junit-dep.

Scala SBT: scala compiler version

I know that the scala swing libraries are present in scala 2.8:
[info] Building project chart 1.0 against Scala 2.8.1
[info] using sbt.DefaultProject with sbt 0.7.4 and Scala 2.7.7
So how come I'm getting this error:
[error] /src/main/scala/Chart.scala:2: value swing is not a member of package scala
[error] import scala.swing.Panel
Is it because SBT is using the wrong version of scala (i.e. 2.7.7)? If so, how do I configure it to use the correct version?
EDIT: Answer
Following Dylan Lacey's answer, I made the following file sbt/project/build/chart.scala:
import sbt._
class SamplesProject(info: ProjectInfo) extends DefaultProject(info)
{
val scalaSwing = "org.scala-lang" % "scala-swing" % "2.8.1"
}
Then I ran: sbt reload update from the shell.
Now things compile!
For sbt 0.11 (and presumably 0.10) then adding the following to build.sbt will do it:
libraryDependencies <+= scalaVersion { "org.scala-lang" % "scala-swing" % _ }
No. The version information reported on line 2 is just the version sbt was built with, it won't effect your build.
Because Swing is a package (Not part of the base classes) I suspect the problem is one of two things. Either:
Your build file doesn't specify that you want to use scala-swing and is getting confused. You can correct this by adding:
val scalaSwing = "org.scala-lang" % "scala-swing" % "packageVersion"
in your /project/build/projectName.scala (Thanks Janx!)
You've added the dependancy but have not yet downloaded the required package. To do this, you need sbt to reload your project definition and then get all required packages:
sbt reload update
If you need option 1, you'll likely need to also do option 2.
If neither of these work, you may have confused your local respository horribly. That can be fixed with a sbt clear-lib, but you will then re-download all your packages.