How to use SBT's libraryDependencyScheme key - sbt

I'm in library dependency hell right now with the following error:
[error] (server / update) found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[error]
[error] * com.lihaoyi:geny_2.13:1.0.0 (early-semver) is selected over 0.6.10
[error] +- com.lihaoyi:scalatags_2.13:0.12.0 (depends on 1.0.0)
[error] +- com.lihaoyi:fastparse_2.13:2.3.3 (depends on 0.6.10)
[error]
[error]
[error] this can be overridden using libraryDependencySchemes or evictionErrorLevel
I'm still stymied by how to use libraryDependencySchemes, as the error message suggests.
A search for libraryDependencySchemes in the SBT documentation comes up empty.
Preventing Version Conflict with VersionScheme is aimed primarily at library authors, not users. It has a short section at the end for users, but focuses on how to impose a dependency scheme when the library author has not. There's only one example, how to impose early-semver if the library author has not:
ThisBuild / libraryDependencySchemes += "io.circe" %% "circe-core" % "early-semver"
From elsewhere (e.g. this sbt issue) I gather that replacing "early-semver" in the above with "always" or VersionScheme.Always is
the correct way to specify "don't check the version compatibility of this library"
Unfortunately, that hasn't worked for me -- I get the same error.
The build for this project has several subprojects. Here's the relevant part of the build. Can anyone explain what's wrong and why?
lazy val xplatform = crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Full)
.in(file("_xplatform"))
.settings(commonSettings)
.settings(
libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always, // "early-semver",
libraryDependencies ++= Seq(
"com.lihaoyi" %%% "fastparse" % "2.3.3",
"com.lihaoyi" %%% "scalatags" % "0.12.0",
// some additional libraries omitted for brevity
),
jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv()
)
.jsSettings(
libraryDependencies ++= Seq(
"ca.bwbecker" %%% "jsFacadeOptionBuilder" % "0.9.6"
),
jsDependencies += "org.webjars" % "jquery" % "3.4.1" / "jquery.js" % "test"
)
.jsConfigure(_.enablePlugins(ScalaJSWeb, JSDependenciesPlugin))
Update:
After further testing, I realize that this is only occurring on the ScalaJS side of the project.
I've tried both of the following; no difference on the JVM side but neither work for ScalaJS.
libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always, // "early-semver",
libraryDependencySchemes += "com.lihaoyi" %%% "geny" % VersionScheme.Always, // "early-semver",

Turns out this is an SBT bug (as of 2023-01-26). Using
libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always
suppresses the error in a JVM-only build file. It doesn't work for anything involving Scala.JS.
See my bug report for a small working example (on the JVM) and failing (on Scala.JS).

Related

Having trouble loading library dependency gatling-grpc into my scala project

I am a newbie to the whole load testing world and trying to get gatling-grpc working within a scala script to be used within Taurus.
I am using IntelliJ as the IDE and SBT. I keep getting the following error when compiling my module with SBT:
[error] sbt.librarymanagement.ResolveException: Error downloading com.github.phisgr:gatling-grpc_2.13:0.9.0
Here is my current build.sbt:
PB.targets in Test := Seq(
scalapb.gen() -> (sourceManaged in Compile).value / "scalapb"
)
name := "cfd-gatling"
version := "0.1"
scalaVersion := "2.13.3"
scalacOptions := Seq(
"-encoding", "UTF-8", "-target:jvm-1.8", "-deprecation",
"-feature", "-unchecked", "-language:implicitConversions", "-language:postfixOps")
libraryDependencies ++= Seq(
"io.gatling.highcharts" % "gatling-charts-highcharts" % "3.4.0" % "test,it",
"io.gatling" % "gatling-test-framework" % "3.4.0" % "test,it",
"com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf",
"io.grpc" % "grpc-netty" % scalapb.compiler.Version.grpcJavaVersion,
"com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion,
"com.github.phisgr" %% "gatling-grpc" % "0.9.0" % "test,it")
enablePlugins(GatlingPlugin)
I was able to get this to download by changing the scalaVersion to match the scalaVersion used in gatling-grpc github repo.
The change was this:
instead of:
scalaVersion: "2.13.3"
I used:
scalaVersion: "2.12.10"
I restarted the IDE and recompiled the project via SBT and the package was there!

SBT dependencyOverrides in a scope doesn't seem to work as expected

