Create target directory outside project directory with sbt - scala

The structure of my project is:
└───current-working-dir
├───my-project
├───src
When I run sbt compile in current-working-dir where .sbt file looks like:
lazy val root = (project in file("my-project"))
.settings(
name := "my-project",
settings,
libraryDependencies ++= commonDependencies
)
then it generates target in the project directory:
└───current-working-dir
├───my-project
├───src
├───target
Is it possible to make sbt to create target outside the project directory? For instance:
└───current-working-dir
├───my-project
├───src
├───target
or
└───current-working-dir
├───my-project
├───src
├───my-project-compilation
├───target

target setting controls where files are generated. Here is an example how to change it
target := baseDirectory.value / "my-project-compilation" / "target"

Actually, I guess correct is
lazy val root = (project in file("my-project"))
.settings(
name := "my-project",
settings,
libraryDependencies ++= commonDependencies,
target := baseDirectory.value / ".." / "my-project-compilation" / "target"
)
You can check that if you place file as current-working-dir/my-project/src/main/scala/App.scala then compiled class appears as current-working-dir/my-project-compilation/target/scala-2.13/classes/App.class.

Related

how to change the scalaPB default path of protobuf files?

I have a build.sbt for a couple of packages in the same project.
When I do sbt compile, my protobuf files are under [packagename]/src/main/protobuf/*,
so it won't scan these files since they have that additional package name in the path.
How to change the default protobuf file path?
It is unclear from your question whether your sbt build is a single or multi-project build. You can tell that it is a multi-project build if you see lines like val someSubProject = project.in(file(...).
If your build.sbt is a single project build, you can add a line to customize where protos are being scanned:
Compile / PB.protoSources += file("pkgname/src/main/protobuf")
If you have a multi-project build with a project proj1, then it should already work in the way you expect:
val proj1 = project.in(file("proj1"))
.settings(
PB.targets in Compile := Seq(
scalapb.gen(javaConversions=true) -> (sourceManaged in Compile).value / "scalapb"
),
libraryDependencies ++= Seq(
"com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf",
)
)
then sbt-protoc will generate sources for the protos under proj1/src/main/protobuf. The sources will get compiled as poart of the proj1 project.
You can customize the path it looks for by setting Compile / PB.protoSources within that project's setting. For example, if you want it to generate source for protos that are in another top-level directory, you can do:
val proj1 = project.in(file("proj1"))
.settings(
PB.targets in Compile := Seq(
scalapb.gen(javaConversions=true) -> (sourceManaged in Compile).value / "scalapb"
),
Compile / PB.protoSources :=
Seq((ThisBuild / baseDirectory).value / "somewhere" / "protos"),
libraryDependencies ++= Seq(
"com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf",
)
)
I recommend using AkkaGrpcPlugin and a multi-project SBT configuration.
Put the .proto files in a separate project and make the others depend on it. This project just has a single directory <root>/grpc/src/main/protobuf containing the .proto files. When this project is compiled it will create all the stub files which can be picked up by other projects that depend on it.
Here is an outline build.sbt file:
lazy val top_level =
(project in file("."))
.aggregate(grpc, main)
lazy val grpc =
project
.in(file("grpc"))
.settings(
???
)
.enablePlugins(AkkaGrpcPlugin)
lazy val main =
project
.in(file("main"))
.settings(
???
)
.dependsOn(grpc)
And add this to plugins.sbt:
addSbtPlugin("com.lightbend.akka.grpc" % "sbt-akka-grpc" % "1.1.1")

Root project version is not set for subprojects

I'm packaging multi-project sbt build with sbt package and have the following version property set in the build.sbt root:
version := "1.0.0"
But unfortunately the aggregated subprojects jar are all have 0.1.0-SNAPSHOT suffix unless I specify a version := for each of the subproject specifically. Is there a way to propagate the version := "1.0.0" set in the build.sbt root? Or any other way to set a version for all the aggregated subprojects?
I tried
lazy val root = project
.in(file("."))
.aggregate(
//...
)
.settings(
version := "1.0.0",
//...
)
But it didn't work.
From Examples of scoped key notation in the sbt shell:
ThisBuild / version sets the subproject axis to “entire build” where the build is ThisBuild, with the default configuration.
Therefore, as #LuisMiguelMejíaSuárez mentioned in the comment, the following should do that:
ThisBuild / version := "1.0.0"
lazy val root = project
.in(file("."))
.aggregate(
//...
)
.settings(
//...
)
In general, I'd recommend reading about Scopes in sbt.

Importing assets from an NPM Package

Say I want to include font-awesome in my webapp. So I define my build.sbt as follows:
val commonSettings = Seq(
name := "repro",
version := "1.0",
scalaVersion := "2.12.8",
unmanagedSourceDirectories in Compile +=
baseDirectory.value / ".." / "shared" / "src" / "main" / "scala"
)
val client = project.in(file("client"))
.settings(commonSettings: _*)
.settings(
npmDependencies in Compile ++= Seq(
"font-awesome" -> "4.7.0",
),
mainClass in Compile := Some("app.App"),
scalaJSUseMainModuleInitializer := true,
webpackBundlingMode := BundlingMode.LibraryOnly(),
)
.enablePlugins(ScalaJSPlugin)
.enablePlugins(ScalaJSBundlerPlugin)
val server = project.in(file("server"))
.settings(commonSettings: _*)
.settings(
npmAssets ++= NpmAssets.ofProject(client) { nodeModules =>
(nodeModules / "font-awesome").allPaths
}.value
)
.enablePlugins(WebScalaJSBundlerPlugin)
Can I configure this project so that my "package" command will then include the css in my target/webapp folder? Or is there another command I have to use?
In addition to your configuration, you have to add the following settings to the server project:
.settings(
scalaJSProjects := Seq(client),
pipelineStages in Assets := Seq(scalaJSPipeline),
managedClasspath in Runtime += (packageBin in Assets).value,
WebKeys.packagePrefix in Assets := "public/"
)
The first line introduces a dependency between the server project and the assets produced by the client project. The scalaJSProjects settings is introduced by the sbt-web-scalajs plugin.
The second line integrates the assets produced by the client project into the Web assets managed by sbt-web.
The third line tells sbt to include the assets produced by the sbt-web plugin to the classpath of the server.
The last line is optional, it simply puts the produced assets into the public/ resource directory, so that they are not mixed with other classpath resources which are not meant to be exposed to the outside world.
With this configuration, you can build the production assets with the following command:
> server/web-assets:package
Or, from a build file, by using the packageBin in Assets task.
This will produce a target/scala-2.12/repro_2.12-1.0-web-assets.jar file containing the JavaScript bundle produced by Webpack on your client project, as well as the font-awesome/ directory.

How to copy resources with scala + play + sbt

I am using sbt [0.13] to compile a play [2.2] project using scala [2.10.3]. I have .sql files and scala files used for database migrations. The directory structure looks like:
app
|-> db
|-> migration
|-> V1__init.scala
|-> V2__newTable.sql
When I run compile from the play console (REPL), the scala file (V1__init.scala) is compiled to a .class and copied to the classes folder. But the .sql file is not moved.
I tried adding unmanagedResourceDirectories in Compile <++= baseDirectory { dir => Seq(dir/"app/db/migration") ++ Seq(dir/"db/migration") } but it did not copy the files. The whole block looks like:
val main = play.Project(appName, appVersion, appDependencies).settings(
scalaVersion := "2.10.3",
scalacOptions ++= Seq("-feature"), // enable feature warnings
unmanagedResourceDirectories in Compile <++= baseDirectory { dir => Seq(dir/"app/db/migration") ++ Seq(dir/"db/migration") }
)
I also tried using copyResources, but couldn't get that to work. Described here: http://www.playframework.com/documentation/2.0/SBTSettings
So does anyone know how I can copy the sql files to the classes folder?
Thanks!
UPDATE
I got IO.copyDirectory(new java.io.File("app/db/migration"), new java.io.File("target/scala-2.10/classes/db/migration"), true) to copy the files, but the destination is hard-coded and will change when I update scala
val main = play.Project(appName, appVersion, appDependencies).settings(
scalaVersion := "2.10.3",
scalacOptions ++= Seq("-feature"), // enable feature warnings
unmanagedResourceDirectories in Compile <+= scalaSource in Compile,
excludeFilter in unmanagedResources in Compile := "*.scala" || "*.java"
)
You can check easily the contents in the class folder with:
sbt clean full-classpath && ls target/scala-2.10/classes/db/migration/

How do I get sbt 0.10.0 to compile files in a subdirectory?

I have a build.sbt file in my project root.. all my source files live in the subdirectory src (and src/irc, src/xmpp).
Here is my build.sbt
name := "mrtoms"
organization := "chilon"
scalaVersion := "2.9.0"
version := "0.1"
libraryDependencies ++= Seq("commons-httpclient" % "commons-httpclient" % "3.1")
crossPaths := false
scalaHome := Some(file("/usr/share/scala"))
target := file("project/target")
sourceDirectory := file("src")
mainClass := Some("org.chilon.mrtoms.MrToms")
However sbt always just makes an empty jar file.
I tried putting build.sbt inside the "src" directory but then it missed out all the scala files in subdirectories of "src".
Seems that you need to provide path relative to the base directory. This should work for you (it replaces sourceDirectory := file("src")):
scalaSource in Compile <<= baseDirectory(_ / "src")
Some more information you can find in this thread:
http://groups.google.com/group/simple-build-tool/browse_thread/thread/095e87247d146fa7?fwc=1
If you want to replace the default convention then you need to override both scala and java source locations
scalaSource in Compile <<= baseDirectory(_ / "src")
javaSource in Compile <<= baseDirectory(_ / "src")