Andrey
Andrey

Reputation: 9072

Can "buildBase" point to directory outside current project in SBT?

Let's say I have an existing (old) codebase and I'd like the least-invasive way of demoing how to compile it with SBT. I'd like to accomplish it in such a way that the file-structure of the root directory containing the codebase is completely untouched. This means that project/Build.scala will need to be outside of the actual project. Also, keep in mind that since the existing project has a non-standard layout and uses a lot on unmanaged dependencies there's quite a bit of configuration that needs to be done (like setting unmanagedSourceDirectories, unmanagedJars, etc.)

Consider the example layout below:

/opt/workspace
        |
        +- existing-codebase
        | |
        | +- module1
        | | |
        | | +- src
        | |
        | +- module2
        |   |
        |   +- src
        |
        +-  sbt-demo-build
          |
          +- project
            |
            +- Build.scala

Also, let's say I have the following environmental variable set:

CODE_HOME=/opt/workspace/existing-codebase

So, what needs to go into Build.scala to indicated that the build base (buildBase?) is /opt/workspace/existing-codebase rather than /opt/workspace/sbt-demo-build

I tried setting baseDirectory key, but SBT just fails with:

java.lang.AssertionError: assertion failed: Directory /opt/workspace/existing-codebase/module1 is not contained in build root /opt/workspace/sbt-demo-build

This is DemoBuild I use in the project:

import java.nio.file.{Paths, Files}
import sbt._
import Keys._

object DemoBuild extends Build {
  val codeHome = Paths.get(sys.env("CODE_HOME")).toAbsolutePath.
                       toRealPath().normalize().toFile
  ...
}

The best analogy I can think of is Ant's basedir attribute in the project element - does this concept not exist in SBT (or is it just not exposed properly)?

Update:

After digging around for a bit I found something called xsbti.AppConfiguration which seems to correspond to a Setting called sbt.Keys.appConfiguration. I attempted to override using:

  appConfiguration ~= { cfg =>
    new AppConfiguration {
      def arguments(): Array[String] = cfg.arguments()
      def baseDirectory(): File = codeHome
      def provider(): AppProvider = cfg.provider()
    }
  }

But got the same AssertionError. Then, I found some official docs that might help, so I'll be looking into those as the next step

Upvotes: 4

Views: 1245

Answers (1)

Jacek Laskowski
Jacek Laskowski

Reputation: 74709

OPTION 1

Use /opt/workspace as the project directory for your SBT project. Use it as you meant to have used /opt/workspace/sbt-demo-build.

OPTION 2

Use the following build definition in build.sbt that defines two SBT modules outside the current project directory.

lazy val root = project in file(".") aggregate (module1, module2)

lazy val module1 = ProjectRef(file("../existing-codebase/module1"), "module1")

lazy val module2 = ProjectRef(file("../existing-codebase/module2"), "module2")

It assumes module1 and module2 are SBT projects and root project aggregates them so running a command in root will also run it on the aggregated projects.

OPTION 3

When on Unix, symlink the projects with ln -s that are outside the build root.

jacek:~/sandbox/so/andrey-workspace/sbt-demo-build
$ ln -s ../existing-codebase/module1 .
jacek:~/sandbox/so/andrey-workspace/sbt-demo-build
$ ln -s ../existing-codebase/module2 .
jacek:~/sandbox/so/andrey-workspace/sbt-demo-build
$ tree
.
├── build.sbt
├── module1 -> ../existing-codebase/module1
└── module2 -> ../existing-codebase/module2

2 directories, 1 file

Use the following build.sbt in which the projects are defined.

jacek:~/sandbox/so/andrey-workspace/sbt-demo-build
$ cat build.sbt
lazy val root = project in file(".") aggregate (module1, module2)

lazy val module1 = project

lazy val module2 = project

In SBT console, projects, project and run worked perfectly:

jacek:~/sandbox/so/andrey-workspace/sbt-demo-build
$ sbt
[info] Loading global plugins from /Users/jacek/.sbt/0.13/plugins
[info] Set current project to root (in build file:/Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build/)
[root]> projects
[info] In file:/Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build/
[info]     module1
[info]     module2
[info]   * root
[root]> module1/run
[info] Running Hello
Hello from module1
[success] Total time: 1 s, completed Jan 11, 2014 9:40:03 PM
[root]> project module1
[info] Set current project to module1 (in build file:/Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build/)
[module1]> run
[info] Running Hello
Hello from module1
[success] Total time: 0 s, completed Jan 11, 2014 9:40:20 PM
[module1]> project root
[info] Set current project to root (in build file:/Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build/)
[root]> show baseDirectory
[info] module1/*:baseDirectory
[info]  /Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build/module1
[info] module2/*:baseDirectory
[info]  /Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build/module2
[info] root/*:baseDirectory
[info]  /Users/jacek/sandbox/so/andrey-workspace/sbt-demo-build

Upvotes: 4

Related Questions