My goal is to have a task or setting that can take some parameters.
After carefully reading the docs, I've written in build.sbt this basic snippet that compiles ok:
val servers = token(
literal("desarrollo") |
literal("parametrizacion")
)
val deploy = inputKey[Unit]("Deploy to server")
deploy := {
val serv = servers.parsed
println(s"Deploying to $serv")
}
I'm experiencing this problems from SBT command line:
> deploy desarrollo
[error] Expected ID character
[error] Not a valid command: deploy
[error] Expected project ID
[error] Expected configuration
[error] Expected ':' (if selecting a configuration)
[error] Expected key
[error] Expected '::'
[error] Expected end of input.
[error] Expected 'desarrollo'
[error] Expected 'parametrizacion'
[error] desploy desarrollo
[error] ^
Tab completion for the argument doesn't work.
My purpose is to admit a parameter whose value can be desarrollo either parametrizacion.
A space must be specified and discarded.
val servers = token(' ' ~> (
literal("desarrollo") |
literal("parametrizacion")
))
val deploy = inputKey[Unit]("Deploy to server")
deploy := {
val serv = servers.parsed
println(s"Deploying to $serv")
}
Now, deploy desarrollo and deploy parametrizacion do work.
Really, the need to specify the initial space, provides more flexibility. :-)
Related
I'm trying to apply FlyWay plugin by sbt build configuration.
In plugins.sbt
In my build.sbt:
lazy val CustomConfig = config("custom") extend Runtime
lazy val customSettings: Seq[Def.Setting[_]] = Seq(
flywayUser := "andrej",
flywayPassword := "123456",
flywayUrl := "jdbc:postgresql://localhost:5432/database",
flywayLocations += "db/migration"
)
lazy val flyWay = (project in file("."))
.settings(inConfig(CustomConfig)(FlywayPlugin.flywayBaseSettings(CustomConfig) ++
customSettings): _*)
In resources.db.migration-directory sql-file is created.
And trying to run migration to database it with command: sbt flywayMigrate
But it returns the following errors:
[error] Expected ';'
[error] Not a valid command: flywayMigrate
[error] No such setting/task
[error] flywayMigrate
[error] ^
Looks like you did not enable the plugin.
Add following line to your project/plugin.sbt
addSbtPlugin("io.github.davidmweber" % "flyway-sbt" % "7.4.0")
and enable the plugin in you build.sbt file:
enablePlugins(FlywayPlugin)
I would like to get system property from command line and print it in sbt.
I used followiing code snippet
Depend.scala
val myVar = Option(System.getProperty("myVar")).getOrElse("default")
Build.sbt
val showMesg = settingKey[Unit]("Show message")
showMesg := {
sLog.value.info(myVar)
}
It works well when I use following command:
sbt -DmyVar=abc compile
[info] abc
But if I want to output it in debug log level. It can't get the system property correctly.
val showMesg = settingKey[Unit]("Show message")
showMesg := {
sLog.value.debug(myVar)
}
sbt -DmyVar=abc compile -debug
[debug] default
I just curious why I can't get the property when log level is debug.
Currently:
Sbt has multiple test runners: scalaTest, junit-interface, etc..
Each test runner has it's own set of flags (scalaTest flags, junit-interface flags).
You can pass flags through sbt to the test runners, for example:
$ sbt '<project>/test-only * -- -f <out_file>' (-f is a scalaTest flag)
However, the flags seem to be passed to all test runners, even if a flag is not compatible with all test runners.
I'm also experiencing behavior contrary to what I found in the documentation. ScalaTest says the -v flag will "print the ScalaTest version" and junit-interface says it will "Log "test run started" / "test started" / "test run finished" events on log level "info" instead of "debug"." Instead ScalaTest throws an unrecognised flag exception.
$ sbt '<project>/test-only * -- -v'
java.lang.IllegalArgumentException: Argument unrecognized by ScalaTest's Runner: -v
at org.scalatest.tools.ArgsParser$.parseArgs(ArgsParser.scala:425)
at org.scalatest.tools.Framework.runner(Framework.scala:929)
...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
[error] (elasticSearchDriver/test:testOnly) java.lang.IllegalArgumentException: Argument unrecognized by ScalaTest's Runner: -v
[error] Total time: 1 s, completed Aug 15, 2017 11:12:56 AM
Question:
What is the actual underlying behavior of the flags passed to the test runners through sbt? Is there a bit of documentation that explains what's going on?
By looking at SBT (0.13.x) we eventually get to a part where:
def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] = inputTests0.mapReferenced(Def.mapScope(_ in key.key))
private[this] lazy val inputTests0: Initialize[InputTask[Unit]] =
{
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
Def.inputTaskDyn {
val (selected, frameworkOptions) = parser.parsed
val s = streams.value
val filter = testFilter.value
val config = testExecution.value
implicit val display = Project.showContextKey(state.value)
val modifiedOpts = Tests.Filters(filter(selected)) +: Tests.Argument(frameworkOptions: _*) +: config.options
val newConfig = config.copy(options = modifiedOpts)
val output = allTestGroupsTask(s, loadedTestFrameworks.value, testLoader.value, testGrouping.value, newConfig, fullClasspath.value, javaHome.value, testForkedParallel.value, javaOptions.value)
val taskName = display(resolvedScoped.value)
val trl = testResultLogger.value
val processed = output.map(out => trl.run(s.log, out, taskName))
Def.value(processed)
}
}
Notice this line: Tests.Filters(filter(selected)) +: Tests.Argument(frameworkOptions: _*) +: config.options
By reading this I deduce that sbt passes the arguments you pass to it to all the underlying testing frameworks.
Solution
Don't pass test framework flags in your commands. Configure them in your *.sbt files like:
testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-f")
Documentation on test framework arguments
I have a SBT multi project which includes two sub projects. One is an ordinary Scala web server project and the other is just some web files. With my self written SBT plugin I can run Gulp on the web project. This Gulp task runs asynchronous. So with
sbt "web/webAppStart" "server/run"
I can start the Gulp development web server and my Scala backend server in parallel. Now I want to create a new task, that combines them both. So afterwards
sbt dev
for example should do the same. Here is what I tried so far:
// Build.sbt (only the relevant stuff)
object Build extends sbt.Build {
lazy val runServer: InputKey[Unit] = run in server in Compile
lazy val runWeb: TaskKey[Unit] = de.choffmeister.sbt.WebAppPlugin.webAppStart
lazy val dev = InputKey[Unit]("dev", "Starts a development web server")
// Scala backend project
lazy val server = (project in file("project-server"))
// Web frontend project
lazy val web = (project in file("project-web"))
// Root project
lazy val root = (project in file("."))
.settings(dev <<= (runServer) map { (_) => {
// do nothing
})
.aggregate(server, web)
This works so far. Now I don't have any idea, how to make dev also depend on the runWeb task. If I just add the runWeb task like
.settings(dev <<= (runWeb, runServer) map { (_, _) => {
// do nothing
})
then I get the error
[error] /Users/choffmeister/Development/shop/project/Build.scala:59:value map is not a member of (sbt.TaskKey[Unit], sbt.InputKey[Unit])
[error] .settings(dev <<= (runWeb, runServer) map { (_, _) =>
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
Can anyone help me with this please?
The optimal solution would pass the arguments given to dev to the runServer task. But I could also live with making dev a TaskKey[Unit] and then hard code to run runServer with no arguments.
tl;dr Use .value macro to execute dependent tasks or just alias the task sequence.
Using .value macro
Your case seems overly complicated to my eyes because of the pre-0.13 syntax (<<=) and the use of project/Build.scala (that often confuse not help people new to sbt).
You should just execute the two tasks in another as follows:
dev := {
runWeb.value
runServer.value
}
The complete example:
lazy val server = project
lazy val runServer = taskKey[Unit]("runServer")
runServer := {
println("runServer")
(run in server in Compile).value
}
lazy val runWeb = taskKey[Unit]("runWeb")
runWeb := {
println("runWeb")
}
lazy val dev = taskKey[Unit]("dev")
dev := {
println("dev")
}
dev <<= dev dependsOn (runServer, runWeb)
Using alias command
sbt offers alias command that...
[sbt-learning-space]> help alias
alias
Prints a list of defined aliases.
alias name
Prints the alias defined for `name`.
alias name=value
Sets the alias `name` to `value`, replacing any existing alias with that name.
Whenever `name` is entered, the corresponding `value` is run.
If any argument is provided to `name`, it is appended as argument to `value`.
alias name=
Removes the alias for `name`.
Just define what tasks/command you want to execute in an alias as follows:
addCommandAlias("devAlias", ";runServer;runWeb")
Use devAlias as if it were a built-in task:
[sbt-learning-space]> devAlias
runServer
[success] Total time: 0 s, completed Jan 25, 2015 6:30:15 PM
runWeb
[success] Total time: 0 s, completed Jan 25, 2015 6:30:15 PM
I want to combine the sbt-release plugin with the Play framework.
The plugins reads the current version number from a file version.sbt. Its content is
version in ThisBuild := "0.41.0-SNAPSHOT"
I would like to use this setting in my main build file but the variable version is of type sbt.SettingKey.
There is an evaluate method but for the life of me I can't figure out what to pass in to get the String I defined in version.sbt.
I tried the accepted answer's solution but it didn't compile. (Play 2.1.5)
[error] (ss: sbt.Project.Setting[_]*)sbt.Project <and>
[error] => Seq[sbt.Project.Setting[_]]
[error] cannot be applied to (Seq[sbt.ModuleID])
[error] val main = play.Project(appName).settings(appDependencies).settings(releaseSettings).settings(
[error] ^
[error] one error found
Instead I came up with this solution:
...
lazy val appSettings = Defaults.defaultSettings ++ ... ++ releaseSettings
val main = play.Project(appName, dependencies = appDependencies, settings = appSettings).settings(
version <<= version in ThisBuild,
...
)
This is a little shortcoming with the play.Project constructor, it excepts a static version number, not one from a setting key.
However, the only required parameter is the application name, so you can switch from something like:
val main = play.Project(appName, appVersion, appDependencies, settings =
Defaults.defaultSettings ++ releaseSettings ).settings(...)
to
val main = play.Project(appName).settings(appDependencies).
settings(releaseSettings).settings(...)
Normally, the version defined in version.sbt should be picked up here automagically. If it isn't, you can always add to the above:
.settings(applicationVersion <<= version in ThisBuild)