I have 2 sbt projects that are runnable (akka app and another play application).
Is it possible to run both of them, and use ~reStart so they refresh on any changes to my project?
Any tips on doing this correctly so I don't run out of memory also?
If you are using Play Framework's latest version you can ~run without any plugin. Regarding standalone akka application you may use a library called sbt-revolver
runAkkaServer := {
(reStart in Compile in `akka-server`).evaluated
}
runWebServer := {
(~run in Compile in `web-server`).evaluated
}
mainClass in reStart := Some("com.example.MainAkka")
val runAkkaServer = inputKey[Unit]("Runs akka-server")
val runWebServer = inputKey[Unit]("Runs web-server")
NOTE: you can run both applications in restart mode without custom tasks:
1. ~run - Play server
2. reStart - Standalone
UPDATE:
I've tried to use following command to both of them, it seems that sbt-revolver is kinda trick and killing application onstart. When replace reStart with run it works perfect, but doesn't trigger changes.
screen -d -m sbt runAppServer; screen -d -m sbt runWebServer
So above code just doesnot behave as expected. Instead of custom tasks, we can run them in separate windows like this:
screen -dmS "appserver" sh -c "sbt 'project appserver;~reStart'; exec bash" ; screen -dmS "webserver" sh -c "sbt runWebServer; exec bash"
Also sbt runWebServer can be replaced by sbt 'project anothersubmodule;~run' if you wish.
I've created a simple demonstration project, you can find here
In order to start you can call just: ./starter.sh
NOTE: you can install screen command if you don't have easily.
Open two different Terminal tabs; cd into the specific directory in each tab and then run with SBT.
sbt run
For multiple web apps, specify a different port:
sbt run -Dhttp.port=8888
Related
how do I execute the instructions below?
"CLI: To setup the CLI interface and beast-shell, extract the binary package in .tar.gz format. Run $BEAST/bin/beast to launch the command line interface."
then I need to run the command line to create a Maven project.
Dev: To create a new Java/Scala project for Beast using the following command.
mvn archetype:generate -DgroupId=com.example.beastExample -DartifactId=beast-project \
-DarchetypeGroupId=edu.ucr.cs.bdlab -DarchetypeArtifactId=beast-spark -DarchetypeVersion=0.9.5-RC2
I already ran the first line of the command in cmd but something is missing.
does the entire command only work if executing the first part of the statement first?
I'm moving my first steps with Scala (2.12.7) and SBT (1.2.7).
At some point, I want to get secret value from the environment:
sys.env("SECRET_TOKEN")
The problem is that, in the sbt shell, SECRET_TOKEN is not defined, therefore the application crashes.
So:
$ export SECRET_TOKEN="xxx"
$ sbt
[... sbt loads]
sbt> run
[ crashes because of the env var not found ]
It's like the sbt shell would get only a subset of the current environment.
Am I missing something?
Thanks
sbt (script + launcher) just launches a fancy java process, which should inherit the environment variables from the parent process.
Given
$ export SECRET_TOKEN="xxx"
Both build.sbt and your application during run should have access to sys.env("SECRET_TOKEN").
In the comment section, Bruno suggested SECRET_TOKEN="xxx" sbt, which apparently worked, but I don't know how that's different from export.
In any case,
object Hello extends App {
println(sys.env("SECRET_TOKEN"))
}
works for me
sbt:hello> run
[info] Running Hello
xxx
When using sbt console I find myself repeatedly entering some import statements. It would be great if there was a way to tell sbt to always run commands. Is there a way?
At the moment I have a kinda crufty solution:
( echo "import my.app._
import my.app.is.sooo.cool._" && cat ) | sbt console
Googleability words:
Initial commands, first commands, initial expressions, build file, initial statements, startup expressions, startup commands, startup statements.
You can use initialCommands:
initialCommands in console := """import my.app._
import my.app.is.sooo.cool._"""
Given that "sbt console" lets you run the scala repl, why not just create a custom .scala file (say "default.scala") where to store all the imports, and then just run :load /path/to/default.scala? This would achieve what you need in a persistent way.
I have two separated git repos, one holds a scala server built with sbt, the other holds a webapp frontend built with npm/bower/gulp.
In server repo, I already have a task to build a standalone jar (not the standard package task) ; in frontend repo, I can build with npm install && npm run build which would result into a standalone directory _public.
Now I would like to include the UI directory _public during sbt building jar task, I am wondering if there is a better way to do so other than manually spawn external process in sbt to call npm ?
The current state of sbt-web and webjars relying on it is that they are hardly keeping up with the growth of Node.js and npm. For example, the sbt-hbs plugin is no longer maintained, and my experience shows that it won't work with any Node.js version 8 or above. Support for sbt 1.0 is also not complete in some of these webjar-based frontent tools.
As such, unlike what the question suggests, directly spawning npm processes via sbt to build the frontend is a better solution than many.
This answer from a different question provides a sufficiently reliable way to call npm from sbt, which I will only replicate here for completeness.
buildFrontend := {
val s: TaskStreams = streams.value
val shell: Seq[String] = if (sys.props("os.name").contains("Windows")) Seq("cmd", "/c") else Seq("bash", "-c")
val npmInstall: Seq[String] = shell :+ "npm install"
val npmTest: Seq[String] = shell :+ "npm run test"
val npmLint: Seq[String] = shell :+ "npm run lint"
val npmBuild: Seq[String] = shell :+ "npm run build"
s.log.info("building frontend...")
if((npmInstall #&& npmTest #&& npmLint #&& npmBuild !) == 0) {
s.log.success("frontend build successful!")
} else {
throw new IllegalStateException("frontend build failed!")
}
}
If your frontend uses NPM and Gulp to build the app, you need to run it with a NodeJS engine (or maybe JVM engines like Rhino or Nashorn can do it? not sure) and it requires an external process.
The question to ask yourself is: do you really want to couple the deployment of your backend from the deployment of your frontend? Isn't there any case where you simply want to deploy one and not the other?
I think using SBT to deploy you frontend is nice but if your frontend is complex, you'd rather keep it separate from SBT.
Your JS app does not necessarily need to be served as a Play public asset, you could simply deploy it to its own place and reference it inside a Play HTML template.
I agree with Sebastien to keep the front-end dev (and possibly even deploy) separate from your back-end, as I am in the process of learning that lesson myself.
That said, have a look at SbtWeb (task workflow) in tandem with WebJars (package management) . SbtWeb has several plugins that can cover the basics (uglify, concat, filter), and in some cases I think if node is installed it can use it directly.
I'm currently using sbt-native-packager to generate a start script for my scala application. I'm using packageArchetype.java_application. I create the script in sbt:
sbt clean myproject/stage
and then "install" the application by copying the created lib and bin directories to the installation directory. I'm not distributing it to anyone, so I'm not creating an executable jar or tarball or anything like that. I'm just compiling my classes, and putting my jar and all the library dependency jars in one place so the start script can execute.
Now I want to add a second main class to my application, so I want a second start script to appear in target/universal/stage/bin when I run sbt stage. I expect it will be the same script but with a different name and app_mainclass set to the different class. How would I do this?
The sbt-native-packager generated script allows you to pass in a -main argument to specify the main class you want to run. Here's what I do for a project named foo:
Create a run.sh script with whatever common options you want that calls the sbt-native-packager generated script:
#!/bin/bash
./target/universal/stage/bin/foo -main "$#"
Then I create a separate script for each main class I want to run. For example first.sh:
#!/bin/bash
export JAVA_OPTS="-Xms512m -Xmx512m"
./run.sh com.example.FirstApp -- "$#"
and second.sh:
#!/bin/bash
export JAVA_OPTS="-Xms2048m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC"
./run.sh com.example.SecondApp -- "$#"
Having multiple main classes is... supported now (Q4 2016, native package 1.2.0)
See "SBT Native Packager 1.2.0" by Muki Seiler
Single Project — Multiple Apps
A major pain point for beginners is the start script creation. The bash and bat start scripts are only generated when there is a either
Exactly one main class
Explicitly set main class with
mainClass in Compile := Some(“com.example.MainClass”)
For 1.2.x we will extends the implementation and support multiple main classes by default.
Native packager will generate a start script for each main class found on the classpath.
SBT provides them via the discoveredMainClasses in Compile task.
If there is only one main class, SBT will assign it to the mainClass in Compile setting. This leads to three cases:
Exactly one main class.
In this case native-packager will behave like previous versions and just generate a single start script, using the executableScriptName setting for the script name.
Multiple main classes and mainClass in Compile := None.
This is the default behaviour defined by SBT. In this case native-packager will generate the same start script for each main class.
Multiple main classes and mainClass in Compile := Some(…).
The user has set a specific main class, which will lead to a main start script being generated using the executableScriptName setting. For all other main classes native-packager generates forwarder scripts.
Having multiple main classes not supported now. As a workaround you could use single main class and check command line args.
Starting your app:
myApp prog1
In your main class:
def main(args: Array[String]): Unit = {
if(args[0] == "prog1")
Programm1.start()
else
Programm2.start()
}