How to share resources between projects in SBT - scala

The project I'm working on at work is a webapp on the Lift Framework. We're using xsbt web plugin as well. There's a "core" project, which contains the vast majority of the functionality; my current goal is to create two "distribution" projects that add a different set of classpath resources to the "core" project. The problem is that I either 1) can't get the "distribution" projects to run, or 2) Get them to run, but the required resource doesn't seem to be there.
What I've tried
Here's an abridged version of my project/Build.scala:
lazy val core = Project("Core", file("core"))
.settings( /*some dependencies, resolvers, webSettings */ )
lazy val app1 = Project("App1", file("app1"))
.aggregate(core)
.settings( /*the same settings as core */ )
lazy val app2 = Project("App2", file("app2"))
.aggregate(core)
.settings( /*the same settings as core*/ )
Then in the directory structure for both app1 and app2, I have a file at src/main/resources/aFileINeed. The core application is using the class.getResource approach to load the file from the classpath.
Problems
If I try to run one of the distribution projects, using container:start, it does not detect the required file in the classpath. Also, it claims that src/main/webapp is not an existing directory (that folder is included in the core project, as it is required by the xsbt web plugin).
How can I get these projects to "merge" their resources? I expected that using aggregate or dependsOn in the Build.scala project definition would handle that for me, but it apparently doesn't.

This is what I'm doing. I create a global 'resources' directory in the root of the project, and then the following variable:
lazy val globalResources = file("resources")
And then in every project's settings:
unmanagedResourceDirectories in Runtime += globalResources
For projects that use the xsbt-web-plugin or some other library that imports it you'll have to use the stronger
unmanagedResourceDirectories in Compile += globalResources
Beware that using this solution your projects will potentially have muliple resource directories and AFAIK if you define the same file twice compile:copy-resources is going to be angry at you.

Related

Mutli-projects build with gradle like sbt

I'm basically a scala developer and i have project in scala - sbt recently i've started using kotlin and trying to some parts of my code in to kotlin. I need help in understanding gradle build system.
db-service
queue-service
business-logic
processor-code depends on projects on db-service, queue-service and business logic
another project "X" depends on queue-service and some other service.
Usually in sbt this is something very straight forward you can use ProjectRef to include these projects as dependencies.
How do i achieve the same with gradle? Thanks in advance
//Update
sample build.sbt
lazy val buildSettings = Seq(
scalaVersion := "2.12",
fork in Test := true,
fork in IntegrationTest := true,
...
)
lazy val root = Project("processor-code", file("."))
.settings(buildSettings: _*)
.settings(
libraryDependencies ++= //Deps
)
.dependsOn(db-service, queue-service, utilities)
.aggregate(db-service, queue-service, utilities)
lazy val db-service = ...
lazy val queue-service = Project("queue-service", file(".")).settings()...
lazy val utilities = ProjectRef(file("../utilities"), "utilities")
i have tried including the project in settings.gradle
include 'project'
project(":project").projectDir = "../myProject"
and added
implementation(project(":project"))
however, it doesn't seem working show error plugin already on classpath, then i've also tried creating a submodule and it seemed like it was working but when i was trying to run it throws a initialization exception
i've understood that we can configure a project in the following scenario
Root project: (contains common build.gradle)
| - subproject A
| - subproject B
| - myapp
now myapp easily can depend on subprojects
My scenario (no common build.gradle, each project will have its own build.gradle)
| Independent project A
| Independent project B
| my app
While it's true that you can only depend on other sub-projects, technically, that's still possible with Gradle.
Since project A is a Gradle project, you could pack it with gradle jar command. Then you could move the produced JAR to wherever you want, but probably to your my app project.
Now it's possible to launch an arbitrary command from Gradle using project.exec {}
What's more, you can even write your own Kotlin/Groovy function inside Gradle to do that for you.
That's what SBT is doing for you, actually.

sbt : Is there a better way of structuring large build.sbt files

Problem description: large sbt file
Our current build.sbt spanns 250+ lines.
We have two problems:
readability
current approach grouping of data and comments:
// Plugins ///////////////////////////////////////////////////
enablePlugins(DockerPlugin)
// basic configuration : projects ///////////////////////////
name := """projectName"""
lazy val projectName =
(project in file(".")).....
logic reuse
We have some configuration logic we would like to share between different projects.
Question
Is there a way to include other *.sbt files?
Or do you have a suggestion how to solve this problem without resorting to write a sbt plugin?
Is there a way to include other *.sbt files?
Yes, you can simply put parts of your build.sbt file into other *.sbt files within your project root. SBT picks up all *.sbt files and merges them together, as there was only a single large file.
One thing you can do is to factor out parts of your build info into scala files in the project directory.
E.g. in our build we have a file Dependencies.scala in the project directory, which contains all dependencies of the various projects in one place:
object Dependencies {
val akka_actor = "com.typesafe.akka" %% "akka-actor" % "2.3.13"
// ...
}
This can then be imported from the build.sbt:
import Dependencies._
lazy val foo = Project(...) dependsOn (akka_actor, ...)
You can also put tasks and commands into objects in the project directory.
Update: One thing I often do when looking for inspiration about how to organize a build is to look at the build of complex, high-profile scala projects such as akka. As you can see, they have moved a lot of logic into scala files in the project directory. The build itself is defined in AkkaBuild.scala.

Add plugins under a same project in sbt

