Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to toggle between project and library dependencies in SBT?

Tags:

scala

sbt

It's easy to declare managed library dependencies in SBT, eg

 libraryDependencies ++= Seq(
 "org.specs2" %% "specs2" % "1.12.2" % "test" ,
 "junit" % "junit" % "4.7" % "test"
)

And while it's not as easy to declare project dependencies in SBT, I can do that too:

object RichMath extends Build {
  lazy val myApp = Project("RichMath", file(".")) dependsOn(richUtil)   
  lazy val richUtil = RootProject(file("../RichUtil"))
}

But in practice, I typically want to change between project mode, where changes are immediately visible in upstream projects, and library mode, where I must publish changes to see them in dependent projects, as code matures.

Early in code-base's life, or whenever I'm wanting to make frequent changes across modules, I don't want the hassle of re-publishing just to see changes upstream. But in stable/mature code, I want to specify exactly what version's I'm depending upon.

It seems like SBT treats the two dependencies as completely different. Is there a more straight-forward way to switch between project- and library- dependencies than rewriting my build definition?

like image 996
Ben Hutchison Avatar asked Jan 31 '13 10:01

Ben Hutchison


2 Answers

I have a few scenarios for my sbt scripts (tests, publishing, production). I start sbt from script (from bash, you may have other environment) with DO=TESTS sbt for example. This is my dynamic dependencies with regard of environment variable:

if (sys.env.contains("LOCAL_BUILD")) {
  Seq[Project.Setting[_]](
    unmanagedResourceDirectories in Compile <+= baseDirectory { _ / "src" / "main" / "scala" },
    libraryDependencies ++= {
      Seq(
        "org.digimead" %% "digi-lib-slf4j" % "0.2.1-SNAPSHOT" % "test",
        "org.digimead" %% "digi-lib-test" % "0.2.1-SNAPSHOT" % "test",
        "org.scalatest" %% "scalatest" % "1.9" % "test"
      )
    }
  )
} else {
  Seq[Project.Setting[_]](
   libraryDependencies ++= {
      Seq(
        "org.slf4j" % "slf4j-log4j12" % "1.7.1"
      )
    }
  )
}

As you can see I may have different project settings with single .sbt definition controlled by one environment variable. The environment variable affect all project/subproject bunch.

like image 54
Ezhik Avatar answered Oct 07 '22 00:10

Ezhik


It is true that the two types of dependencies are treated rather differently and it would be nice if they were not. The main obstacle is that sbt needs to know about all external projects before settings are loaded (for various reasons).

For now, the easiest solution is probably an environment variable or system property as described in another answer. Going forward, the following is very close to being possible in sbt, but still needs some more work:

  1. Declare a dependency as usual

    libraryDependencies += "org.example" % "rich-util" % "0.1"
    
  2. Add the source dependency from the command line, overriding the normal dependency automatically in the process

    $ sbt
    > projects add ../RichUtil
    

The convention-based approach described in Setting up sbt environment to hack on multiple libraries at once is a special case and would be enabled by this working as well.

like image 20
Mark Harrah Avatar answered Oct 07 '22 01:10

Mark Harrah