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

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).

Related

Dependency of parent project defined with `test` scope is not visible in derived project

Let's say there is project A that has following dependencies.
"org.testng" % "testng" % "6.14.3" % "test",
"org.scalatest" %% "scalatest" % "3.0.3" % "test",
"org.scalacheck" %% "scalacheck" % "1.14.0" % "test",
"org.hamcrest" % "hamcrest-core" % "1.3" % "test"
There is also project B that depends on project A via sbt.Project.dependsOn(projectA).
Tests in project B are not compiled due to missing org.scalatest.*.
Is that by design? How can I overcome this?
Looks like by default .dependsOn uses only compile scope. In order to make it work for tests I had to changed to
.dependsOn(projectA % "compile->compile;test->test")
More information about it here.

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

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.

Play Framework SBT import play.api.libs.streams

I am building an application in Play Framework (2.4.0) / scala and trying to add play.api.libs.streams so I can use the object Streams in my application.
so here is my working build.sbt
libraryDependencies ++= Seq(
specs2 % Test,
cache,
ws,
"com.softwaremill.macwire" %% "macros" % "2.2.2",
"com.softwaremill.macwire" %% "runtime" % "1.0.7",
"org.reactivemongo" %% "play2-reactivemongo" % "0.11.10",
"com.eclipsesource" %% "play-json-schema-validator" % "0.6.5",
"org.scalatest" %% "scalatest" % "2.2.5" % Test,
"org.scalacheck" %% "scalacheck" % "1.12.2" % Test,
"org.scalatestplus" %% "play" % "1.4.0-M4" % Test,
"com.typesafe.akka" %% "akka-stream" % "2.4.4"
)
Now when I try to add the following line :
streams,
or when I just add
libraryDependencies += streams
I get the error :
error: No implicit for Append.Value[Seq[sbt.ModuleID], sbt.TaskKey[sbt.Keys.TaskStreams]] found,
so sbt.TaskKey[sbt.Keys.TaskStreams] cannot be appended to Seq[sbt.ModuleID]
libraryDependencies += streams
And I am unable to launch my project.
I found this question, but tweaking by adding '%' or '%%' did not solve the issue, and I was not sure how to use the solutions as I am just trying to add a play.api.libs dependency and not an external one.
I am kind of stuck here, I don't understand why streams is a sbt.TaskKey[sbt.Keys.TaskStreams] but ws or any other key added in the Sequence is a sbt.ModuleID
This this case the cache, ws, etc lines refer not to packages in play.api.libs, but to build artefacts that the Play sbt-plugin pre-defines as components in the play.sbt.PlayImport object, for example here.
In this context, ws is exactly equivalent to:
"com.typesafe.play" %% "play-ws" % "2.5.4"
The reason you see an error for streams is because there is no such component defined by Play, and therefore SBT assumes you are making reference to a TaskKey.
The play.api.libs.streams.Streams object should be available without anything extra added to your build if you have a PlayScala project on Play 2.5.x and above.

Is it possible for a Scala project to list its own dependencies?

In sbt, we define dependencies for a project:
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.3.2",
"org.scalatest" %% "scalatest" % "2.2.4" % "test"
)
Is it possible for the Scala application thus compiled to get access to this data, somehow?
I am making a modular system of Play 2.4 APIs and would like the "umbrella" to be able to list which APIs it's carrying.
I will probably get this done using sbt-buildinfo that I found via this question.
Other suggestions are of course welcome.
A simple solution is checking maven repositories. For example, the link below shows all libraries com.beachape" %% "enumeratum" % "1.3.2" depends on.
http://mvnrepository.com/artifact/com.beachape/enumeratum_2.11/1.3.2

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"