How to run main project with all sub-project in scala SBT - scala

I'm using multi-project build in SBT to create a simple microservice architecture. I defined build.sbt as:
addCommandAlias("rebuild", ";clean; compile; package")
lazy val oc = Project(id = "oc",
base = file("."),
settings = commonSettings).aggregate(
persistence,
core,
configuration,
integration).dependsOn(
persistence,
core,
configuration,
integration)
.configs (MultiJvm)
lazy val persistence = Project(...)
lazy val core = Project(...)
lazy val log = Project(...)
lazy val configuration = Project(...)
lazy val integration = Project(...)
lazy val commonSettings = Defaults.coreDefaultSettings ++
basicSettings ++
net.virtualvoid.sbt.graph.Plugin.graphSettings
lazy val basicSettings = Seq(
version := PROJECT_VERSION,
organization := ORGANIZATION,
scalaVersion := SCALA_VERSION,
scalacOptions in Compile ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlog-reflective-calls", "-Xlint" , "-encoding", "utf8"),
javacOptions in Compile ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"),
javaOptions in run ++= Seq("-Xms128m", "-Xmx1024m"),
libraryDependencies ++= Seq( ...
),
fork in run := true,
// disable parallel tests
parallelExecution in Test := false,
licenses := Seq(("CC0", url("http://creativecommons.org/publicdomain/zero/1.0"))),
fork in Test := true
)
For single sub-project I can easily build the project. But I cannot build all projects at once to check the working as a whole system. Any help from the experts on building the system would be appreciable

Related

How to apply common test configuration to all projects?

I'm migrating an old project to Scala 3. The build.sbt is as follows:
import Dependencies._
inThisBuild(
Seq(
scalaVersion := "2.12.7",
scalacOptions ++= Seq(
"-unchecked",
// more
)
)
++ inConfig(Test)(Seq(
testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-o", "-e"),
// more
))
)
lazy val root = (project in file("."))
.aggregate(
`test-util`
)
lazy val `test-util` = project
Now, I want to separate stuff inside inThisBuild for legibility.
import Dependencies._
ThisBuild / scalaVersion := "3.0.1"
ThisBuild / scalacOptions ++= Seq(
"-unchecked",
// more
)
lazy val testSettings = inConfig(Test)(
Seq(
testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-o", "-e"),
// more
))
lazy val root = (project in file("."))
.aggregate(
`test-util`
)
.settings(testSettings)
lazy val `test-util` = project
As you can see, I'm having to apply the testSettings for each project. Ideally, I'd like to do something like ThisBuild / Test := testSettings but that is not valid syntax.
Is there a way to apply the testSettings to all projects without having to explicitly set .settings(testSettings)?
Edit:
I understand I can write each line of testSettings with ThisBuild / Test prefix, but I’d rather not repeat the same prefix. I’m looking for something like what I’ve done with scalacOptions.
Is there a way to apply the testSettings to all projects without having to explicitly set .settings(testSettings)
Consider creating an auto plugin which can inject settings automatically in all the sub-projects, for example in project/CommonTestSettings.scala
import sbt._
import Keys._
object CommonTestSettings extends sbt.AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements
override lazy val projectSettings =
inConfig(Test)(
Seq(
testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-o", "-e")
// more
)
)
}
You can test with show testOptions which should reveal the common settings in all the sub-projects, for example in my project where root aggregates foo and bar I get something like
sbt:sbt-multi-project> show testOptions
[info] foo / Test / testOptions
[info] List(Argument(Some(TestFramework(org.scalatest.tools.Framework, org.scalatest.tools.ScalaTestFramework)),List(-o, -e)))
[info] bar / Test / testOptions
[info] List(Argument(Some(TestFramework(org.scalatest.tools.Framework, org.scalatest.tools.ScalaTestFramework)),List(-o, -e)))
[info] Test / testOptions
[info] List(Argument(Some(TestFramework(org.scalatest.tools.Framework, org.scalatest.tools.ScalaTestFramework)),List(-o, -e)))
As you can done with scalaVersion and scalacOptions, you can do with Test. For example:
lazy val testSettings = inConfig(Test)(
Seq(
testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-o", "-e"),
// more
))
Can be rewritten as:
ThisBuild / Test / testOptions += Test.Argument(TestFrameworks.ScalaTest, "-o", "-e")
Is it this that you want? Or do you want to pass a sequence directly?

