What is the difference between "container" and "provided" in SBT dependencies? - scala

When reading build.sbt of many web applications, one can often see dependencies marked as "provided", see e.g. sbt-assembly documentation:
"org.apache.spark" %% "spark-core" % "0.8.0-incubating" % "provided"
I was unable to find any mention in SBT documentation, however Maven documentation says following about provided:
provided
This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime
Sometimes however I have also seen "container" in the same position, like in this build.sbt. Is this the same thing?
val tomcatVersion = "7.0.53"
libraryDependencies ++= Seq(
"org.apache.tomcat.embed" % "tomcat-embed-core" % tomcatVersion % "container",
"org.apache.tomcat.embed" % "tomcat-embed-logging-juli" % tomcatVersion % "container",
"org.apache.tomcat.embed" % "tomcat-embed-jasper" % tomcatVersion % "container",
"org.apache.tomcat" % "tomcat-catalina" % tomcatVersion % "provided",
"org.apache.tomcat" % "tomcat-coyote" % tomcatVersion % "provided"
)

That forth element of the dependency associates the dependency with a configuration; establishing a configuration dependency. It originates with ivy, which sbt uses internally.
The "container" configuration is defined by
xsbt-web-plugin version 0.9, which is brought into the project you reference here.
It is being used to establish the container/hosting runtime for sbt container:start.
As an aside - that runtime would necessarily provide the runtime libraries corresponding to the "provided" configuration, which were used during the compile phase but not included in the transitive dependencies for the resulting artifacts.

Related

sbt Test scope includes Runtime?

I'm configuring SLF4J within an SBT application and the Test vs Runtime scopes are working differently than I'd expect.
The setup I want:
tests (sbt test): use slf4-simple as the implementation
bundle/production runtime (sbt run): use log4j-slf4j-impl
Relevant build.sbt (sbt 0.13) section:
libraryDependencies += "org.slf4j" % "slf4j-simple" % "1.7.25" % Test,
libraryDependencies += "org.apache.logging.log4j" % "log4j-api" % 2.8.2 % Runtime,
libraryDependencies += "org.apache.logging.log4j" % "log4j-core" % 2.8.2 % Runtime,
libraryDependencies += "org.apache.logging.log4j" % "log4j-slf4j-impl" % 2.8.2 % Runtime
The error I'm getting is that there are two slf4j bindings present, the log4j one and the simple.
I'm wondering how the Runtime dependencies can be excluded from the Test scope, or if this is the wrong approach here.
To distill the question: I want to use a few different jars at runtime vs test that are mutually exclusive. How can this be done in sbt 0.13?
The issue is that Test scope includes Compile and presumably Runtime. So anything you add in Runtime it's also added in Test.
You can try to exclude log4j-slf4j-impl from the Test classpath like this:
fullClasspath.in(Test) := fullClasspath.in(Test).value.filterNot(_.data.getName.contains("log4j-slf4j-impl"))

Keep dependencies scoped to `test` in lock.sbt

I use sbt-lock plugin for dependency management, and have a problem: test dependencies in build.sbt, like
libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.+" %
"test"
are resolved as normal dependencies in lock.sbt, like
"com.typesafe.akka" % "akka-testkit_2.11" % "2.4.9"
which leads to bigger library size when it's pushed to maven. How to keep "test" scope for such dependencies?

Have sbt put javadocs and sources of dependencies on the class path

When using a managed dependency, I can tell sbt to download the javadocs and sources:
"mygroup" % "mymodule" % "myversion" withJavadoc() withSources()
But these jars don't seem to be on the runtime classpath?
What I would like to do, is access the javadocs and sources from my application. Can I make these jars appear as managed resources, such that I could do
ClassLoader.getSystemClassLoader.getResource("/my/package/MyDependency.scala")
?
You can do this by adding a classifier.
For a given library dependency, add a javadoc or sources classifer:
libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.0.6" classifier "javadoc"
libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.0.6" classifier "sources"
Then, access its contents from the classpath:
val docStream = getClass.getResourceAsStream("""/scalaz/Monad$.html""")
val doc = io.Source.fromInputStream(docStream).mkString
println(doc)
Here's a working example: https://earldouglas.com/ext/stackoverflow.com/questions/22160701/

Lift-2.5 build issue in sbt/Eclipse

