Say I have the following dependencies
+-A:1.0
+-B:1.0
+-C:1.0
I want to exclude dependency B and only B I want to keep all of its transitive dependencies so that in my classpath I will have both A.jar and C.jar but no B.jar.
I there an easy way to do so in sbt? For example, if I do
libraryDependencies += "com.example" % "A" % "1.0" exclude("com.example", "B")
It will not even try to resolve C
In other words, how do I only read the POM of B, skip downloading the jar and proceed normally with other dependencies?
Related
I'm trying to come up with a structure for a large, multi-module sbt project that satisfies the following requirements:
When the root project is built, dependencies are first resolved from the modules available under the root ( i.e. if module A depends on module B version 2, which is the version of B available under the root, satisfy the dependency with whatever the build for B produces )
When modules are built individually, dependencies are resolved from repositories ( local, cache, remote )
I am aware of two vehicles to define dependencies to an sbt project: dependsOn() and the libraryDependencies setting key.
So far, in my naive structure, where all build information for the modules (A, B) was tracked at the root, I simply passed .dependsOn the project references, and the inter-module dependencies were correctly resolved in the build of R
What I would like to do, is to move/track this relationship in the build.sbt file of the modules themselves, which are then hosted in separate repositories (and pulled back occasionally to an "aggregate" tag of the parent project's repo via git submodule)
I've never had any problem doing this with maven (I assume because of being able to refer to a parent explicitly in the module's pom and there being only one way to establish a dependency) but I can't yet wrap my head around how to get it going in sbt
So my question is, will I have to write a custom resolver for this? Is there anything obvious I'm missing here?
Thanks.
I'm also having a similar setup, with an aggregate project with 100+ sub-projects. Sub-project also live in their own repository and can be built/published stand-alone or as part of the aggregate project. I don't need any special resolver for this to work.
I'm just combining both approaches you described:
project A:
groupId := "groupId"
version := "1.0.0-SNAPSHOT"
libraryDependencies += "groupId" %% "B" % version
project B:
groupId := "groupId"
version := "1.0.0-SNAPSHOT"
project R:
lazy val a = (project in file(a)).dependsOn(b)
lazy val b = (project in file(b))
I noticed that sbt is clever enough not to include the dependency on b twice.
I have a build that contains two modules a and b. b depends on a. a contains only resources (think: logging configuration). Locally, if I run the sbt task b/console, I want a to be on the classpath. However, I don't want to publish a and hence don't want the dependency to appear in b's artifact. How can I configure this?
You can use the 'provided' scope when adding the library dependency
libraryDependencies += "javax.servlet" % "javax.servlet-api" % "3.0.1" % "provided"
In my project I want to use the sbinary library to (de)serialize some case classes to a binary form. I also want to use the latest Scala in the project. Typesafe offers a version of sbinary in their repositories, and they seem to be the only one who are doing so.
So I add the repository and dependency to my build.sbt like so:
scalaVersion := "2.11.2"
resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
libraryDependencies += "org.scala-tools.sbinary" %% "sbinary" % "0.4.2"
Surprisingly, this fails. With a dependency defined like this, SBT tries to find the dependency at the url http://repo.typesafe.com/typesafe/releases/org/scala-tools/sbinary/sbinary_2.11.0 whereas it is really located at http://repo.typesafe.com/typesafe/releases/org.scala-tools.sbinary/sbinary_2.11.0. Because SBT replaces the dots in the dependency group id with slashes, it is not able to find the dependency in the place it's in.
I've tried some tricks for building the string in other ways, but they are all useless since SBT replaces the .s by /s in the string after it is evaluated. How can I get SBT to find the dependency at this URL?
Please note that I'm aware that I could simply make this an offline dependency, but I'd prefer to have this build script work out of the box on any computer with SBT installed.
http://repo.typesafe.com/typesafe/releases/org.scala-tools.sbinary/sbinary_2.11.0 is in ivy style. The default style of sbt is maven2 so your resolver doesn't work.
try
resolvers += Resolver.url("Typesafe Repository (ivy)", url("http://repo.typesafe.com/typesafe/releases/"))(Resolver.ivyStylePatterns)
Source: https://groups.google.com/forum/#!topic/simple-build-tool/TY1AoYYvB4k
One of my projects will provide a jar package supposed to be used for unit testing in several other projects. So far I managed to make sbt produce a objects-commons_2.10-0.1-SNAPSHOT-test.jar and have it published in my repository.
However, I can't find a way to tell sbt to use that artifact with the testing scope in other projects.
Adding the following dependencies in my build.scala will not get the test artifact loaded.
"com.company" %% "objects-commons" % "0.1-SNAPSHOT",
"com.company" %% "objects-commons" % "0.1-SNAPSHOT-test" % "test",
What I need is to use the default .jar file as compile and runtime dependency and the -test.jar as dependency in my test scope. But somehow sbt never tries to resolve the test jar.
How to use test artifacts
To enable publishing the test artifact when the main artifact is published you need to add to your build.sbt of the library:
publishArtifact in (Test, packageBin) := true
Publish your artifact. There should be at least two JARs: objects-commons_2.10.jar and objects-commons_2.10-test.jar.
To use the library at runtime and the test library at test scope add the following lines to build.sbt of the main application:
libraryDependencies ++= Seq("com.company" % "objects-commons_2.10" % "0.1-SNAPSHOT"
, "com.company" % "objects-commons_2.10" % "0.1-SNAPSHOT" % "test" classifier "tests" //for SBT 12: classifier test (not tests with s)
)
The first entry loads the the runtime libraries and the second entry forces that the "tests" artifact is only available in the test scope.
I created an example project:
git clone git#github.com:schleichardt/stackoverflow-answers.git --branch so15290881-how-do-i-resolve-my-own-test-artifacts-in-sbt
Or you can view the example directly in github.
Your problem is that sbt thinks that your two jars are the same artifact, but with different versions. It takes the "latest", which is 0.1-SNAPSHOT, and ignores the 0.1-SNAPSHOT-test. This is the same behaviour as you would see if, for instance you have 0.1-SNAPSHOT and 0.2-SNAPSHOT.
I don't know what is in these two jars, but if you want them both to be on the classpath, which is what you seem to want to do, then you'll need to change the name of the test artifact to objects-commons-test, as Kazuhiro suggested. It seems that this should be easy enough for you, since you're already putting it in the repo yourself.
It will work fine if you change the name like this.
"com.company" %% "objects-commons" % "0.1-SNAPSHOT",
"com.company" %% "objects-commons-test" % "0.1-SNAPSHOT" % "test",
I have a legacy war project that depends on a jar project, the jar project needs to add a few unmanaged jars to the classpath for compilation. But these jars should not be packaged in the war. So my question is how do I remove these entries from the fullClasspath. The following won't work:
val excludeFilter = "(servlet-api.jar)|(gwt-dev.jar)|(gwt-user.jar)"
val filteredCP = cp.flatMap({ entry =>
val jar = entry.data.getName()
if (jar.matches(excludeFilter)) {
Nil
} else {
Seq(entry)
}
})
fullClasspath in Runtime = filteredCP
I am pretty sure there must be simple way to do this but so far it has eluded me.
Edit: Based on Pablo's sugestion to use the managed classpath instead of the unmanaged I can rephrase the question as: how do you add local jars to the managedClasspath. My jars are placed in a local folder with a (very) nonstandard layout:
lib/testng.jar
lib/gwt/2.3/gwt-user.jar
lib/jetty/servlet.jar
So basically I am looking for something like:
libraryDependencies += "testng" % "provided->test"
libraryDependencies += "gwt" % "2.3" % "gwt-user" % "provided->compile"
libraryDependencies += "jetty" % "servlet" % "provided->default"
allowing me to grab jars from my own local lib folder.
Some information is provided on the Classpaths page, but it is not very clear or detailed. The information is also available using the inspect command, described on the Inspecting Settings page.
Basically, for a configuration X, in a short-hand notation:
// complete, exported classpath, such as used by
// 'run', 'test', 'console', and the war task
fullClasspath in X =
dependencyClasspath in X ++ exportedProducts in X
// classpath only containing dependencies,
// used by 'compile' or 'console-quick', for example
dependencyClasspath in X =
externalDependencyClasspath in X ++ internalDependencyClasspath in X
// classpath containing only dependencies external to the build
// (as opposed to the inter-project dependencies in internalDependencyClasspath)
externalDependencyClasspath in X =
unmanagedClasspath in X ++ managedClasspath in X
// the manually provided classpath
unmanagedClasspath in X =
unmanagedJars for X and all configurations X extends, transitively
So, normally, when you want to add unmanaged libraries, you add them to unmanagedJars. For example, if you add libraries to unmanagedJars in Compile, then sbt will correctly include the libraries on the unmanagedClasspath for Compile, Runtime, and Test.
However, you want explicit control here. Add the libraries only to the unmanagedClasspath you want the jars on, which is unmanagedClasspath in Compile. For example, in sbt 0.11.0+:
unmanagedClasspath in Compile <++= baseDirectory map { base =>
val lib = base / "lib"
Seq(
lib / "testng.jar",
lib / "gwt/2.3/gwt-user.jar",
lib / "jetty/servlet.jar"
)
}
Assuming the war plugin uses the Runtime classpath, those jars will only show up on the compile classpath and not in the war.
sbt supports ivy-like configurations, and implements maven basic scopes.
If you want to use some jars in your compilation classpath but don't want to ship them, I guess the provided scope is for you:
libraryDependencies += "org.example" % "example" % "1.0" % "provided->compile"