I would like to have a different version of library in test scope.
I was hoping the simplified version of project descriptor could look like that.
Please mind it's a simplified view, in my real project it's more convoluted. I need to use dependencyOverrides to enforce certain library version.
import sbt._, Keys._
organization := "me"
name := "test"
version := "0.1"
libraryDependencies := Seq("ch.qos.logback" % "logback-classic" % "1.2.3")
dependencyOverrides := Seq(
"ch.qos.logback" % "logback-classic" % "1.2.2"
)
dependencyOverrides in Test := Seq(
"ch.qos.logback" % "logback-classic" % "1.2.1"
)
I'd be hoping to see logback-classic version 1.2.1 when I run:
show test:managedClasspath.
Instead I get logback-classic version 1.2.2 as if dependencyOverrides in Test was ignored.
At the same time when I run show Test/dependencyOverrides I get the expected result which is:
ch.qos.logback:logback-classic:1.2.1
Does anyone has a clue what am I missing in the relation between dependencyOverrides in Test scope and managedClasspath?
It appears the problem cannot be solve the way I imagined. The main reason is libraryDependencies and update are not scoped to configuration.
I think the best solution is in case I need a different version of library in some tests to extract those tests to a separate module with independent set of libraryDependencies.

How to force a specific version of dependency?

A dependency bar depends on foo 1.2.3, but that version of foo has a bug and I need to use version 1.2.2.
I can do that with force().
libraryDependencies += "foo" %% "foo" % "1.2.2" force()
That method is not recommended by the docs:
Forcing a revision (Not recommended)
Note: Forcing can create logical inconsistencies so it’s no longer recommended.
Does this mean SBT has a different, better way than force() to use a specific version of a dependency? If so, what?
Or am I to infer from the documentation that this entire problem is one that I'm recommended not to have?
you can use dependencyOverrides:
dependencyOverrides += "foo" %% "foo" % "1.2.2"
You're not avoiding "logical inconsistencies" anyway. If you force a version, you have to manually take care of compatibility with other libraries, there's no way out of that.
From the documentation:
Overriding a version
For binary compatible conflicts, sbt provides dependency overrides.
They are configured with the dependencyOverrides setting, which is a
set of ModuleIDs. For example, the following dependency definitions
conflict because spark uses log4j 1.2.16 and scalaxb uses log4j
1.2.17:
libraryDependencies ++= Seq(
"org.spark-project" %% "spark-core" % "0.5.1",
"org.scalaxb" %% "scalaxb" % "1.0.0" )
The default conflict manager chooses the latest revision of log4j, 1.2.17:
show update
[info] compile:
[info] log4j:log4j:1.2.17: ... ...
[info] (EVICTED) log4j:log4j:1.2.16 ...
To change the version
selected, add an override:
dependencyOverrides += "log4j" % "log4j" % "1.2.16"

Bad symbolic reference to scala.ScalaObject

I'm attempting to initiate a basic sbt build for the Lift framework and running into the following error:
[error] bad symbolic reference to scala.ScalaObject encountered in class file 'package.class'.
[error] Cannot access type ScalaObject in package scala. The current classpath may be
[error] missing a definition for scala.ScalaObject, or package.class may have been compiled against a version that's
[error] incompatible with the one found on the current classpath.
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 7 s, completed Aug 19, 2014 8:27:51 PM
This is my build file, run under sbt 0.13:
name := "MyApp"
version := "0.0.0"
organization := "com.myapp"
scalaVersion := "2.11.1"
EclipseKeys.createSrc := EclipseCreateSrc.Default + EclipseCreateSrc.Resource
resolvers ++= Seq("snapshots" at "http://oss.sonatype.org/content/repositories/snapshots",
"releases" at "http://oss.sonatype.org/content/repositories/releases",
"releases" at "http://oss.sonatype.org/content/repositories/releases"
)
seq(webSettings :_*)
unmanagedResourceDirectories in Test <+= (baseDirectory) { _ / "src/main/webapp" }
scalacOptions ++= Seq("-deprecation", "-unchecked")
libraryDependencies ++= {
val liftVersion = "2.6-RC1"
Seq(
"net.liftweb" %% "lift-webkit" % liftVersion % "compile",
"net.liftweb" %% "lift-mapper" % liftVersion % "compile",
"net.liftmodules" % "lift-jquery-module_2.6_2.9.1-1" % "2.8",
"org.eclipse.jetty" % "jetty-webapp" % "9.2.2.v20140723" % "container,test",
"org.eclipse.jetty" % "jetty-plus" % "9.2.2.v20140723" % "container,test", // For Jetty Config
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container,test" artifacts Artifact("javax.servlet", "jar", "jar"),
"org.specs2" %% "specs2" % "2.4.1" % "test",
"mysql" % "mysql-connector-java" % "5.1.+",
"org.slf4j" % "slf4j-log4j12" % "1.7.+",
"org.squeryl" % "squeryl_2.11" % "0.9.6-RC3"
)
}
There are similar questions here and here, but I don't understand the answers, and they are not helping me solve the problem. I recently both upgraded to Scala 2.11.1 and upgraded the dependencies declared within sbt, but I'm not sure where the problem is actually arising. My specific question is: how do I trace from the error above to the dependency that is causing this problem? Or, if it is not an issue of a dependency, where the issue lies and how do I determine where that is?
A quick glance looks like you might be using a scala 2.9.1 version of Lift-JQuery. From their docs:
For versions >= 2.3
"net.liftmodules" %% "moduleName_x1.y1 %
"x2.y2[.z2][-SNAPSHOT/rcx/mx]"
Where x1.y1 is Lift major and minor version numbers and a.b.c is Scala
version number and x2.y2.[z2] is the module's major x2, minor y2 and
eventual incremental numbers z2 followed by a eventual SNAPSHOT
release candidate (rcX) or milestone (mX) version part.
Trying: "net.liftmodules" % "lift-jquery-module_2.6" % "2.8" might fix your issue