I'm trying to get a mac development environment operational around Eclipse, SBT and Lift. Once installed as near to proper as I'm able to manage, I can run the app from sbt, but Eclipse still reports problems.
Eclipse is the Scala IDE build of Eclipse SDK, Build id:
3.0.1-vfinal-20130711-0941-Typesafe.
SBT is macport installed: sbt #0.12.3_1
Lift is the most recent 2.5 zip (This from this page.)
This tutorial was used for initial guidance. However, this tutorial is for a somewhat earlier version of Lift and associated dependencies, including the sbt-eclipse plugin. What I landed at was the 2.2 version of the eclipse plugin, and in my ~/.sbt/plugin/build.sbt I have this single line:
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.2.0")
Per the tutorial instructions, I'm pulling over the source file (of Lift's lift_basic project specifically) and modifying my project build.sbt to the following:
name := "sample project"
organization := "com.nford"
version := "0.1-SNAPSHOT"
scalaVersion := "2.10.1"
EclipseKeys.createSrc := EclipseCreateSrc.Default + EclipseCreateSrc.Resource
libraryDependencies ++= {
val liftVersion = "2.5"
Seq(
"net.liftweb" %% "lift-webkit" % liftVersion % "compile",
"net.liftweb" %% "lift-mapper" % liftVersion % "compile",
"org.mortbay.jetty" % "jetty" % "6.1.26" % "test",
"junit" % "junit" % "4.7" % "test",
"ch.qos.logback" % "logback-classic" % "0.9.26",
"org.scala-tools.testing" %% "specs" % "1.6.9" % "test",
"com.h2database" % "h2" % "1.2.147"
)
}
Importing the project into Eclipse works fine, except for 20 errors, mostly around the test cases. These include, but are not limited to:
object eclipse is not a member of package org
not found: value JQueryModule
Googling errors like this I see a lot of stuff from a year ago, largely which seems to be a package mismatch. From this research I was able to make some changes (reflected in the build.sbt, etc. above):
Upgrade scala version to 2.10.1
Upgrade lift version to 2.5
Use sbt-eclipse 2.2 plugin
Yet I'm still receiving these errors. To verify; I have updated, from the sbt terminal console, and run the eclipse build from there as well. I imported the project to Eclipse after that point. I am unable to determine where the package mismatches are coming from (or indeed why they can't be discovered, since they exist on the system and sbt can find them). Is this an eclipse IDE plugin weakness, or a solvable problem? Or, in my obvious newness to Scala Lift, am I missing something really obvious?
JQueryModule is not part of Lift. You need to add:
"net.liftmodules" %% "lift-jquery-module_2.5" % "2.3"
Jetty:
"org.eclipse.jetty" % "jetty-webapp" % "8.1.7.v20120910" % "container,compile",
"org.eclipse.jetty" % "jetty-servlets" % "8.1.7.v20120910" % "container,compile",
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container,compile" artifacts Artifact("javax.servlet", "jar", "jar")
Specs2:
"org.specs2" %% "specs2" % "1.14"

What do the % and %% operators do when setting up SBT dependencies?

In Lift Web Framework, dependencies for Simple Build Tool (SBT) are specified in LiftProject.scala. That file includes this code:
override def libraryDependencies = Set(
"net.liftweb" %% "lift-webkit" % liftVersion % "compile->default",
"net.liftweb" %% "lift-mapper" % liftVersion % "compile->default",
"org.mortbay.jetty" % "jetty" % "6.1.22" % "test->default",
"junit" % "junit" % "4.5" % "test->default",
"org.scala-tools.testing" %% "specs" % "1.6.6" % "test->default",
"org.scala-lang" % "scala-compiler" % "2.8.1" % "test->default",
"org.apache.tomcat" % "tomcat-juli" % "7.0.0" % "test->default",
"com.h2database" % "h2" % "1.2.138"
) ++ super.libraryDependencies
What do the % and %% operators do here? If I paste this code into the scala interpreter, it errors out, and neither % nor %% is defined for String or RichString. What's going on here?
The difference between these functions is that %% considers Scala version when SBT resolve dependency, so for example net/liftweb/lift-webkit_2.8.1/2.3/lift-webkit_2.8.1-2.3.jar will be downloaded from repo.
Regarding compile error - these methods should be called when some implicit methods defined in SBT class hierarchy that make actual conversion are in scope.
Best regards,
Vladimir
They control grabbing builds for a specific version of Scala.
% grabs the dependency exactly as you described it.
%% tacks the Scala version into the resource name to fetch a version for the local Scala build. Extra useful.if you crossbuild for several releases of Scala.
Since 2011, the doc got a bit more complete: "Library dependencies ".
The article "Sbt heiroglyphs and multi-projects explained" from Divan Visagie also details those sbt operators:
% and %% get a little tricky: they define the ids and versions of each library in the sequence , but it’s safe to say that:
"org.scala-tools" % "scala-stm_2.11.1" % "0.3"
Is the equivalent of
"org.scala-tools" %% "scala-stm" % "0.3"
So effectively the extra %% means it figures out what Scala version you are on.
The doc adds:
The idea is that many dependencies are compiled for multiple Scala versions, and you’d like to get the one that matches your project to ensure binary compatibility.
The complexity in practice is that often a dependency will work with a slightly different Scala version; but %% is not smart about that.
So if the dependency is available for 2.10.1 but you’re using scalaVersion := "2.10.4", you won’t be able to use %% even though the 2.10.1 dependency likely works.
If %% stops working, just go see which versions the dependency is really built for, and hardcode the one you think will work (assuming there is one).