How to run multiple sbt projects in parallel? - scala

I have a multi-project sbt build (each project is micro service).
For development convenience, I want to run all of them at the same time.
Is it possible with sbt?
lazy val root = (project in file("."))
.aggregate(
serviceA,
serviceB
)
lazy val serviceA = (project in file("service-a"))
...
lazy val serviceB = (project in file("service-b"))
...
I can run them individually with serviceA/run or serviceB/run
But I need to run serviceA and serviceB with single sbt command (they will be running on different ports)

You could try to use Ammonite
We us Ammonite scripts (e.g. runner.sc) to run sbt. I never used Future as we run one thing after the other.
Or use a simple bash file:
Your requirement is more or less running sbt in the background.
Here is an according question: how-to-run-sbt-as-daemon
Taking this to your question, this could look like:
#!/usr/bin/env bash
sbt -Djline.terminal=jline.UnsupportedTerminal serviceA/run &
sbt -Djline.terminal=jline.UnsupportedTerminal serviceB/run &
I couldn't test this, let me know if it works.

Related

Running multi-project sbt project results in clobbered compilation of shared project

I have a play application and a normal scala application that have shared code in a dependency defined as such:
project A
project B
shared
lazy val shared = (project in file("shared")).settings(...)
lazy val projectA = (project in file("A")).settings(...).dependsOn(shared)
lazy val projectB = (project in file("B")).settings(...).dependsOn(shared)
Due to the way sbt handles triggered execution, running sbt ~run in development mode is not usable for handling file changes correctly. I'm also using sbt-revolver to handle re-running the non-play application. As a result, I run both applications separately using the commands:
sbt 'project A' '~run'
sbt 'project B' '~reStart'
in parallel, so when I make a change to shared, both try to recompile it, and therefore sometimes result in an error. I frankly despise SBT's documentation, and cannot figure out how to get this to work within SBT, so I am asking for help.

Disable single test in Play 2.4 scala

