SBT: How to set transitive dependencies of a dependency to "provided" later? - sbt

I have something like this in my build.sbt:
lazy val someDeps = Seq(
libraryDependencies += "com.example" %% "foo" % "1.3.37",
// more
)
lazy val some_library = project.in(file("libs/somelibrary")).
settings(commonSettings).
settings(
// project-specific settings
libraryDependencies ++= someDeps
)
lazy val something_with_deps_provided = project.in(file("swdp")).
settings(commonSettings).
settings(
// project-specific settings
libraryDependencies ++= someDeps.map(d => d % "provided")
).dependsOn(some_library)
When I now use the sbt-assembly-plugin to create the assembly of something_with_deps_provided, it still puts the dependencies into the resulting jar, ignoring the provided. Is it possible to set a transitive dependency to provided later and if yes, how is it done?

In cases like this, excludeDependencies can be used as described in
SBT manual here:
Exclude Transitive Dependencies.
With your example:
lazy val something_with_deps_provided = project.in(file("swdp"))
.settings(commonSettings)
.dependsOn(some_library)
.settings(
// project-specific settings
excludeDependencies ++= someDeps.map { d =>
ExclusionRule(
organization = d.organization,
name = d.name
)
}
)
The dependencies from someDeps will no longer be included in the
assembly JAR for something_with_deps_provided project.

Related

Build a Jar with and without provided dependencies

I have an SBT project, with spark dependencies. These dependencies are provided at runtime, and hence I import them under provided scope.
val hadoop = Seq("org.apache.hadoop" % "hadoop-client" % "3.3.1" % provided)
val spark = Seq(
"org.apache.spark" %% "spark-core" % SparkVersion % provided,
"org.apache.spark" %% "spark-sql" % SparkVersion % provided,
"org.apache.spark" %% "spark-mllib" % SparkVersion % provided
)
lazy val coreDto = (project in file("xxxx"))
.enablePlugins(BuildInfoPlugin)
.enablePlugins(PackPlugin)
.settings(
name := "xxxx",
moduleName := "xxxx",
version := "1.0",
libraryDependencies ++= (hadoop ++ spark))
All is well till now. Now I have a new scenario, where I have to publish the jar to our maven repository. And successfully I am able to publish it. The issue now is: provided scope. As the compile time dependencies are not appropriately set.
Question: How do I configure, where the provided scope is ignored during publishing? But still considered when I package it?
Using this to publish in case if helpful
lazy val publishSettings = Seq(
publishMavenStyle := true,
publishTo := {
val url = "https://xxxxl/maven/v1/"
if (version.value.trim.toUpperCase.endsWith("SNAPSHOT"))
Some("snapshots".at(url))
else
Some("releases".at(url))
},
aetherDeploy / logLevel := Level.Info,
aetherOldVersionMethod := true,
credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
)

When using a Scala compiler plugin in sbt, how do you set a library dependency for the plugin?

I'm using a compiler plugin I wrote that depends on the Kyro serialization library. When attempting to use my plugin I set this up in build.sbt (top-level) like this:
lazy val dependencies =
new {
val munit = "org.scalameta" %% "munit" % "0.7.12" % Test
val kyro = "com.esotericsoftware" % "kryo" % "5.0.0-RC9"
}
lazy val commonDependencies = Seq(
dependencies.kyro,
dependencies.munit
)
lazy val root = (project in file("."))
.settings(
libraryDependencies ++= commonDependencies,
Test / parallelExecution := false
)
addCompilerPlugin("co.blocke" %% "dotty-reflection" % reflectionLibVersion)
But when I compile my target project, I get a java.lang.NoClassDefFoundError that it can't find Kyro. I've added kyro to my dependencies, but since this is for the compiler, not my app, it's not picking that up.
How can I properly tell sbt about a dependency my plugin needs?

Unresolved dependency in published assembly package in SBT

