Why does sbt create layers of projects and src in IDEA? - scala

I am new to SBT and trying to build a project. My Build.scala looks like
lazy val ec = project.in(file("."))
.settings(commonSettings: _*)
.settings(name := "ec")
.aggregate(ahka, currentLogProcessor, main)
lazy val currentLogProcessor = project.in(file("currentLogProcessor"))
.settings(commonSettings: _*)
.settings(name := "currentlogprocessor")
.settings(
libraryDependencies += "com.myorg.util" % "LP" % "0.18.0-SNAPSHOT" % "provided"
)
lazy val main = project
.settings(commonSettings: _*)
.settings(name := "main")
When SBT refreshes in IntelliJ, I see following
As you could see, even if the settings looks same for currentLogProcessor and main, the project structure is very very different.
project inside currentLogProcessor looks good but project under main is layer with project and src
What is the issue here? How can I remove the layers of project inside project?
Thanks

Your projects ec and main share the same folder. Remove main or ec, or change "in file" for one of them.
lazy val main = project in file("another_path") ...

The answer by #ka4eli is correct, but I'd like to point out few issues with the build definition that can make understanding it so much painful.
Defining top-level aggregate project
lazy val ec = project.in(file("."))
.settings(commonSettings: _*)
.settings(name := "ec")
.aggregate(ahka, currentLogProcessor, main)
You don't need it whatsoever as it's defined automatically anyway - you're just repeating what sbt does implicitly. Just remove it from the build and add build.sbt with the following:
commonSettings
Use build.sbt for a project's build definition
lazy val currentLogProcessor = project.in(file("currentLogProcessor"))
.settings(commonSettings: _*)
.settings(name := "currentlogprocessor")
.settings(
libraryDependencies += "com.myorg.util" % "LP" % "0.18.0-SNAPSHOT" % "provided"
)
By default, lazy val's name is used to call a project project macro should point to, i.e. no need for in(file("currentLogProcessor")). The same applies to the name setting - you're using all-lowercase name that may or may not be needed.
Use build.sbt under currentLogProcessor directory to have the same effect:
name := "currentlogprocessor"
commonSettings
libraryDependencies += "com.myorg.util" % "LP" % "0.18.0-SNAPSHOT" % "provided"
It's that simple.
Apply the rules to the main project.
Have fun with sbt = it's so simple that people hardly accept it and mess up build definitions on purpose to claim otherwise :)

Related

Can I create a proto jar for scalaVersion 2.11/2.12 and use it within the same sbt under different sub-project?