I have some long running tests in my project. These these are sitting in parallel to my integration and unit-tests in
/test/manual/*
Is there in Play 2.4 for Scala a way to disable/mark these test classes. So they are not run automaticly when
$ activator test
but only run when using the test-only command.
Problem is that I do not want to run these longer tests on my CI server.
Having similar problems for long-running integration tests, I created an It configuration derived from the standard test config (in <projectHome>/build.sbt):
lazy val It = config("it").extend(Test)
Then I add the sources and test sources to this config
scalaSource in It <<= (scalaSource in Test)
and you needd to enable to config and corresponding tasks available in the current project
lazy val root = (project in file(".")).configs(It)
.settings(inConfig(It)(Defaults.testTasks): _*)
I then disable long running tests in the Test config :
testOptions in Test := Seq(Tests.Argument("exclude", "LongRunning"))
And include only these long running tests in the It config:
testOptions in It := Seq(Tests.Argument("include", "LongRunning"))
These last 2 configs are kinda dependent on the test framework you use (specs2 in my case, scala test would probably use -n and -l in addition to tags to achieve the same)
Then sbt test will exclude all LongRunning tests and you can run it:test or it:testOnly your.long.running.TestCaseHere in an interactive sbt session if need be.

sbt auto-plugins - disable them but for one sub project

Switching sbt-assembly from 0.11.2 to 0.13.0, I suddenly find myself in a situation where calling sbt assembly does not just invoke the task in the sub-project that explicitly added assemblySettings, but it tries to run it for each and every sub project.
So, if I have
lazy val root = project(...).aggregate(core, app)
lazy val core = project(...)
lazy val app = project(...).dependsOn(core)
How can I disable the assembly task for all but the root project? With other plugins such as sbt-buildinfo this problem doesn't occur because you have to explicitly enable the plugin per sub-project.
The goal is to be able to run sbt assembly so it will do that just for the root project.
Found the answer in a closed issue. You have to add the following line to your common settings:
aggregate in assembly := false

scala sbt assembly "no main manifest attribute"

I use assembly plugin in sbt to assemble my project. But errors happen when run by "java -jar xx.jar" -
"no main manifest attribute".
I think it's because there are two files in my src/main/scala/ directory and each with an object extending Application which means there are two main entry in the project. But I need two applications, one is the server and the other is the test client.
How to handle this two-main-entry problem in scala sbt. Thanks in advance.
In your SBT build file, define the main class.
If you are using build.sbt, then that would be:
mainClass in assembly := Some("com.domain.Main")
If you are using Build.scala then you could do something like:
lazy val app = (project in file("app")).
settings(assemblySettings: _*)
settings(mainClass in assembly := Some("com.domain.Main"))
You can use -cp instead of -jar
java -cp xx.jar com.domain.AnyClassName
I had this issue while testing out Lagom.
To deploy in Lagom you can just access the -impl project and run this:
./sbt "project <your-project>-impl" dist
This will generate a zip with the executable inside.

How do I run an sbt main class from the shell as normal command-line program?

How can I run an sbt app from the shell, so that I can run my app as a normal command-line program (as if run directly via scala but without having to set up an enormous classpath)?
I know I can do:
echo hello | sbt 'run-main com.foo.MyMain3 arg1 arg2' > out.txt
But this (1) takes forever to start because it starts sbt, (2) causes all stdout and stderr to go to stdout, and (3) causes all output to be decorated with a logger [info] or [error].
I looked at https://github.com/harrah/xsbt/wiki/Launcher but it seems too heavyweight, since it downloads dependencies and sets up a new environment and whatnot. I just want to run this app within my existing development environment.
Thus far I've cobbled together my own script to build up a classpath, and you can also do some other things like modify your project file to get sbt to print the raw classpath, but I feel like there must be a better way.
Here's what I have in my SBT (version 0.10) project definition,
val Mklauncher = config("mklauncher") extend(Compile)
val mklauncher = TaskKey[Unit]("mklauncher")
val mklauncherTask = mklauncher <<= (target, fullClasspath in Runtime) map { (target, cp) =>
def writeFile(file: File, str: String) {
val writer = new PrintWriter(file)
writer.println(str)
writer.close()
}
val cpString = cp.map(_.data).mkString(":")
val launchString = """
CLASSPATH="%s"
scala -usejavacp -Djava.class.path="${CLASSPATH}" "$#"
""".format(cpString)
val targetFile = (target / "scala-sbt").asFile
writeFile(targetFile, launchString)
targetFile.setExecutable(true)
}
... // remember to add mklauncherTask to Project Settings
The mklauncher task creates a script target/scala-sbt that executes scala with the project classpath already set. It would be nice to have mklauncher executed automatically whenever the classpath changes, but I haven't looked into doing this yet.
(I use the Java classpath, rather than Scala's, for ease of creating embedded interpreters.)
The start-script SBT plugin is now at:
https://github.com/sbt/sbt-start-script
It requires a few steps to set up and generates scripts that do not work on OS X, but that can be easily fixed if you're on that platform (see below).
Setup
Install greadlink (OS X only):
a) brew install coreutils
b) map readlink to the new function (greadlink) by adding these lines to ~/.bashrc:
function readlink() { greadlink "$#"; }
export -f readlink`
Add start-script plugin to ~/.sbt/plugins/build.sbt:
addSbtPlugin("com.typesafe.sbt" % "sbt-start-script" % "0.8.0")
Add start-script task to current project:
$ sbt add-start-script-tasks # execute from directory where build.sbt resides
Add start-script support to current build.sbt:
import com.typesafe.sbt.SbtStartScript
seq(SbtStartScript.startScriptForClassesSettings: _*)
Note the blank line in between statements (de rigueur for SBT build files).
Generate Start Script
Then, whenever you want to create a script to start your app like sbt run-main, but without sbt, execute:
$ sbt start-script
Run
target/start mypackage.MyMainClass
Time flies by and a lot have changed since the other answers. It's currently SBT 0.13.6 time.
I think what you may need is the sbt-onejar plugin or the SBT Native Packager plugin.
sbt-onejar "is a simple-build-tool plugin for building a single executable JAR containing all your code and dependencies as nested JARs."
SBT Native Packager's "goal is to be able to bundle up Scala software built with SBT for native packaging systems, like deb, rpm, homebrew, msi."
Just discovered the sbt start script plugin: https://github.com/typesafehub/xsbt-start-script-plugin:
This plugin allows you to generate a script target/start for a
project. The script will run the project "in-place" (without having to
build a package first).
The target/start script is similar to sbt run but it doesn't rely on
SBT. sbt run is not recommended for production use because it keeps
SBT itself in-memory. target/start is intended to run an app in
production.
The plugin adds a task start-script which generates target/start. It
also adds a stage task, aliased to the start-script task.