Trigger SBT assembly from other subproject - scala

I have a root project containing 3 subprojects plus sbt config files and nothing else. 2 main subprojects are called server and backend, the other is called common and is dependency of both main projects. server is PlayFramework project. backed project is configured to generate assembly jar into resources directory of server.
The jar is generated correctly and server is able to see it, but I don't know how to run assembly task from backend when server is compiled(i.e. I want the server to depend on assembly of backend.jar)
/* [...] */
lazy val commonSettings = Seq(
version := "0.1",
organization := "org.example",
scalaVersion := "2.11.7"
)
lazy val server = (project in file("server")).enablePlugins(PlayJava).settings(commonSettings: _*).settings(
name := """example""",
libraryDependencies ++= Seq(
/* [...] */
),
/* [...] */
unmanagedResourceDirectories in Compile += { baseDirectory.value / "resources" }
).dependsOn(common)
lazy val backend = (project in file("backend")).settings(commonSettings: _*).settings(
assemblyJarName in assembly := "backend.jar",
assemblyOutputPath in assembly := server.base / "resources/backend.jar",
libraryDependencies := Seq(
)
).dependsOn(common)
lazy val common = (project in file("common")).settings(commonSettings: _*)
onLoad in Global := (Command.process("project server", _: State)) compose (onLoad in Global).value

Thanks to comment by #pfn I got it working. One thing I needed to do was to insert this line in server subproject settings and change server to Compile, so it is now:
(compile in Compile) <<= (compile in Compile) dependsOn (assembly in backend)

Related

Intellij SBT project: How to change the content roots?

This is the current content root configuration in my project:
However, I want the "scala" directory to be the actual test content root, and not the directory named "test". If I modify it, I get the warning that "Module is imported from Sbt. Any changes in its configuration will may be lost after re-importing." (and, indeed, they are).
Unfortunately, I couldn't find where in my Build.scala file (or any other file) this configuration is declared. What I can do to once and for all convince IntelliJ that "scala" is the correct test content root?
This is my Build.scala file (this is a Play 2.5.4 project if it matters):
import play.routes.compiler.StaticRoutesGenerator
import play.sbt.PlayScala
import play.sbt.routes.RoutesKeys._
import sbt.Keys._
import sbt._
object Build extends Build {
val main = Project("Mp3Streamer", file(".")).enablePlugins(PlayScala).settings(
scalaVersion := "2.11.8",
version := "1.0-SNAPSHOT",
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full),
libraryDependencies ++= Seq(
// a bunch of dependencies
),
resolvers += Resolver.mavenLocal,
javaOptions ++= Seq("-Xmx4000M", "-Xms2024M", "-XX:MaxPermSize=2000M"),
routesGenerator := StaticRoutesGenerator
)
}
By adding scalaSource in Test := baseDirectory.value / "test" "/scala", to my Build.scala file, I've been able to make the "scala" folder a test source, but the parent "test" folder was still also a test source:
As far as I could tell, this is a setting inherited from Play, since if I removed the .enablePlugins(PlayScala) code, the "test" folder stops being a test source. Following the instructions in https://www.playframework.com/documentation/2.5.x/Anatomy#Default-SBT-layout, I disabled the play layout, and then manually added the source and resource directories, which I copied from https://github.com/playframework/playframework/blob/master/framework/src/sbt-plugin/src/main/scala/play/sbt/PlayLayoutPlugin.scala#L9, only modifying the test source, and adding my own resource folders. My modified Build.scala file is now:
val main = Project("Mp3Streamer", file("."))
.enablePlugins(PlayScala)
.disablePlugins(PlayLayoutPlugin)
.settings(
target := baseDirectory.value / "target",
sourceDirectory in Compile := baseDirectory.value / "app",
// My change
sourceDirectory in Test := baseDirectory.value / "test" / "scala",
resourceDirectory in Compile := baseDirectory.value / "conf",
scalaSource in Compile := baseDirectory.value / "app",
// My change
scalaSource in Test := baseDirectory.value / "test" / "scala",
// I've added this resource
resourceDirectory in Test := baseDirectory.value / "test" / "resources",
javaSource in Compile := baseDirectory.value / "app",
sourceDirectories in(Compile, TwirlKeys.compileTemplates) := Seq((sourceDirectory in Compile).value),
sourceDirectories in(Test, TwirlKeys.compileTemplates) := Seq((sourceDirectory in Test).value),
// sbt-web
sourceDirectory in Assets := (sourceDirectory in Compile).value / "assets",
sourceDirectory in TestAssets := (sourceDirectory in Test).value / "assets",
resourceDirectory in Assets := baseDirectory.value / "public",
// Native packager
sourceDirectory in Universal := baseDirectory.value / "dist",
// Everything else is the same as the original Build.scala file
Honestly, this feels so hacky that I'll probably end up modifying my directory structure to match Play's default... But it's the principle that counts!

SBT: How to define dependencies of subprojects in subprojects' build.sbt files?

The following build.sbt file works, but it defines the dependencies of all subprojects:
name := "myproject"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
"org.scalafx" %% "scalafx" % "8.0.60-R9"
)
lazy val aLib = (project in file("lib/a"))
lazy val bLib = (project in file("lib/b"))
.dependsOn(aLib)
.dependsOn(cLib)
lazy val cLib = (project in file("lib/c"))
.dependsOn(aLib)
lazy val myApp = (project in file("myapp"))
.dependsOn(aLib)
.dependsOn(bLib)
.dependsOn(cLib)
.aggregate(aLib, bLib, cLib)
Since each subproject (directories lib/a, lib/b, lib/c, myapp) has its own build.sbt file, I would like to use those build files to define the individual dependencies of each project.
I tried to move the dependsOn/aggregate statements to the subprojects' build files, but I am not able to make it work that way. What is the recommended way?

