SBT 0.11 InputKey depending on other tasks - scala

In 0.7.x we used dependsOn to declare that a task depends on other tasks - meaning other tasks have to be executed first.
In 0.11.x we use <<= to declare that a task depends on some other task. The SBT wiki says a lot on how to declare a TaskKey[_] which depends on other tasks and settings (there are questions here that deal with that), but not much on InputKey[_]. If I have an input key declared like this:
val benchTask = InputKey[Unit](
"bench",
"Runs a specified benchmark."
) <<= inputTask {
(argTask: TaskKey[Seq[String]]) =>
argTask map {
args =>
// ...
} // xxx
}
How can I make it depend on other tasks, like for example packageBin in Test? I can put dependsOn instead of the xxx comment above, but that gives me type errors.
Thank you.

Map your other task together with argTask:
inputTask {
(argTask: TaskKey[Seq[String]]) =>
(argTask, packageBin in Test) map {
(args, pb) =>
// ...
}
}

Related

How to call an InputKey from within a Task in an SBT Plugin

I am trying to make a task execute several inputKey.
myTask := Def.taskDyn {
val outputOfMyInputKey = myInputKey.[WHAT SHOULD I DO HERE].value
Def.task {
// do something with outputOfMyInputKey
}
}
Anybody knows how to call inputKey with default parameters ?
I tried parsed , evaluated, value, inputTaskValue but none of them works.
Thanks.
Take a look at this section of the sbt docs: Get a Task from an InputTask. You can use .toTask to provide input for your input task:
myInputKey.toTask("").value
Notice that if you provide a non-empty input, it should start with a space:
myInputKey.toTask(" arg1 arg2").value

How to log in settingKey in SBT?

I would like to do some logging in SBT. I tried to get streams when initializing settingKey. However the compiler complains that A setting cannot depend on a task.
The config snippet is here.
val appConfig = settingKey[Config]("The parsed application.conf in SBT")
appConfig := {
// ...
streams.value.log.error("Cannot find application.conf. Please check if -Dconfig.file/resource is setting correctly.")
// ...
}
Is there any method to do logging in settingKey? Thanks.
The proper way to log from an sbt setting is by using the Keys.sLog setting. This setting is set up by sbt and it holds the logger that it's used by other settings in the sbt universe.
val appConfig = settingKey[Config]("The parsed application.conf in SBT")
appConfig := {
// ...
Keys.sLog.value.log.error("Cannot find application.conf. Please check if -Dconfig.file/resource is setting correctly.")
// ...
}
A setting should only hold settable data or something directly computable from other settings . streams is a task, so you can make another task depend on it and the appConfig setting. For example:
val appConfig = settingKey[File]("application.conf file")
val parsedAppConfig = taskKey[Config]("The parsed application.conf in SBT")
parsedAppConfig := {
// ...
parse(appConfig.value)
// ...
streams.value.log.error("Cannot find application.conf. Please check if -Dconfig.file/resource is setting correctly.")
// ...
}
It's possible to go around streams and create a new ConsoleLogger() directly.
val appConfig = settingKey[Config]("The parsed application.conf in SBT")
appConfig := {
// ...
val logger: Logger = ConsoleLogger()
logger.error("Cannot find application.conf. Please check if -Dconfig.file/resource is setting correctly.")
// ...
}
Caveat: if streams.value.log gets set to something other than a ConsoleLogger, your log statement will be oblivious and still log to the console. That may be acceptable for your purposes though.

sbt package separate jars for different test types

We have just upgraded to using sbt 12.2 on our project. I would like to have our tests packaged in separate jars such as: project-unit.jar, project-integration.jar
Our current folder structure is:
src
main
...
test
scala
com.company.unit
com.company.integration
com.company.functional
Any suggestion is very much appreciated.
Thanks
I have found a way to do this by:
Create a packaging task for the appropriate test type:
val integrationPackaging = TaskKey[File]("package-integration")
Add package settings to the test settings:
lazy val integrationTestSettings = createTestSettings("integration", IntegrationTests) ++ createPackageSettings("integration", IntegrationTests, integrationPackaging)
private def createPackageSettings(testType: String, testConfiguration: Configuration, packagingTaskKey: TaskKey[sbt.File]) = {
inConfig(testConfiguration)(Defaults.testSettings) ++
Defaults.packageTaskSettings(packagingTaskKey, mappings in (Test, packageBin)) ++
(artifactName in packagingTaskKey := {(scalaversion, moduleId, artifact) => "%s_%s-%s-%s.jar" format (moduleId.name, scalaversion.binary, buildVersion, testType)}) ++
(mappings in packagingTaskKey ~= { (ms: Seq[(File,String)]) =>
ms.filter { case (file, path) =>{ !file.getName.endsWith(".class") || file.getAbsolutePath.contains(testType) }
}
})
}
Note in the create package settings, I had to:
add default test settings to ensure all test settings are inherited
add default test package task settings (using mappings in Test packageBin)
add artifactName (what you want the jar name to be)
add specific mappings for the package task key (created in step 1 above), this is the crux of it, I had to define a filter that ensures only files with the path containing the testType (e.g. "integration", "unit" or "functional") are selected and resource files (e.g. files that do not end with ".class")

Disable aggregate for sbt custom task

How can I disable aggregate for a single custom task?
I tried to add the following to my build.sbt:
aggregate in myTaskName:= false
But it doesn't work as I expected - I've got this error:
~\build.sbt:1: error: not found: value myTaskName
aggregate in myTaskName:= false
Working example (sbt 0.13.5):
val hello = TaskKey[Unit]("hello", "Prints 'Hello Zhu'")
val helloTask = hello := {
println("Hello Zhu")
}
aggregate in hello := false
Note, that TaskKey was used - not the Setting[Task] itself. It worth additional notice that this key should be accessable from your build.sbt and, as #Mark Harrah mentioned, hello must be fully-qualified.

SBT how to run InputTask

I am creating some custom tasks in my SBT project and need to call other tasks for that.
How can i call inputTasks from inside my tasks and support them some input?
Since you can factor your own tasks around this I'm assuming you're trying to use the run task. It took a bit of digging, but I've finally made it work; in a nutshell, this is what you do (assuming your task is named deployTask, tweak to match your needs):
deployTask <<= ( fullClasspath in Compile, runner ) map { ( classpath, runner ) =>
val logger = ConsoleLogger() // Not sure this is optimal
Run.executeTrapExit( {
Run.run( "com.sample.MainClass",
classpath map { _.data },
Seq( "option1", "option2", "..." ), // <-- Options go here
logger )( runner )
}, logger )
}
This doesn't invoke the InputTask directly (I haven't found a way to do that yet), but it at least lets you run arbitrary Java code.