Intellij SBT project: How to change the content roots? - scala

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!

Related

ScalaJS - SBT crossproject configuration for testing part of the `JS`-module on the JVM

The build.sbt below is for a project where there 3 modules:
Shared-module
compiles to the JS-platform and to the JVM-platform
visible to the JVM module, to the JS module and to itself
JVM-module
compiles to JVM-platform,
not visible to JS-module, nor to Shared-module, only visible to itself
JS-module
compiles to JS-platform
not visible to JVM-module, nor to Shared-module, only visible to itself
I would like to have a fourth module TestJSonJVM which compiles to both the JVM-platform and to the JS-platform and it is visible only to the JS-module and to itself.
The purpose of the TestJSonJVM-module is to extract part of the JS-modul's logic/code into TestJSonJVM-module which makes it possible to test the extracted part on the JVM-platform (which has better tooling - (debuging, IDE integration, etc..) than the JS-platform for ScalaJS).
How do I need to modify the build.sbt file below ? Such that this becomes possible ?
lazy val root = project
.in(file("."))
.aggregate(imJS, imJVM)
.settings(
scalaVersion := Settings.versions.scala,
publish := {},
publishLocal := {}
)
lazy val im = crossProject
.in(file("."))
.settings(
libraryDependencies ++= Settings.sharedDependencies.value,
addCompilerPlugin(
"org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full),
scalaVersion := Settings.versions.scala,
name := "im",
version := "0.1-SNAPSHOT"
)
.jvmSettings(
libraryDependencies ++= Settings.jvmDependencies.value,
mainClass in Test := Some("app.server.rest.TestHttpServerApp"),
mainClass in Compile := Some("app.server.rest.TestHttpServerApp")
)
.jsSettings(
mainClass in Compile := Some("app.client.Main"),
libraryDependencies ++= Settings.scalajsDependencies.value,
persistLauncher in Compile := true,
persistLauncher in Test := false,
jsDependencies += RuntimeDOM,
scalaJSOptimizerOptions ~= { _.withDisableOptimizer(true) }
)
lazy val imJVM = im.jvm
lazy val imJS = im.js
persistLauncher in Compile := true
persistLauncher in Test := false
cancelable in Global := true

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?

Trigger SBT assembly from other subproject

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)

How to reference a custom SBT Setting in sub-projects

Somewhat similar to this question, how can reference a custom setting in a sub project.
In build.sbt:
import sbt.Keys._
val finagleVersion = settingKey[String]("Defines the Finagle version")
val defaultSettings = Defaults.coreDefaultSettings ++ Seq(
finagleVersion in ThisBuild := "6.20.0",
organization in ThisBuild := "my.package",
scalaVersion in ThisBuild := "2.10.4",
version in ThisBuild := "0.1-SNAPSHOT"
)
lazy val root = project.in(file(".")).aggregate(thrift).settings(
publishArtifact in (Compile, packageBin) := false,
publishArtifact in (Compile, packageDoc) := false,
publishArtifact in (Compile, packageSrc) := false
)
lazy val thrift = project.in(file("thrift"))
In thrift/build.sbt:
name := "thrift"
// doesn't work
libraryDependencies ++= Seq(
"com.twitter" %% "finagle-thriftmux" % (finagleVersion in LocalRootProject).value
)
.sbt files cannot see the definitions (e.g., vals) in other .sbt files, even if they are part of the same build.
However, all .sbt files in a build can see/import the content of project/*.scala files. So you'll have to declare your val finagleVersion in a .scala file:
project/CustomKeys.scala:
import sbt._
import Keys._
object CustomKeys {
val finagleVersion = settingKey[String]("Defines the Finagle version")
}
Now, in your .sbt files, just
import CustomKeys._
and you're good to go.