Alex Gilleran
Alex Gilleran

Reputation: 597

Make only relevant file changes trigger execution in multi-project SBT build

I'm trying to set up a multi-project build like so:

+-- common
|   +-- build.sbt
+-- api
|   +-- build.sbt
+-- indexer
|   +-- build.sbt
+-- build.sbt

build.sbt in root looks like so:

lazy val common = (project in file("common"))
lazy val searchApi = (project in file("search"))
  .dependsOn(common)
lazy val indexer = (project in file("indexer"))
  .dependsOn(common)

As you can see, indexer and api both depend on common but not on each other. The problem is if I try to do a triggered execution for a task, say compile:

sbt ~api/compile

Then change a file in the indexer project, the project will still recompile even though the file changed isn't actually on its classpath - it seems that watchSources is always comprised of every project referenced by the root build.sbt and doesn't take the project that you're actually running the task on into account.

I've tried filtering watchSources but it's hard to do neatly because the build.sbt file that I put it in can only see the resources for the project that it's in... e.g. watchSources in indexer/build.sbt can only see the watched sources inside indexer, build.sbt in the root is only watching src/main/resources in the root directory (it can't see the watchSources of the sub-projects).

Does anyone have a nice way of solving this. The best I've got is putting something like this in every subproject's build.sbt...

watchSources <<= (watchSources) map { files =>
  if (Option(System.getProperty("project")).getOrElse("none").equals("indexer")) {
    files
  } else {
    Nil
  }
}

... then running sbt -Dproject=indexer ~indexer/compile.

Upvotes: 0

Views: 359

Answers (1)

jkinkead
jkinkead

Reputation: 4431

The ~ operator watches the currently-active project for changes. Try running project api first:

> project api
> ~compile

Upvotes: 1

Related Questions