Using sbt 0.13.5, when opening the project in IntelliJ, there is a warning message
~\myproject\project\Build.scala:5: trait Build in package sbt is
deprecated: Use .sbt format instead
The content of the Build.scala is
import sbt._
object MyBuild extends Build {
lazy val root = Project("MyProject", file("."))
.configs(Configs.all: _*)
.settings(Testing.settings ++ Docs.settings: _*)
}
The Appendix: .scala build definition and the sbt documentation is rather overwhelming.
How to merge my existing Build.scala to build.sbt? Would appreciate any direction to doc/tutorial/examples.
Rename Build.scala to build.sbt and move it up one directory level, so it's at the top rather than inside the project directory.
Then strip out the beginning and end, leaving:
lazy val root = Project("MyProject", file("."))
.configs(Configs.all: _*)
.settings(Testing.settings ++ Docs.settings: _*)
That's the basics.
Then if you want to add more settings, for example:
lazy val root = Project("MyProject", file("."))
.configs(Configs.all: _*)
.settings(
Testing.settings,
Docs.settings,
name := "MyApp",
scalaVersion := "2.11.8"
)
You don't need the :_* thing on sequences of settings anymore in sbt 0.13.13; older versions required it.
The migration guide in the official doc is here: http://www.scala-sbt.org/0.13/docs/Migrating-from-sbt-012x.html#Migrating+from+the+Build+trait
Related
I have an sbt project with multiple modules, each with their own build.sbt file.
In the root project, I have the following:
lazy val commonSettings = Seq(
organization := "com.game.scala",
sourcesInBase := false,
fork in run := true,
scalaVersion := "2.12.1"
)
lazy val common = project.settings(commonSettings)
lazy val original = project.settings(commonSettings).dependsOn(common)
lazy val functional = project.settings(commonSettings).dependsOn(common)
lazy val root = (project in file("."))
.aggregate(original, functional)
.settings(commonSettings)
The build.sbt in all the submodules are pretty much the same:
lazy val module = (project in file("."))
.settings(
name := "Game subpart",
version := "0.1.0-SNAPSHOT"
)
And the layout of the project looks something like:
root
|__ common
|__ original
|__ functional
The problem is that from within the functional module, if I try importing a trait declared in common module, I get an error that it is not available:
Error:(1, 12) object game is not a member of package com
import com.game.scala
What am I missing?
This is because you never compiled your common project. The dependsOn method only add a dependency to the other project, but do no action on it, unless explicitly asked to. If you want your dependency to be re-compiled whenever the functional module is compiled, you should do both dependsOn(common) and aggregate(common).
I'm developing a library that includes an sbt plugin. Naturally, I'm using sbt to build this (multi-project) library. My (simplified) project looks as follows:
myProject/ # Top level of library
-> models # One project in the multi-project sbt build.
-> src/main/scala/... # Defines common models for both sbt-plugin and framework
-> sbt-plugin # The sbt plugin build
-> src/main/scala/...
-> framework # The framework. Ideally, the sbt plugin is run as part of
-> src/main/scala/... # compiling this directory.
-> project/ # Multi-project build configuration
Is there a way to have the sbt-plugin defined in myProject/sbt-plugin be hooked into the build for myProject/framework all in a unified build?
Note: similar (but simpler) question: How to develop sbt plugin in multi-project build with projects that use it?
Is there a way to have the sbt-plugin defined in myProject/sbt-plugin be hooked into the build for myProject/framework all in a unified build?
I have a working example on Github eed3si9n/plugin-bootstrap. It's not super pretty, but it kind of works. We can take advantage of the fact that sbt is recursive.
The project directory is another build inside your build, which knows how to build your build. To distinguish the builds, we sometimes use the term proper build to refer to your build, and meta-build to refer to the build in project. The projects inside the metabuild can do anything any other project can do. Your build definition is an sbt project.
By extension, we can think of the sbt plugins to be library- or inter-project dependencies to the root project of your metabuild.
meta build definition (project/plugins.sbt)
In this example, think of the metabuild as a parallel universe or shadow world that has parallel multi-build structure as the proper build (root, model, sbt-plugin).
To reuse the source code from model and sbt-plugin subprojects in the proper build, we can re-create the multi-project build in the metabuild. This way we don't need to get into the circular dependency.
addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.5")
lazy val metaroot = (project in file(".")).
dependsOn(metaSbtSomething)
lazy val metaModel = (project in file("model")).
settings(
sbtPlugin := true,
scalaVersion := "2.10.6",
unmanagedSourceDirectories in Compile :=
mirrorScalaSource((baseDirectory in ThisBuild).value.getParentFile / "model")
)
lazy val metaSbtSomething = (project in file("sbt-plugin")).
dependsOn(metaModel).
settings(
sbtPlugin := true,
scalaVersion := "2.10.6",
unmanagedSourceDirectories in Compile :=
mirrorScalaSource((baseDirectory in ThisBuild).value.getParentFile / "sbt-plugin")
)
def mirrorScalaSource(baseDirectory: File): Seq[File] = {
val scalaSourceDir = baseDirectory / "src" / "main" / "scala"
if (scalaSourceDir.exists) scalaSourceDir :: Nil
else sys.error(s"Missing source directory: $scalaSourceDir")
}
When sbt loads up, it will build metaModel and metaSbtSomething first, and use metaSbtSomething as a plugin to your proper build.
If you have any other plugins you need you can just add it to project/plugins.sbt normally as I've added sbt-doge.
proper build (build.sbt)
The proper build looks like a normal multi-project build.
As you can see framework subproject uses SomethingPlugin. Important thing is that they share the source code, but the target directory is completely separated, so there are no interference once the proper build is loaded, and you are changing code around.
import Dependencies._
lazy val root = (project in file(".")).
aggregate(model, framework, sbtSomething).
settings(inThisBuild(List(
scalaVersion := scala210,
organization := "com.example"
)),
name := "Something Root"
)
// Defines common models for both sbt-plugin and framework
lazy val model = (project in file("model")).
settings(
name := "Something Model",
crossScalaVersions := Seq(scala211, scala210)
)
// The framework. Ideally, the sbt plugin is run as part of building this.
lazy val framework = (project in file("framework")).
enablePlugins(SomethingPlugin).
dependsOn(model).
settings(
name := "Something Framework",
crossScalaVersions := Seq(scala211, scala210),
// using sbt-something
somethingX := "a"
)
lazy val sbtSomething = (project in file("sbt-plugin")).
dependsOn(model).
settings(
sbtPlugin := true,
name := "sbt-something",
crossScalaVersions := Seq(scala210)
)
demo
In the SomethingPlugin example, I'm defining something task that uses foo.Model.x.
package foo
import sbt._
object SomethingPlugin extends AutoPlugin {
def requries = sbt.plugins.JvmPlugin
object autoImport {
lazy val something = taskKey[Unit]("")
lazy val somethingX = settingKey[String]("")
}
import autoImport._
override def projectSettings = Seq(
something := { println(s"something! ${Model.x}") }
)
}
Here's how we can invoke something task from the build:
Something Root> framework/something
something! 1
[success] Total time: 0 s, completed May 29, 2016 3:01:07 PM
1 comes from foo.Model.x, so this demonstrates that we are using the sbt-something plugin in framework subproject, and that the plugin is using metaModel.
I'm having some difficulties understanding the syntax for scalapb, specifically I'm trying to add multiple .proto source directories for a multi-project SBT build.
My project structure is as follows:
/build.sbt
/main/src/protobuf
/common/main/src/protobuf
/client/main/src/protobuf
My build.sbt is as follows:
name := "myApp"
import Dependencies._
import com.trueaccord.scalapb.{ScalaPbPlugin => PB}
val protoDirectories = Seq(
file("common/src/main/protobuf"),
file("client/src/main/protobuf")
)
sourceDirectories in PB.protobufConfig ++= protoDirectories
PB.protobufSettings ++ Seq(
flatPackage := false
)
lazy val common = (project in file("common")).
settings(Commons.settings: _*).
settings(libraryDependencies ++= commonDependencies)
lazy val client = (project in file("client")).
settings(Commons.settings: _*).
settings(libraryDependencies ++= clientDependencies).
dependsOn(common)
When I run sbt compile, I get the following error message:
[error] Reference to undefined setting:
[error]
[error] sphere/*:sourceDirectories from myApp/*:sourceDirectories (<path_to_project_dir>\build.sbt:11)
[error] Did you mean myApp/protobuf:sourceDirectories ?
Could someone please point me in the right direction? I'm failing to understand some basic concept here...
EDIT
Ok, so I was pointing to the wrong sequence for the protoDirectories. I have amended the build.sbt to reflect the new changes. I still have a problem that my .proto files are not compiled in the sub projects. If I move my .proto files to the root /main/src/protobuf, they compile just fine.
You need to enable the ScalaPB plugin for both projects separately if both contain files in src/main/protobuf. This example also shows how to set the import search path. A full example is at https://github.com/thesamet/scalapb-test/tree/multiproject
import com.trueaccord.scalapb.{ScalaPbPlugin => PB}
version in PB.protobufConfig := "3.0.0-beta-2"
lazy val common = (project in file("common")).
settings(PB.protobufSettings)
lazy val client = (project in file("client")).
settings(PB.protobufSettings ++ Seq(
// If you want proto files in client to import proto files in common.
PB.includePaths in PB.protobufConfig += file("common/src/main/protobuf")
)).
dependsOn(common)
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 :)
In an SBT Plugin, I'm trying to access to managed resources of subprojects.
Here is the build file:
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "demo"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
"org.jruby" % "jruby-complete" % "1.7.1"
)
val widgets = play.Project("widgets", appVersion, appDependencies, path = file("widgets"))
val main = play.Project(appName, appVersion, appDependencies, path = file("demo"))
.dependsOn(widgets)
}
I'm working in an SBT plugin defined in plugins.sbt.
Now, I need to use resources files from the subproject (widgets) during compilation of the parent project (demo).
So far the closest I've got to is the buildDependencies settings key - but I'm only getting ProjectRef objects, and the only information is the build base and the project id. I couldn't find a way to get to that project's resources directory.
I'm not familiar with writing plugins, but at least in your build.sbt you can define the resource file.
Or, again in the build.sbt you can create a "common" project that others reference, like:
lazy val common = (project in file("common"))
.settings(
Seq(
includeFilter in unmanagedResources := new SimpleFileFilter(_.getCanonicalPath.startsWith((sourceDirectory.value / "main" / "resources").getCanonicalPath))
)
)
Then other code (e.g. a Task) could reference this like:
lazy val doSomething = taskKey[Seq[File]]("Does something useful")
lazy val doSomethingSetting = doIt := {
val resourceDir = (resourceDirectory in common in Compile).value
println(resourceDir)
}
So your other projects could run this or reference that directory
Hopefully there's a straight forward way to implement one of those solutions for a plugin vs a build?
Unfortunately I do not believe this is possible. I was trying something similar but found the following in the documentation:
Note: At runtime, all plugins for all builds are loaded in a separate, parent class loader of the class loaders for builds. This means that plugins will not see classes or resources from build definitions
See: SBT Plugins