Play Framework: Multi Module Project

I have created a multi module project with the following structure:
my_app
|__app
|__conf
|__public
|__project
| |__CommonBuild.scala
|__core
| |__src/main/scala
| |__src/test/scala
| |__build.sbt
|__build.sbt
I notice 2 issues:
In development mode when I do activator run and I make changes to my core module I see that it recompiles but when running it is picking up published core-[ver].jar dependency instead of the module locally.
In IntelliJ IDEA, I see the same issue. Under project structure of my_app I do see core added as both a module and a jar.
CommonBuild.scala:
object CommonBuild {
val settings: Seq[Setting[_]] = Seq(
organization = "com.myorg",
scalaVersion = "2.11.8",
transitiveClassifiers in Global := Seq(Artifact.SourceClassifier),
resolvers ++= Seq(
"scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
),
aggregate in update := false,
parallelExecution in Test := false,
Keys.fork in Test := false,
libraryDependencies ++= Seq(/*all dependencies here*/)
)
}
core/build.sbt:
name := "core"
CommonBuild.settings
unmanagedResourceDirectories in Compile += baseDirectory.value / "src" / "main" / "resources"
unmanagedResourceDirectories in Test += baseDirectory.value / "src" / "test" / "resources"
publishMavenStyle := true
publishArtifact in Test := true
my_app/build.sbt:
CommonBuild.settings
lazy val my_app =
(project in file(".")).
enablePlugins(PlayScala)
.aggregate(core)
.dependsOn(core % "test->test;compile->compile")
lazy val core = project
name := "my-app"
routesGenerator := InjectedRoutesGenerator
If I do not publish or publishLocal the core artifact, my_app does not pick up the core module to compile and throws a bunch of compilation errors.
How do I make sure that both activator and IntelliJ IDEA use core module itself as the dependency instead of the artifact produced by it?

Project aggregation in sbt

I am just starting to learn sbt to build scala projects.
Here is my build.sbt file
lazy val commonSettings = Seq(
organization := "com.example",
version := "0.1.0",
scalaVersion := "2.11.7"
)
lazy val task = taskKey[Unit]("An example task")
lazy val root = project.in(file(".")).
aggregate(core).
settings(commonSettings: _*).
settings(
task := { println("Hello!") },
name := "hello",
version := "1.0"
)
lazy val core = project.in( file("SbtScalaProjectFoo") )
My project structure is as follows
SbtScalaProject
|--SbtScalaProjectFoo
|--build.sbt
|--build.sbt
When I try to run "sbt" inside SbtScalaProject I get the following
No project 'core' in 'file:/Users/asattar/Dev/work/SbtScalaProject/'
What am I missing?
Having multiple build.sbt's has proven to make problems for me, too.
I would recommend aggregating all project data into one build.sbt. If you want to modularize the build, consider moving parts into .scala-Files in (the root project's) project/ directory.

How to have sbt multi-project builds configure setting for subprojects?

I have an sbt (0.13.1) project with a bunch of subprojects. I am generating eclipse project configurations using sbteclipse. My projects only have scala source files, so I want to remove the generated src/java folders.
I can achieve that by (redundantly) adding the following to the build.sbt of each subproject:
unmanagedSourceDirectories in Compile := (scalaSource in Compile).value :: Nil
unmanagedSourceDirectories in Test := (scalaSource in Test).value :: Nil
I tried just adding the above configuration to the root build.sbt but the eclipse command still generated the java source folders.
Is there any way to specify a configuration like this once (in the root build.sbt) and have it flow down to each subproject?
You could define the settings unscoped and then reuse them
val onlyScalaSources = Seq(
unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value),
unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value)
)
val project1 = project.in( file( "project1" )
.settings(onlyScalaSources: _*)
val project2 = project.in( file( "project2" )
.settings(onlyScalaSources: _*)
You could also create a simple plugin (untested code)
object OnlyScalaSources extends AutoPlugin {
override def trigger = allRequirements
override lazy val projectSettings = Seq(
unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value),
unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value)
)
}
More details about creating plugins in the plugins documentation