5

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?

Ben Hutchison
  • 2,433
  • 2
  • 21
  • 25
  • maybe this question/answer is some help to you: http://stackoverflow.com/questions/14351940/setting-up-sbt-environment-to-hack-on-multiple-libraries-at-once/14352600#14352600 –  Jan 31 '13 at 10:23

2 Answers2

3

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.

Ezhik
  • 876
  • 6
  • 23
  • Although this example only shows settings being changed by an environment variable, it could apply to the original question as well. System properties are also an option. That said, I prefer avoiding system properties/env variables so I'd typically use a custom setting for the scenario in this answer. For the original question, settings aren't available when defining inter-project dependencies, so while env variables/properties aren't elegant, you could do worse. – Mark Harrah Feb 02 '13 at 17:36
3

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.

Community
  • 1
  • 1
Mark Harrah
  • 6,999
  • 1
  • 26
  • 31