Can SBT work with jMockit?

After many struggles I finally got a large project converted over from Maven to SBT. One of the remaining issues, however, is that some of the unit tests in the project use jMockit which can be a bit high-maintenance when it comes to configuring the environment.
Specifically the jmockit dependency/jar has two difficult requirements:
The jmockit jar must appear in the classpath before the junit jar
On many JVM's, such as the OpenJDK one I'm using, the JVM argument -javaagent:<path/to/jmockit.jar> is required
If both of these conditions are not met, I'm faced with the error:
[error] Test <mytestclass>.initializationError failed: java.lang.Exception: Method <mytestmethod> should have no parameters
[error] at mockit.integration.junit4.JMockit.<init>(JMockit.java:32)
I think I eventually managed to take care of #1 with SBT but I'm still having trouble with the second one. The debug SBT logs do not show enough detail about the forked process invocation to tell me if my settings are working or not. But the test output consistently indicates that it's not working. I have what I think are all the relevant settings:
lazy val myproj = Project(
...
settings = otherSettings ++ Seq(
libraryDependencies ++= Seq(
"com.googlecode.jmockit" % "jmockit" % "1.7" % "test",
"junit" % "junit" % "4.8.1" % "test"
),
fork in Test := true,
javaOptions in test += "-javaagent:<hardcode-path-to-jmockit.jar>"
)
I think the classpath is OK based on the output of the test:dependencyClasspath:
sbt> project <myproject>
sbt> show test:dependencyClasspath
[info] List(...., Attributed(/var/build/ivy2/cache/junit/junit/jars/junit-4.8.1.jar), ...
..., Attributed(/var/build/ivy2/cache/com.googlecode.jmockit/jmockit/jars/jmockit-1.7.jar), ...)
So I'm thinking that my javaagent setting is not having the intended result.
If I do happen to get this to work, my next question is how to get the hard-coded jmockit.jar path out of there but for now I'll settle for a passing test case.
So, how do I set the JVM options used for testing? How do I view/verify what options are actually used when the tests are launched?
You need to change your javaOptions to javaOptions in Test (note the T in Test is capitalized).
You can check your options by executing show test:javaOptions
> show test:javaOptions
[info] List(-javaagent:/home/lpiepiora/.ivy2/cache/com.googlecode.jmockit/jmockit/jars/jmockit-1.7.jar)
Additionally if you want to use dynamic path to the jmockit jar, you can set your javaOptions like this:
def jmockitPath(f: Seq[File]) = f.filter(_.name.endsWith("jmockit-1.7.jar")).head
javaOptions in Test += s"-javaagent:${jmockitPath((dependencyClasspath in Test).value.files)}"
build.sbt for reference
libraryDependencies += "com.novocode" % "junit-interface" % "0.9" % "test"
libraryDependencies ++= Seq(
"com.googlecode.jmockit" % "jmockit" % "1.7" % "test",
"junit" % "junit" % "4.8.1" % "test"
)
fork in Test := true
def jmockitPath(f: Seq[File]) = f.filter(_.name.endsWith("jmockit-1.7.jar")).head
javaOptions in Test += s"-javaagent:${jmockitPath((dependencyClasspath in Test).value.files)}"

Resources