If in my build.sbt I have the following code:
val example = TaskKey[Unit]("example")
example := Def.task[Unit] {
streams.value.log.info("EXAMPLE")
}.triggeredBy(compile in Compile).value
When I execute ~ compile, whenever a source changes I'll see in the console EXAMPLE.
How to get the same behavior for ~ run arg1 arg2?
The difficulty I'm having in implementing this is because run is an InputKey as opposed to compile in Compile which is a TaskKey.
You can have :
example in run := Def.task[Unit] {
streams.value.log.info("EXAMPLE")
}.triggeredBy(compile in Compile).value
Related
I want to create a custom runLocal task that executes the sbt run task with modified unmanagedClasspath.
I want the unmanagedClasspath modification to only be visible/last while running runLocal, not run.
What I've tried in build.sbt:
Runtime / unmanagedClasspath ++= Seq(new java.io.File("src/main/my_resources")).classpath
val runLocal = taskKey[Unit]("Run app with my config")
runLocal := {
(Runtime / run).toTask("").value
}
The above works but the problem is that the modification of unmanagedClasspath is "global" and affects every task that uses this value.
How can I run runLocal with modified unmanagedClasspath that is not visible outside that task?
What I ended up doing is using a Command.
Commands have access to the state and are able to modify it.
val runLocal = Command.command("runLocal") { state =>
val extracted = Project.extract(state)
val localConfigClasspath = Seq(new java.io.File("src/main/my_resources")).classpath
val newState = extracted.appendWithoutSession(Seq(Runtime / unmanagedClasspath ++= localConfigClasspath), state)
Project.extract(newState).runInputTask(Runtime / run, "", newState)._1
}
This way the config is only changed while running sbt runLocal without affecting sbt run.
How would one override the libraryDependencies ?
I tried:
Keys.libraryDependencies in Compile := {
val libraryDependencies = (Keys.libraryDependencies in Compile).value
val allLibraries = UpdateDependencies(libraryDependencies)
allLibraries
}
So that seem to work, when I add print statement, the allLibraries is correct.
However, in the next steps, it doesn't seem to have the right values:
Keys.update in Compile := Def.taskDyn {
val u = (Keys.update in Compile).value
Def.task {
val allModules= u.configurations.flatMap(_.allModules)
log.info(s"Read ${allModules.size} modules:")
u
}
}.value
The print statement only have a few modules instead of all the one I would have added in the previous step.
Anyone have a solution ? Thanks !
So I understand where my problem was.
I was not understanding correctly how settings and tasks were working together.
settings are only evaluated once when sbt start.
and tasks are only evaluated once when sbt start a task / command which will require it.
So you cannot read and then rewrite settings like that.
It was so convoluted, I even wrote a whole article about it
I've just written my first SBT Autoplugin which has a custom task that generates a settings file (if the file is not already present). Everything works as expected when the task is explicitly invoked, but I'd like to have it automatically invoked prior to compilation of the project using the plugin (without having the project modify it's build.sbt file). Is there a way of accomplishing this, or do I somehow need to override the compile command? If so, could anyone point me to examples of doing so? Any help would be extremely appreciated! (My apologies if I'm missing something simple!) Thanks!
You can define dependencies between tasks with dependsOn and override the behavior of a scoped task (like compile in Compile) by reassigning it.
The following lines added to a build.sbt file could serve as an example:
lazy val hello = taskKey[Unit]("says hello to everybody :)")
hello := { println("hello, world") }
(compile in Compile) := ((compile in Compile) dependsOn hello).value
Now, every time you run compile, hello, world will be printed:
[IJ]sbt:foo> compile
hello, world
[success] Total time: 0 s, completed May 18, 2018 6:53:05 PM
This example has been tested with SBT 1.1.5 and Scala 2.12.6.
val runSomeShTask = TaskKey[Unit]("runSomeSh", " run some sh")
lazy val startrunSomeShTask = TaskKey[Unit]("runSomeSh", " run some sh")
startrunSomeShTask := {
val s: TaskStreams = streams.value
val shell: Seq[String] = if (sys.props("os.name").contains("Windows")) Seq("cmd", "/c") else Seq("bash", "-c")
// watch out for those STDOUT , SDERR redirection, otherwise this one will hang after sbt test ...
val startMinioSh: Seq[String] = shell :+ " ./src/sh/some-script.sh"
s.log.info("set up run some sh...")
if (Process(startMinioSh.mkString(" ")).! == 0) {
s.log.success("run some sh setup successful!")
} else {
throw new IllegalStateException("run some sh setup failed!")
}
}
// or only in sbt test
// test := (test in Test dependsOn startrunSomeShTask).value
(compile in Compile) := ((compile in Compile) dependsOn startrunSomeShTask).value
I tried to set some system properties in "build.sbt", then read it in my scala application.
In build.sbt:
name := "hello"
version := "1.0"
scalaVersion := "2.11.0"
fork := true
javaOptions := Seq("-Daaa=bbb")
Note I set aaa=bbb. Following is my scala code:
In src/main/scala/hello.scala:
object Hello {
def main(args:Array[String]) {
println("hello, world")
println(System.getProperty("aaa"))
println("==========")
}
}
Then I run:
$ sbt
$ console
$ Hello.main(null)
But it prints:
hello, world
null
==========
You can see it's still null. What's the correct way to do it?
Instead of:
$ sbt
$ console
$ Hello.main(null)
Use:
$ sbt
$ run-main Hello
I'm trying to create a multi-module application and run one of it's modules separately from the others (from another machine).
Project structure looks like this:
main
/ \
module1 module2
I want to run a module1 as a separate jar file (or there is a better way of doing this?), which I will run from another machine (I want to connect it to the main app using Akka remoting).
What I'm doing:
Running "play dist" command
Unzipping module1.zip from universal folder
Setting +x mode to bin/module1 executable.
Setting my main class (will paste it below): instead of play.core.server.NettyServer im putting my main class: declare -r app_mainclass="module1.foo.Launcher"
Running with external application.conf file.
Here is my main class:
class LauncherActor extends Actor {
def receive = {
case a => println(s"Received msg: $a ")
}
}
object Launcher extends App {
val system = ActorSystem("testsystem")
val listener = system.actorOf(Props[LauncherActor], name = "listener")
println(listener.path)
listener ! "hi!"
println("Server ready")
}
Here is the console output:
#pavel bin$ ./module1 -Dconfig.file=/Users/pavel/projects/foobar/conf/application.conf
[WARN] [10/18/2013 18:56:03.036] [main] [EventStream(akka://testsystem)] [akka.event-handlers] config is deprecated, use [akka.loggers]
akka://testsystem/user/listener
Server ready
Received msg: hi!
#pavel bin$
So the system switches off as soon as it gets to the last line of the main method. If I run this code without Play - it works as expected, the object is loaded and it waits for messages, which is expected behavior.
Maybe I'm doing something wrong? Or should I set some options in module1 executable? Other ideas?
Thanks in advance!
Update:
Versions:
Scala - 2.10.3
Play! - 2.2.0
SBT - 0.13.0
Akka - 2.2.1
Java 1.7 and 1.6 (tried both)
Build properties:
lazy val projectSettings = buildSettings ++ play.Project.playScalaSettings ++ Seq(resolvers := buildResolvers,
libraryDependencies ++= dependencies) ++ Seq(scalacOptions += "-language:postfixOps",
javaOptions in run ++= Seq(
"-XX:MaxPermSize=1024m",
"-Xmx4048m"
),
Keys.fork in run := true)
lazy val common = play.Project("common", buildVersion, dependencies, path = file("modules/common"))
lazy val root = play.Project(appName, buildVersion, settings = projectSettings).settings(
resolvers ++= buildResolvers
).dependsOn(common, module1, module2).aggregate(common, module1, module2)
lazy val module1 = play.Project("module1", buildVersion, path = file("modules/module1")).dependsOn(common).aggregate(common)
lazy val module2: Project = play.Project("module2", buildVersion, path = file("modules/module2")).dependsOn(common).aggregate(common)
So I found a dirty workaround and I will use it until I will find a better solution. In case someone is interested, I've added this code at the bottom of the Server object:
val shutdown = Future {
readLine("Press 'ENTER' key to shutdown")
}.map { q =>
println("**** Shutting down ****")
System.exit(0)
}
import scala.concurrent.duration._
Await.result(shutdown, 100 days)
And now system works until I will hit the ENTER key in the console. Dirty, I agree, but didn't find a better solution.
If there will be something better, of course I will mark it as an answer.