I have a set of .proto files (protobuf) which I generate java from using scalapb. I also have in the same sbt 2 sub-projects, one is scalaVersion 2.11 compatible (can't upgrade it to 2.12 due to missing packages) and the other one is scala 2.12.
I created a sub-project to hold my proto, and by default 2.12 is used and my 2.12 sub-project can use it, but my 2.11 can't.
I set the crossScalaVersions to 2.11/2.12, I compiled my project with both, which passed, but then even then I was unable to get the 2.11 sub-project to find that code.
I am "wondering" if that is something supported, or if there is a track I could use a single location to hold my .proto yet have my 2 sub-projects using the same sbt file use those.
lazy val scala212 = "2.12.13"
lazy val scala211 = "2.11.12"
lazy val supportedScalaVersion = List(scala212, scala211)
ThisBuild / scalaVersion := scala212
lazy val root = (project in file("."))
.aggregate(proto, subproject1, subproject2)
.settigns(
crossScalaVersions := Nil,
publish / skip := true
)
lazy val proto = project
.settings(
crossScalaVersions := supportedScalaVersions,
name := "proto",
libraryDependencies += "com.trueaccord.scalapb" %% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf",
PB.targets in Compile := Seq(
scalapb.gen(grpc = false) -> (sourceManaged in Compile).value / "protobuf"
)
)
lazy val subproject1 = project
.dependsOn(proto)
lazy val subproject2 = project
.settings(
scalaVersion := scala211
)
.dependsOn(proto)
So, from the above, if I do sbt "+ proto" I can compile both versions. If I do sbt subproject1/compile it works too. Using sbt subproject2/compile fails indicating that it cannot find the 2.11:proto jar file.
Either, I would like the above somehow to work nicely, or any other trick that I could generate the code from the same proto location but within subproject1/subproject2 would be appreciated.
You could try the sbt-projectmatrix plugin:
https://github.com/sbt/sbt-projectmatrix
The idea is to have separate sbt subprojects for the different Scala versions, so you can simply reference the relevant subproject when calling dependsOn.
I think this plugin is going to end up in sbt some day as it's a much better solution in general than the current built-in stateful cross compilation support, and it's developed by Eugene Yokota, who is also an sbt developer.

scala using github repo as a libraryDependencies

I was facing one error while trying using RootProject
I need to use gatling snapshot version which is 3.5.0-SNAPSHOT and to enable this I know two options:-
using git clone and then sbt publishLocal finally using this jar as an unmanaged dependency, This works fine but it is rather more manual work, So I moved to the second option.
Using sbt RootProject, so let me first explain the project setup:-
example/Build.sbt
lazy val gatling = RootProject(uri("https://github.com/gatling/gatling.git"))
lazy val root = (project in file("."))
.settings(
name := "example",
version := "0.1",
scalaVersion := "2.13.3"
).dependsOn(gatling)
example/project/plugins.sbt -> These two were added because it was required while building the project
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.21")
libraryDependencies += "org.scala-sbt" %% "io" % "1.4.0"
example/src/main/scala/Main.scala
import io.gatling.core.scenario.Simulation
object Main extends App {
class A extends Simulation
val a = new A
println(a.toString)
}
So after this executing sbt run will result in a successful build.
But the problem starts when I tried to import gatling-highcharts in a similar fashion as:-
lazy val gatling = RootProject(uri("https://github.com/gatling/gatling.git"))
lazy val gatlingHighCharts = RootProject(uri("https://github.com/gatling/gatling-highcharts.git"))
lazy val root: Project = (project in file("."))
.settings(
name := "example",
version := "0.1",
scalaVersion := "2.13.3"
).dependsOn(gatling, gatlingHighCharts)
now executing sbt will result in an error as:-
[error] not found: C:\Users\user\.ivy2\local\io.gatling\gatling-recorder\3.5.0-SNAPSHOT\ivys\ivy.xml
[error] not found: https://repo1.maven.org/maven2/io/gatling/gatling-recorder/3.5.0-SNAPSHOT/gatling-recorder-3.5.0-SNAPSHOT.pom
[error] not found: https://jcenter.bintray.com/io/gatling/gatling-recorder/3.5.0-SNAPSHOT/gatling-recorder-3.5.0-SNAPSHOT.pom
And this was because gatling is being used via dependsOn while actually there is nothing available to do like:-
lazy val gatlingHighCharts = RootProject(uri("https://github.com/gatling/gatling-highcharts.git")).dependsOn(gatling)
This is not possible as there is no method named dependsOn inside RootProject class and I am not able to figure out how to make that work.
Can anyone help me to figure out how can I make that work?
Plus, if somehow exist a way to use github repo jars directly as managed sources instead of unmanaged sources which is something like
libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % "3.5.0-SNAPSHOT"
without using dependsOn.

How to enable SbtWeb in not-play project?

I have a single-project build, implemented in Build.scala file with the following settings:
scala
lazy val root = Project(
id = ProjectInfo.name,
base = file("."),
settings = Project.defaultSettings
++ Revolver.settings
++ Revolver.enableDebugging(port = 5050)
++ Twirl.settings
++ // more tasks omitted
++ Seq(
mainClass in Compile := Some(launcherClassName),
mainClass in Revolver.reStart := Some(launcherClassName),
javaOptions in Revolver.reStart ++= List(
"-XX:PermSize=256M",
"-XX:MaxPermSize=512M",
"-Dlogback.debug=false",
"-Dlogback.configurationFile=src/main/resources/logback.xml"
),
resolvers ++= projectResolvers,
libraryDependencies ++= Dependencies.all,
parallelExecution in Test := false,
)
)
I would like to add sbt-web managed assets processing for the project, as I want to handle coffeescript, less and so on.
I added sbt-coffeescript plugin straight to plugins.sbt file in project folder and actually got it working. So now when I run web-assets:assets I have a coffeescript sample file in /src/main/coffeescript/foo.coffee and it gets compiled to target/web/coffeescript/main/coffeescript/foo.js.
Unfortunately, nothing gets processed when I simply run compile or run task. How do I enable processing of assets during compile in development workflow?
The issue you're having is that the old-style of specifying dependencies in projects does not work with AutoPlugins (which is what the WebPlugin is).
Specifically:
val foo = Project(
id = "ok"
base = file("ok")
settings = defaultSettings // BAD!
)
i.e. if you manually place settings on the Project, you're telling sbt "I Know EVERY setting I want on this project, and I want to completely override the defaults."
The load order of sbt settings is:
AutoPlugins (Core settings now come from AutoPlugins)
Settings defined in Project instances
Settings defined in build.sbt files in the base directory of a project.
The above code is re-applying ALL of the sbt default settings from 0.13.x series, which will overwrite anything that the AutoPlugins previously enabled. This is by design, as any other mechanism wouldn't be "correct".
If you're migrating to using AutoPlugins, simply modify your build to be:
lazy val root = Project(
id = ProjectInfo.name,
base = file("."))
settings =
// NOTICE we dropped the defaultSettings
Revolver.settings
++ Revolver.enableDebugging(port = 5050)
++ Twirl.settings
++ // more tasks omitted
++ Seq(
mainClass in Compile := Some(launcherClassName),
mainClass in Revolver.reStart := Some(launcherClassName),
javaOptions in Revolver.reStart ++= List(
"-XX:PermSize=256M",
"-XX:MaxPermSize=512M",
"-Dlogback.debug=false",
"-Dlogback.configurationFile=src/main/resources/logback.xml"
),
resolvers ++= projectResolvers,
libraryDependencies ++= Dependencies.all,
parallelExecution in Test := false,
)
)
To run assets generation on compilation I did this:
settings = ... ++ Seq(
pipelineStages := Seq(rjs),
(compile in Compile) <<= compile in Compile dependsOn (stage in Assets),
// ...
)
Than when I run compile, stage command is also executed, thus running sbt-web's pipeline.
The question for me is how to make generated assets to become available as part of managed resources (I'm trying to get sbt-web working with xsbt-web-plugin and liftweb)

How to avoid adding a 'root' scala sbt project in IntelliJ when defining github dependencies?

I'm using IntelliJ with SBT plugin and I've added the following lines to build.sbt in order to add a dependency to a private github repository:
lazy val g = RootProject(uri("ssh://git#github.com/XXXX/myrepo.git"))
lazy val root = project in file("myproject") dependsOn g
After running sbt, my referenced project is successfully cloned, but build fails due to output path clashes between my base project and a root project that is automatically added each time I refresh sbt after modifying build.sbt.
I was having this same issue awhile back.
I'm not sure what causes it but I know that if you use the multi-project setup for sbt (root/project/build.scala) instead of the simple one (root/build.sbt) Intellij respects your settings.
Try the multi-project setup like this and see if it solves your problem:
import sbt.Keys._
import sbt._
lazy val g = RootProject(uri("ssh://git#github.com/XXXX/myrepo.git"))
object MyProjectBuild extends Build {
lazy val project = Project("myproject", file(".")) // <-- Make sure to name your project what you want the module to be named
.settings(
name := "myproject", // <-- Same here
version := "1.0",
scalaVersion := "2.11.4",
libraryDependencies ++=Seq(
"org.scalatest" % "scalatest_2.11" % "2.2.0" % "test",
)
).dependsOn(g)
}

How to prepend setting in sbt

How do I prepend to an SBT setting?
++= appends. What prepends?
(Background: I want to put different resolvers before Typesafe for my Play project.)
You could set the value to be the given resolver + the old ones, that way the old values all go the back of the search queue.
For build.sbt:
resolvers := ("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") +: resolvers.value
For Build.scala try something like:
lazy val root = Project("myproject", file("."))
.settings(otherSettings: _*)
.settings(resolvers := ("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") +: resolvers.value)