In my project there are 3 sub projects under root. build.sbt is as below.
proj_C depends on proj_A and proj_B.
If I created the assembly proj_C package with below command. It success and the assembly package could be imported in other projects.
sbt "project proj_C" assembly
If I publish with "sbt publish", as I defined addArtifact in proj_C settings, an assembly jar package is also generated and then published. But when I try to compile another project which imports this assembly jar, it will below error
[error] unresolved dependency: proj_A;1.0.0: not found
part of build.sbt is as below. Could anyone point me what I made wrong in my way?
Many thanks!
artifact in (Compile, assembly) := {
val art = (artifact in (Compile, assembly)).value
art.withClassifier(Some("assembly"))
}
lazy val assemblySettings = Seq(
assemblyMergeStrategy in assembly := {
{
case PathList("META-INF", xs # _*) => MergeStrategy.discard
case _ => MergeStrategy.first
}
}
)
lazy val root = Project(base = file("."))
.disablePlugins(sbtassembly.AssemblyPlugin)
.aggregate(proj_A, proj_B, proj_C)
.settings(
commonSettings,
skip in publish := true,
name := "proj_root"
)
lazy val proj_A= (project in file("proj_A"))
.disablePlugins(sbtassembly.AssemblyPlugin)
.settings(
commonSettings,
skip in publish := true,
name := "proj_A"
)
lazy val proj_B= (project in file("proj_B"))
.disablePlugins(sbtassembly.AssemblyPlugin)
.settings(
commonSettings,
skip in publish := true,
name := "proj_B"
)
lazy val proj_C= (project in file("proj_C"))
.settings(
commonSettings,
assemblySettings,
addArtifact(artifact in (Compile, assembly), assembly),
name := "proj_C"
) dependsOn(proj_A, proj_B)
First of all, I hope you know that the publishing of the fat jar is not recommended. And to be honest, in your case I really see no benefit in doing so.
If you simply publish A, B, C separately and then add the dependency in your other project it will all be automatically downloaded (along with dependencies of those projects). And the dependency management will be much easier...
But, since you want to add the A-assembly dependency, by the error I guess that you are actually adding the wrong jar. My guess would be that you publish both C.jar and C-assembly.jar, and you added the dependency like:
"your.organisation" %% "C" % "version"
but you should have:
"your.organisation" %% "C" % "version" classifier "assembly"

Excluding a dependency in creating fat jar using SBT

I am writing a akka application. While creating far jar of application , I dont want scala libraries to be packaged with the jar. My build.sbt looks as follows:
lazy val root = (project in file(".")).
settings(
name :="akka-app",
version :="1.0",
scalaVersion :="2.10.4",
mainClass in Compile := Some("sample.hello.HelloWorld")
)
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.3.4" % "provided",
"com.typesafe" % "config" % "1.2.1"
)
// META-INF discarding
mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
{
case PathList("META-INF", xs # _*) => MergeStrategy.discard
case x => MergeStrategy.first
}
}
But this sbt packages scala with jar. I want only com.typesafe.config library to be present in the jar. Any solution how to achieve this?
You can exclude Scala by modifying the option in the assemblyOption setting:
assemblyOption in assembly :=
(assemblyOption in assembly).value.copy(includeScala = false)

sbt 0.13.2-M3 to 0.13.5-RC3 issue

I'm having a problem moving from sbt version 0.13.2-M3 to 0.13.5-RC3 where transitive dependencies that 13.2-M3 successfully resolves fail to be resolved by 0.13.5-RC3.
I get unresolved dependency errors where the version is "working#".
It's happening when I have a multi-project build with two sub-projects, one of which depends on the other. They both have dependencies whose maven poms specify a common parent (though I'm not sure if that's a red herring or not).
It only happens when the dependencies aren't already in the local ivy cache.
A minimal repro Build is:
import sbt._
import Keys._
object BarBuild extends Build {
val buildSettings = Seq(scalaVersion := "2.10.3")
lazy val root = Project(
id = "bar",
base = file(".")
) aggregate(withSolrCore, withSolrClient)
lazy val withSolrCore = Project(
id = "withSolrCore",
base = file("solrCore"),
settings = buildSettings ++ Seq(
libraryDependencies ++= Seq("org.apache.solr" % "solr-core" % "4.7.1")
)
) dependsOn (withSolrClient)
lazy val withSolrClient = Project(
id = "withSolrClient",
base = file("solrClient"),
settings = buildSettings ++ Seq(
libraryDependencies ++= Seq("org.apache.solr" % "solr-solrj" % "4.7.1")
)
)
}
With build.properties's sbt.version=0.13.5-RC3 I see lots of errors like
[warn] module not found: org.apache.lucene#lucene-analyzers-kuromoji;working#heraclitus.local
and
[error] unresolved dependency: org.apache.lucene#lucene-core;working#heraclitus.local: not found
but with sbt.version=0.13.2-M3 everything's peachy.
I'm not sure if I'm doing something wrong or something's up with sbt, but at this point I suspect the latter.
Thanks.
This is a known ivy issue. The workaround is to override the versions of all the dependencies in the full transitive closure that's breaking with the "real" versions to use. (I derived the real ones by running update on a stub project with only the problem dependency with an older version of sbt, 0.13.2, which is pre-ivy-bug), like,
dependencyOverrides ++= Set(
"com.google.guava" % "guava" % "14.0.1",
"com.google.protobuf" % "protobuf-java" % "2.5.0",
"com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.2",
"com.spatial4j" % "spatial4j" % "0.4.1",
...
)

Resources