Running multi-project sbt project results in clobbered compilation of shared project - scala

I have a play application and a normal scala application that have shared code in a dependency defined as such:
project A
project B
shared
lazy val shared = (project in file("shared")).settings(...)
lazy val projectA = (project in file("A")).settings(...).dependsOn(shared)
lazy val projectB = (project in file("B")).settings(...).dependsOn(shared)
Due to the way sbt handles triggered execution, running sbt ~run in development mode is not usable for handling file changes correctly. I'm also using sbt-revolver to handle re-running the non-play application. As a result, I run both applications separately using the commands:
sbt 'project A' '~run'
sbt 'project B' '~reStart'
in parallel, so when I make a change to shared, both try to recompile it, and therefore sometimes result in an error. I frankly despise SBT's documentation, and cannot figure out how to get this to work within SBT, so I am asking for help.

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 auto-plugins - disable them but for one sub project

Switching sbt-assembly from 0.11.2 to 0.13.0, I suddenly find myself in a situation where calling sbt assembly does not just invoke the task in the sub-project that explicitly added assemblySettings, but it tries to run it for each and every sub project.
So, if I have
lazy val root = project(...).aggregate(core, app)
lazy val core = project(...)
lazy val app = project(...).dependsOn(core)
How can I disable the assembly task for all but the root project? With other plugins such as sbt-buildinfo this problem doesn't occur because you have to explicitly enable the plugin per sub-project.
The goal is to be able to run sbt assembly so it will do that just for the root project.
Found the answer in a closed issue. You have to add the following line to your common settings:
aggregate in assembly := false

Custom sbt configuration with Intellij auto import

I can't get the embedded sbt plugin (with auto import enabled) in Intellij (13.1) to recognize custom sbt configurations. I have the follow setup in my sbt build file:
lazy val EndToEndTest = config("e2e") extend (Test)
private lazy val e2eSettings =
inConfig(EndToEndTest)(Defaults.testSettings)
lazy val root: Project = Project(
id = "root",
base = file(".")
)
.configs(EndToEndTest)
.settings(e2eSettings)
The code works according to expectations in the sbt console. E.g I can write:
sbt e2e:test (and it will execute tests located in /src/e2e/scala)
The issue is that the directory /src/e2e/scala won't get registered as a source directory in Intellij. This makes it hard to use intellij to manage the tests. I can manually mark the directory as source but it gets reverted every time
I update my sbt files (auto import).
Do a manual update through the sbt tool window
Related:
Using the preconfigured configuration IntegrationTest works as expected but custom once don't.
According to sbt-idea documentation this can be done in your case by adding
ideaExtraTestConfigurations := Seq(EndToEndTest)
to your project settings.

What is the issue with this sbt file?

When I import a SBT project into intelliJ, the build.sbt file is showing lot of errors as shown in the following screenshot. Wondering what might be the issue
IDEA Version 13.1.4
I also see the following
The following source roots are outside of the corresponding base directories:
C:\Users\p0c\Downloads\recfun\src\main\resources
C:\Users\p0c\Downloads\recfun\src\test\java
C:\Users\p0c\Downloads\recfun\src\test\scala
C:\Users\p0c\Downloads\recfun\src\test\resources
These source roots cannot be included in the IDEA project model. Please consider using shared SBT projects instead of shared source roots.
I think the question perhaps does not provide all the required information to answer conclusively, but I'll give it a spin anyways -
Since sbt runs correctly when invoked from the shell, we know the sbt file is fine. I use Idea for my Scala and sbt projects and I am sure the Idea sbt support works very well, but! Idea is far more restrictive than sbt when it comes to project structure. It is really easy to create a valid sbt project structure that Idea can't support very well.
Given that the source roots error indicates that the recfun/src folder is not in the project folder, it seems clear that this error is not emitted during the processing of recfun/build.sbt. The screenshot shows you have at least three different sbt files, progfun-recfun, submission and scala-recfun. Since Idea will also create projects like submission-build, and you have an assignment-build project there, something is probably broken in the project structure, not from the sbt viewpoint - there you're fine, you can build - but from the Idea viewpoint, which is more restrictive.
My suggestion to resolve this would be to change your project structure as follows. First, have a top level project with a build.sbt. Then create a sub-project for each src folder you want. Do not put a src folder in your top level project. Each sub-project needs a build.sbt as well.
Second, make sure the sub-projects build correctly with sbt when run from the shell. Arrange the sub-project build.sbt files with the proper dependencies, using this syntax:
lazy val a = ProjectRef(file("../a"), "a")
lazy val b = ProjectRef(file("../b"), "b")
lazy val root = Project(id = "c", base = file(".")) dependsOn (a, b)
(This example has three sister projects a, b and c, where c depends on a and b. The three projects are placed in directories with the same name, within the root directory. The code snippet is from the build file for c.)
Third, arrange your top level build.sbt to aggregate the sub-projects, using this syntax in the top level build.sbt:
lazy val a = ProjectRef(file("a"), "a")
lazy val b = ProjectRef(file("b"), "b")
lazy val c = ProjectRef(file("c"), "c")
lazy val root = (project in file(".")).
aggregate(a, b, c)
Building this top level project will build each of the sub-projects a, b and c, and the dependencies established in the sub-project build files will ensure they are built in the right order.
Fourth, import the top level project into Idea, and all should be well.
You can get fancy with the file structure if you want, because the project references use relative paths, but it's usually nice to at least start simple.
I had a lot of frustration with sbt and Idea at the start, I hope this helps :)

Run "clean" all dependent SBT subprojects

I have an SBT project, specifically a Play Framework 2.1 project, that has a number of subprojects specified in the configuration. The dependencies seem to work fine when compiling, but "clean" only seems to clean the currently selected project, not including its dependencies. Is there any way to clean both the selected project and its dependent subprojects?
If your main project aggregates subjects, like this:
lazy val root = Project("name", file("."))
.aggregate(module1, module2, macros)
then any command called on this root project will be executed for all subprojects. If you call inspect clean command in your sbt session, you'll see, under Related section all subprojects which relates on this clean
On the side note in the comment
aggregate and dependsOn are different command for different purposes. The purpose of aggregation is in running commands called on the root project. In my example by calling test command on my root project, this command will be executed also for module1 module2 and macros. If you want to turn off such behaviour with the following setting:
aggregate in test := false
Aggregated project are independent on the code in them. It's usually used on the root project, nfor example not to call test on each project, but to call it on root. Remeber that in case of aggregation commands will be executed in parallel.
And dependsOn means that your project will depend on the code from other project. And in this case SBT will execute command sequentialy, in order to compile your root project, which dependsOn some modules, it should compile those modules at first step, the the root project.