I'm trying to build a Scala project aggregated by multiple projects, one of which is an sbt plugin. I would like to use this plugin in another subproject under the same parent project, but I don't quite understand how to do this.
My "build.sbt" in the project root is like this:
lazy val plugin = project
.in(file("sbt-Something"))
.dependsOn(lib)
.settings(common: _*)
.settings(name := "My plugin",
sbtPlugin := true)
lazy val examples = project
.in(file("examples"))
.dependsOn(lib, plugin)
.settings(common: _*)
.settings(name := "Examples")
How to add the plugin as a plugin to project examples?
I don't think you can have a plugin at the same "level" that project which is using it.
If you think of it, the plugin must be available before the compilation of the project that is using it. This is because it may, for example modify the build settings, which would influence the way the project is built.
If you want to keep your plugin within your project you can do so by declaring a project in the project/project directory.
$YOUR_PROJECT_ROOT/project/build.sbt
lazy val plugin = project
.in(file("sbt-plugin"))
.dependsOn(lib)
.settings(name := "My plugin", sbtPlugin := true)
lazy val lib = project.in(file("lib"))
lazy val root = project.in(file(".")).dependsOn(plugin)
Then you can put your code to sbt-plugin directory, and your shared library code to the lib folder.
In your normal build you can reference the shared library and the plugin.
$YOUR_PROJECT_ROOT/build.sbt
val lib = ProjectRef(file("project/lib"), "lib")
val root = project.in(file(".")).dependsOn(lib).enablePlugins(MyPlugin)
Please note that maybe it would be better to keep the shared library as a separate project, because I think this setup may be a bit tricky. For example if you change something in the shared library the main project should recompile and should use new code. The plugin however will only use new code after issuing the reload command on the project.
If you want to share settings between the projects you can check answers to How to share version values between project/plugins.sbt and project/Build.scala?

scalajs: multiple apps in one project?

If I understood scalajs docs correctly it allows only one javascript generation per project.
Is there a way to avoid this limitation?
Currently I created scalajs sub project for Play framework. In this sub project I planned to create all scalajs apps for the service I am working on. Now I found this limitation and it's really confusing and annoying, because the only two solutions I can think of are:
create one "mega-script" which isn't acceptable for me
for every scalajs app create separate sub projects
They both are really not acceptable for a big project.
Every scalajs in it's own subproject and manage everything via SBT MutliProject
Here is somewhat complex example of play project, that has 6+ subprojects that compiles to one single file. scala-js-binding
Check the Build.scala
lazy val preview = (project in file(".")).enablePlugins(PlayScala) settings(previewSettings: _*) dependsOn shared dependsOn bindingPlay aggregate frontend
//aggregate scalaJs
lazy val frontend = Project(
id = "frontend",
base = file("frontend") ) dependsOn shared dependsOn binding
...
scalajsOutputDir := baseDirectory.value / "public" / "javascripts" / "scalajs",
//fastOptJs - not optimized (3Mb)
compile in Compile <<= (compile in Compile) dependsOn (fastOptJS in (frontend, Compile)),
//fullOptJS - fully optimized (330k)
dist <<= dist dependsOn (fullOptJS in (frontend, Compile)),
Scala.js is indeed designed to generate one JavaScript output per project. There is virtually no way to change this.
However, this is not a restriction of Scala.js. Scala/Java themselves behave the same way: you cannot generate two .jars from a single sbt project for a Scala/Java application. So I do not see why Scala.js should behave any differently.
Use multiple projects in your sbt build for this, as suggested by #user3430609.

Custom SBT Build file to not compile views in Play 2.0

I have a Play 1.2.4 app that I'm trying to migrate to Play 2.0.2. I currently have a structure in Play 1.2.4 like this:
Website depends on Frontend
Catalog depends on Frontend
Frontend depends on (a routes file being defined when compiling views)
Where Frontend contains a bunch of views that are used by both Website and Catalog. This decision was made because Catalog is really lightweight and is used for quick development of Frontend. While Website has a lot more code in it and takes longer to code/compile/test.
I cannot setup these projects as subprojects like is decribed here http://www.playframework.org/documentation/2.0/SBTSubProjects because there is a circular dependency. The views use Asset.of which requires the routes file to be defined. But the Website and Catalog each define a routes file and Play 2.0 does not support routes files from dependencies (this is supposed to come in Play 2.1). And in the Catalog the views are referenced in the controllers.
I was thinking that if I could change my build logic for Frontend to not try to compile the views, but instead just publish an artifact containing them then I could have Website and Catalog add those artifacts to the views it defines and build them together. This would break the circular dependency I have.
Has anyone else done this before? I'm too much of a beginner with SBT to even know if this is possible. Could anyone tell me how I could modify the Build.scala file to stop compiling the views but export them instead? Would it make sense for me to make this an SBT plugin? Of if you know of any code that shows how to do this another could you post a link to the code?
I used the play new to create two projects. The LDAPInterface was an interface to LDAP that we wanted to use across several applications. The Second Project was the Access manger. In the AccessManager\project\build.scala file, we structured it this way in order to use the LDAPInterface project. In eclipse, we just included the LDAPInterface in the project dependency section so we could debug. You could always compile a jar file and include that, but ... not as good if you want to drill down on project dependencies within eclipse. If we used play.Project it recognized it as a web project. If we just used Project it seemed to think it was a console application.
import sbt._
import Keys._
import play.Project._
object LDAPInterface {
lazy val depProject = RootProject(file("../LDAPInterface"))
}
object ApplicationBuild extends Build {
val appName = "AccessManager"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
//Add your project dependencies here,
javaCore,
javaJdbc,
javaEbean
)
// lazy val root = Project(id = "AccessManager",
// base = file(".")
//).dependsOn(LDAPInterface.depProject)
lazy val main = play.Project(appName, appVersion, appDependencies).settings(
// Add your own project settings here
).dependsOn(LDAPInterface.depProject)
}