how to run scala sbt-native-packager for a appJS/appJVM cross-build project

The sbt-native-packager can make a zip file with all dependencies and a script to run_
$ sbt universal:packageBin
I have a scala web application, using cross-build (appJS for front-end and appJVM for back-end).
How do I run this packager for the appJVM?
I've tried as follows, but it does not accept the command:
$ sbt appJVM/universal:packageBin
Here it is the build.sbt project, from https://www.scala-js.org/doc/project/cross-build.html
...
lazy val foo = crossProject.in(file(".")).
settings(
name := "foo",
version := "0.1-SNAPSHOT"
).
jvmSettings(
// Add JVM-specific settings here
).
jsSettings(
// Add JS-specific settings here
)
lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js
How do I run this packager for the appJVM?
And how I include the file generated by sbt appJS/fullOptJS?
And some other static files?
Update with Ivan response
build.sbt:
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
val sharedSettings = Seq(
scalaVersion := "2.12.8",
)
lazy val app =
crossProject(JSPlatform, JVMPlatform)
.in(file("."))
.settings(sharedSettings)
.jsSettings(
)
.jvmSettings(
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % "10.1.9"
),
)
lazy val backend = project
.enablePlugins(UniversalPlugin)
.enablePlugins(JavaAppPackaging)
.dependsOn(app.jvm)
.settings(
mainClass in Compile := Some("com.example.EchoServer")
)
lazy val frontend = project
.enablePlugins(ScalaJSPlugin)
.dependsOn(app.js)
backend
.settings(
Seq(
resourceGenerators in Compile += Def.task {
Seq(
(fullOptJS in Compile in frontend).value,
(fastOptJS in Compile in frontend).value
).map { js =>
val resource = (resourceManaged in Compile).value / "public" / "assets" / js.data.name
IO.write(resource, IO.read(js.data))
resource
}
}.taskValue
)
)
and run:
$ sbt backend/universal:packageBin
34: error: type mismatch;
found : Seq[sbt.Def.Setting[Seq[sbt.Task[Seq[java.io.File]]]]]
required: Int
Seq(
^
[error] Type error in expression
I used the following structure.
Define a shared project that needs to be cross-compiled for JS and Scala.
lazy val shared = CrossPlugin.autoImport
.crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
.jvmSettings(???)
.jsSettings(???)
lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js
Add project that contains a Main class.
lazy val backend = project
.enablePlugins(UniversalPlugin)
.enablePlugins(JavaAppPackaging)
.dependsOn(sharedJvm)
Add web project containing web related code.
lazy val web = project
.enablePlugins(ScalaJSPlugin)
.dependsOn(sharedJs)
And finally, attach resources from web compiled into JS to backend.
backend
.settings(
Seq(
resourceGenerators in Compile += Def.task {
Seq(
(fullOptJS in Compile in web).value,
(fastOptJS in Compile in web).value
).map { js =>
val resource = (resourceManaged in Compile).value / "public" / "assets" / js.data.name
IO.write(resource, IO.read(js.data))
resource
}
}.taskValue
)
Main class needs to service compiled JS from public/assets, as configured in sbt, and any other web resources from its class path.

SBT/Scala: macro implementation not found

I tried my hand on macros, and I keep running into the error
macro implementation not found: W
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
I believe I've set up a two pass compilation with the macro implementation being compiled first, and the usage second.
Here is part of the /build.sbt:
lazy val root = (project in file(".")).
settings(rootSettings: _*).
settings(name := "Example").
aggregate(macros, core).
dependsOn(macros, core)
lazy val macros = (project in file("src/main/com/example/macros")).
settings(macrosSettings: _*).
settings(name := "Macros")
lazy val core = (project in file("src/main/com/example/core")).
settings(coreSettings: _*).
settings (name := "Core").
dependsOn(macros)
lazy val commonSettings = Seq(
organization := Organization,
version := Version,
scalaVersion := ScalaVersion
)
lazy val rootSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ rootDeps ++ macrosDeps ++ coreDeps
)
lazy val macrosSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ macrosDeps
)
lazy val coreSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ coreDeps
)
The macro implementation looks like this:
/src/main/com/example/macros/Macros.scala
object Macros {
object Color {
def ColorWhite(c: Context): c.Expr[ObjectColor] = c.Expr[ObjectColor](c.universe.reify(ObjectColor(White())).tree)
}
}
The usage looks like this:
/src/main/com/example/core/Main.scala
object Macros {
import com.example.macros.Macros._
def W: ObjectColor = macro Color.ColorWhite
}
object Main extends App {
import Macros._
println(W)
}
Scala 2.11.6. SBT 0.13.8.
What am I doing wrong?
Thanks for your advice!
Fawlty Project:
The Project on Github
Working Project:
Rearranged the projects to a more correct form:
The cleanedup working project
Your macros and core projects don't contain any files, so they don't cause the problem. The error happens when sbt compiles root, which contains both Main.scala and Macros.scala by the virtue of you saying project in file(".") in the sbt build.

