Reputation: 1288
I'm using SBT 0.13. I'm running into a problem, which is exhibited by the following toy example:
lazy val nativeOne = TaskKey[Unit]( "nativeOne", "One" )
lazy val nativeTwo = TaskKey[Unit]( "nativeTwo", "Two" )
lazy val testProj = Project(
id = "testProj",
base = file( "." ),
settings = Defaults.defaultSettings ++ Seq(
scalaVersion := "2.10.2",
nativeOne :=
{
println( "Native one"
},
nativeTwo :=
{
if ( true )
{
println( "Native two" )
}
else
{
val n1 = nativeOne.value
}
}
)
)
If I go into sbt and run nativeTwo
:
> nativeTwo
Native one
Native two
Why is this happening? Why is the false
branch being evaluated? Is branching in TaskKeys not allowed?
Upvotes: 1
Views: 2004
Reputation: 5624
In sbt ALL dependencies are computed in parallel before your task runs. If you were to construct a graph of what you have, it would be:
nativeOne
^
|
nativeTwo
What you're trying to do is order the tasks. In sbt, we try to promote tasks returning the results that other tasks use directly, hence the .value
. What that does is not directly run a task, but say "give me the result of this other task".
The best way understand sbt's syntax is as a mimic of the scala-async project. Your code is similar to the following async code:
nativeOne = async {
println( "Native one")
}
nativeTwo = async {
if(true) println("Native Two")
else await(nativeOne)
}
There, it's a little more obvious that you're just saying "wait for the value if it hasn't already computed.
If you want to optionally execute a Task, you need to do so at the Task[_]
layer of sbt, which is a bit more verbose. We're using a 'dynamic task'. That is one that chooses which tasks are actually run at runtime.
SO, you'll need to use the Def.taskDyn
method which lets you compose tasks in the order they are defined. You'll work on the tasks themselves using the toTask
method of TaskKey
s. This is instead of working on the values the tasks produce. Here's an example build.sbt
:
val taskOne = taskKey[Int]("test")
val taskTwo = taskKey[Int]("test2")
val taskThree = taskKey[Int]("test3")
val switchEm = settingKey[Boolean]("switch 'em")
switchEm := true
taskOne := { println("taskOne"); 1 }
taskTwo := { println("taskTwo"); 2 }
taskThree := Def.taskDyn({
if(switchEm.value) taskTwo.toTask
else taskOne.toTask
}).value
And then in the sbt console:
> reload
[info] Loading project definition from /home/jsuereth/projects/sbt/test-projects/project
[info] Set current project to test-projects (in build file:/home/jsuereth/projects/sbt/test-projects/)
> taskThree
2
Also note, you won't see the corrected dependencies in the inspect command, because the dependencies are dynamically added:
> inspect taskThree
[info] Task: Int
[info] Description:
[info] test3
[info] Provided by:
[info] {file:/home/jsuereth/projects/sbt/test-projects/}test-projects/*:taskThree
[info] Defined at:
[info] /home/jsuereth/projects/sbt/test-projects/build.sbt:15
[info] Dependencies:
[info] *:switchEm
[info] *:settingsData <- TaskOne + TaskTwo are missing, this replaces
[info] Delegates:
[info] *:taskThree
[info] {.}/*:taskThree
[info] */*:taskThree
Upvotes: 6