include upstart scripts when running debian:packageBin

i want to start my scala app as a background service on a ubuntu machine. I'm currently trying to figure out how to use the JavaServerAppPackaging Settings in my package task.
Any suggestion, what I have to add where to include the upstart script in my deb file?
This is my Project description incl. oneJar and debian building.
lazy val root = Project(id = appName, base = file("."), settings = SbtOneJar.oneJarSettings ++ packageSettings ++ allSettings ++ Project.defaultSettings)
lazy val allSettings = Seq(
mainClass in SbtOneJar.oneJar := Some("Kernel"),
resolvers += "Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases",
resolvers += "Sonatype OSS Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/",
libraryDependencies ++= dependencies)
lazy val packageSettings = JavaServerAppPackaging.settings ++ packagerSettings ++ Seq(
version := appVersion,
packageSummary := appName,
packageDescription := appName,
maintainer := appAuthor,
mappings in Universal += {
SbtOneJar.oneJar.value -> jarFsPath
},
linuxPackageMappings in Debian <+= (SbtOneJar.oneJar) map {
jar: File =>
(packageMapping(jar -> jarFsPath) withUser unixUser withGroup unixGroup withPerms "0755")
},
debianPackageDependencies in Debian ++= Seq("openjdk-7-jre-headless"))
}
The settings should include the packageArchetype.java_server value eg:
lazy val packageSettings = packageArchetype.java_server ++ Seq(
/* ... */
}

Is it possible to re-launch and test xsbti.AppMain derived application from sbt?

I'm developing an sbt launched application with custom command line interface.
The problem is that every time I want to test it I have to remove the previously published boot directory and then recompile and publish locally the artefacts, and then finally run the app and test it manually. Part of this is accomplished by running external shell scripts.
How could I make sbt doing the job for me? I've already made the skeleton command for it:
lazy val root = Project(
id = "app",
base = file("."),
settings = buildSettings ++ Seq( resolvers := rtResolvers,
libraryDependencies ++= libs,
scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked"),
commands ++= Seq(launchApp))
)
val launchApp = Command.command("launch") { state =>
state.log.info("Re-launching app")
state
}
Create launcher configuration file, e.g. fqb.build.properties in the project's main directory.
Create a script that launches the application
#!/usr/bin/env bash
java -jar /path/to/sbt-launch.jar "$#"
Define task and command:
lazy val launcherTask = TaskKey[Unit]("launch", "Starts the application from the locally published JAR")
lazy val launchApp: Seq[Setting[_]] = Seq(
commands += Command.command("publish-launch") { state =>
state.log.info("Re-launching app")
val modulesProj = modules.id
s"$modulesProj/publishLocal" ::
"publishLocal" ::
launcherTask.key.label ::
state
},
launcherTask := {
"launch #fqb.build.properties" !<
}
)
Add it as a setting to a project:
lazy val root = Project(
id = "app",
base = file("."),
settings = buildSettings ++ Seq( resolvers := rtResolvers,
libraryDependencies ++= libs,
scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked"),
launchApp)
)
Remember to delete old ~/.<app_name> directory when re-deploying, so the changes could take effect.