I am writing few sbt tasks in a scala file. These SBT tasks will be imported into many other projects.
lazy val root = (project in file(".")).
settings(
inThisBuild(List(
organization := "com.example",
scalaVersion := "2.11.8",
version := "1.0.0"
)),
name := "sbttasks",
libraryDependencies ++= Seq(
"org.scala-sbt" % "sbt" % "1.0.0" % "provided"
)
)
I get a compilation error
error] java.lang.RuntimeException: Conflicting cross-version suffixes in: org.scala-lang.modules:scala-xml, org.scala-lang.modules:scala-parser-combinators
[error] at scala.sys.package$.error(package.scala:27)
[error] at sbt.librarymanagement.ConflictWarning$.processCrossVersioned(ConflictWarning.scala:39)
[error] at sbt.librarymanagement.ConflictWarning$.apply(ConflictWarning.scala:19)
[error] at sbt.Classpaths$.$anonfun$ivyBaseSettings$64(Defaults.scala:1995)
[error] at scala.Function1.$anonfun$compose$1(Function1.scala:44)
[error] at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:39)
[error] at sbt.std.Transform$$anon$4.work(System.scala:66)
[error] at sbt.Execute.$anonfun$submit$2(Execute.scala:262)
[error] at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error] at sbt.Execute.work(Execute.scala:271)
[error] at sbt.Execute.$anonfun$submit$1(Execute.scala:262)
[error] at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:174)
[error] at sbt.Completion
I don't want to write the custom tasks in build.sbt itself (as the SBT documentation shows) because then I won't be able to import my custom tasks into other projects.
To write reusable tasks that you can "import" in different projects, you need to make an sbt plugin.
If you have a multi-project build and want to reuse your tasks in the subprojects, you can create a file project/MyPlugin.scala with
import sbt._
import sbt.Keys._
object MyPlugin extends AutoPlugin {
override def trigger = noTrigger
object autoImport {
val fooTask = taskKey[Foo]("Foo description")
val barTask = taskKey[Bar]("Bar description")
}
import autoImport._
override lazy val projectSettings = Seq(
fooTask := { ??? },
barTask := { ??? }
)
}
Then to enable this plugin (i.e. make those tasks available) in a subproject, you can write this in your build.sbt:
lazy val subproject = (project in file("subproject"))
.enablePlugins(MyPlugin)
On the contrast, if you want to reuse these tasks in other unrelated projects, you need to make this plugin a separate project and publish it. It's a normal sbt project, but instead of an explicit sbt dependency, you write in its build.sbt:
sbtPlugin := true
And the code defining tasks goes to src/main/scala/ (like in a normal project).
You can read in detail about writing plugins in the sbt documentation.
Change version of "org.scala-sbt" to "1.0.0-M4"
lazy val root = (project in file(".")).
settings(
inThisBuild(List(
organization := "com.example",
scalaVersion := "2.11.8",
version := "1.0.0",
name := "sbttasks"
)),
libraryDependencies ++= Seq(
"org.scala-sbt" % "sbt" % "1.0.0-M4" % "provided"
)
)
For entire compatibility matrix check
https://mvnrepository.com/artifact/org.scala-sbt/main
Related
I have a small project.
Where I have the following problem:
scalaTest needs to be added to all three dependency project (client, server, shared), otherwise the scalatest library is not accessible from all projects.
In other words, if I write
val jvmDependencies = Def.setting(Seq(
"org.scalaz" %% "scalaz-core" % "7.2.8"
)++scalaTest)
then things work fine.
But if I don't write ++scalaTest into each three dependencies then it fails like this:
> test
[info] Compiling 1 Scala source to /Users/joco/tmp3/server/target/scala-2.11/test-classes...
[error] /Users/joco/tmp3/server/src/test/scala/Test.scala:1: object specs2 is not a member of package org
[error] import org.specs2.mutable.Specification
[error] ^
[error] /Users/joco/tmp3/server/src/test/scala/Test.scala:3: not found: type Specification
[error] class Test extends Specification {
[error] ^
[error] /Users/joco/tmp3/server/src/test/scala/Test.scala:5: value should is not a member of String
[error] "Test" should {
[error] ^
[error] /Users/joco/tmp3/server/src/test/scala/Test.scala:6: value in is not a member of String
[error] "one is one" in {
[error] ^
[error] /Users/joco/tmp3/server/src/test/scala/Test.scala:8: value === is not a member of Int
[error] 1===one
[error] ^
[error] 5 errors found
[error] (server/test:compileIncremental) Compilation failed
[error] Total time: 4 s, completed Mar 18, 2017 1:56:54 PM
However for production(not test) code everything works just fine: I don't have to add 3 times the same dependencies (in this example autowire) to all three projects if I want to use a library in all three projects, it is enough to add it to only the shared project and then I can use that library from all three projects.
For test code, however, as I mentioned above, currently I have to add the same library dependency (scalaTest - below) to all three projects.
Question: Is there a way to avoid this ?
Settings.scala:
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
import sbt.Keys._
import sbt._
object Settings {
val scalacOptions = Seq(
"-Xlint",
"-unchecked",
"-deprecation",
"-feature",
"-Yrangepos"
)
object versions {
val scala = "2.11.8"
}
val scalaTest=Seq(
"org.scalatest" %% "scalatest" % "3.0.1" % "test",
"org.specs2" %% "specs2" % "3.7" % "test")
val sharedDependencies = Def.setting(Seq(
"com.lihaoyi" %%% "autowire" % "0.2.6"
)++scalaTest)
val jvmDependencies = Def.setting(Seq(
"org.scalaz" %% "scalaz-core" % "7.2.8"
))
/** Dependencies only used by the JS project (note the use of %%% instead of %%) */
val scalajsDependencies = Def.setting(Seq(
"org.scala-js" %%% "scalajs-dom" % "0.9.1"
)++scalaTest)
}
build.sbt:
import sbt.Keys._
import sbt.Project.projectToRef
import webscalajs.SourceMappings
lazy val shared = (crossProject.crossType(CrossType.Pure) in file("shared")) .settings(
scalaVersion := Settings.versions.scala,
libraryDependencies ++= Settings.sharedDependencies.value,
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
) .jsConfigure(_ enablePlugins ScalaJSWeb)
lazy val sharedJVM = shared.jvm.settings(name := "sharedJVM")
lazy val sharedJS = shared.js.settings(name := "sharedJS")
lazy val elideOptions = settingKey[Seq[String]]("Set limit for elidable functions")
lazy val client: Project = (project in file("client"))
.settings(
scalaVersion := Settings.versions.scala,
scalacOptions ++= Settings.scalacOptions,
libraryDependencies ++= Settings.scalajsDependencies.value,
testFrameworks += new TestFramework("utest.runner.Framework")
)
.enablePlugins(ScalaJSPlugin)
.disablePlugins(RevolverPlugin)
.dependsOn(sharedJS)
lazy val clients = Seq(client)
lazy val server = (project in file("server")) .settings(
scalaVersion := Settings.versions.scala,
scalacOptions ++= Settings.scalacOptions,
libraryDependencies ++= Settings.jvmDependencies.value
)
.enablePlugins(SbtLess,SbtWeb)
.aggregate(clients.map(projectToRef): _*)
.dependsOn(sharedJVM)
onLoad in Global := (Command.process("project server", _: State)) compose (onLoad in Global).value
fork in run := true
cancelable in Global := true
For test code, however, as I mentioned above, currently I have to add the same library dependency (scalaTest - below) to all three projects.
That is expected. test dependencies are not inherited along dependency chains. That makes sense, because you don't want to depend on JUnit just because you depend on a library that happens to be tested using JUnit.
Although yes, that calls for a bit of duplication when you have several projects in the same build, all using the same testing framework. This is why we often find some commonSettings that are added to all projects of an sbt build. This is also where we typically put things like organization, scalaVersion, and many other settings that usually apply to all projects inside one build.
I'm trying to workaround creating sbt AutoPlugins.
I want to create plugin which will autoloading all his dependencies, so I use NoTrigger policy.
I wrote my own AutoPlugin which must execute assembly task from sbt-assembly and look like:
settings in /build.sbt
name := "sbt-myplugin"
version := "0.0.1"
organization := "com.org"
scalaVersion := "2.10.6"
sbtPlugin := true
sbtVersion := "0.13.11"
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")
plugin code in /src/main/scala/myplugin/MyPlugin.scala
package myplugin
import sbt._
import sbtassembly.AssemblyPlugin
import sbtassembly.AssemblyPlugin.autoImport._
object MyPlugin extends AutoPlugin{
override def trigger = noTrigger
override def requires = AssemblyPlugin
object autoImport {
val myAssembly = taskKey[File]("Assembled file")
}
import autoImport._
override lazy val projectSettings = Seq(
myAssembly := assembly.value
)
}
Then i'm create artifact with sbt clean compile publishLocal
After this I created test project which will use my plugin.
settings for this project in /project/plugins.sbt
logLevel := Level.Warn
resolvers += "Local Ivy Repository" at "file://"+Path.userHome.absolutePath+"/.ivy2/local"
addSbtPlugin("com.academmedia.ias" % "sbt-pkplace" % "0.0.1")
settings in /biuld.sbt
name := "test-project"
version := "1.0"
scalaVersion := "2.11.8"
lazy val root = (project in file(".")).enablePlugins(myplugin.MyPlugin)
Now I'm expecting able to use MyPlugin task myAssembly but my project sbt is unable to download project settings with error:
[error] java.lang.NoClassDefFoundError: sbtassembly/AssemblyPlugin$
What am I doing wrong?
Thanks for answer!
I am upgrading from Play 2.1.3 to Play 2.5.4. I resolved multiple issues but I am now stuck at one last step I guess:
My project/Build.scala:
import sbt._
import Keys._
import play.sbt._
import Play.autoImport._
import PlayKeys._
object ApplicationBuild extends Build {
val appName = "dashboard"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
// Add your project dependencies here,
javaCore,
javaJdbc,
javaEbean
)
val main = play.Project(appName, appVersion, appDependencies).settings(
// Add your own project settings here
)
}
When I do activator run on my project, I get the following error:
[error] \project\Build.scala:19: object Project is not a member of package play
[error] val main = play.Project(appName, appVersion, apDependencies).settings(
[error] ^
[error] one error found
[debug] Compilation failed (CompilerInterface)
[error] (compile:compileIncremental) Compilation failed
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
Can someone please help?
play.Project was replaced by native sbt Project support at version 2.3:. From this version migration docs:
If you were previously using play.Project, for example a Scala project:
object ApplicationBuild extends Build {
val appName = "myproject"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq()
val main = play.Project(appName, appVersion, appDependencies).settings(
)
}
...then you can continue to use a similar approach via native sbt:
object ApplicationBuild extends Build {
val appName = "myproject"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq()
val main = Project(appName, file(".")).enablePlugins(play.PlayScala).settings(
version := appVersion,
libraryDependencies ++= appDependencies
)
}
But, since you are migrating from a very old version (Play 2.1 last release was in Sep 2013), I truly recommend you to use build.sbt instead of project/Build.scala. The migration would be something like:
name := """dashboard"""
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayJava)
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
javaJdbc,
cache,
javaWs
)
And, instead of adding javaEbean, you will need to use play-ebean instead. To do so, just add the following line to your project/plugins.sbt file (this was changed at Play 2.4 and you have to use the updated version as documented for Play 2.5):
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")
After that, change your root project definition to something like this:
lazy val myProject = (project in file(".")).enablePlugins(PlayJava, PlayEbean)
This will automatically add Ebean dependencies. Finally, I can't recommend enough that you read all the migration guides for version between 2.1 and 2.5.
I am writing a project which contains scala macros. This is why I have organized my project into two sub projects called "macroProj" and "coreProj". The "coreProj" depends on "macroProj" and also contains the main method to run my code.
My requirement is that when I do a sbt run from the root project, the main method is taken from the coreProj sub project. I search and found a thread which has a solution for this
sbt: run task on subproject
Based on this my build.sbt looks like
lazy val root = project.aggregate(coreProj,macroProj).dependsOn(coreProj,macroProj)
lazy val commonSettings = Seq(
scalaVersion := "2.11.7",
organization := "com.abhi"
)
lazy val coreProj = (project in file("core"))
.dependsOn(macroProj)
.settings(commonSettings : _*)
.settings(
mainClass in Compile := Some("demo.Usage")
)
lazy val macroProj = (project in file("macro"))
.settings(commonSettings : _*)
.settings(libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value)
mainClass in Compile <<= (run in Compile in coreProj)
But when I do sbt run from the root directory. I get an error
/Users/abhishek.srivastava/MyProjects/sbt-macro/built.sbt:19: error: type mismatch;
found : sbt.InputKey[Unit]
required: sbt.Def.Initialize[sbt.Task[Option[String]]]
mainClass in Compile <<= (run in Compile in coreProj)
^
[error] Type error in expression
In sbt, mainClass is a task that will return an entry point to your program, if any.
What you want to do is to have mainClass be the value of mainClass in coreProj.
You can achieve that this way:
mainClass in Compile := (mainClass in Compile in coreProj).value
This could also be achieved with
mainClass in Compile <<= mainClass in Compile in coreProj
However, the preferred syntax is (...).value since sbt 0.13.0.
Can someone give me a minimal working sbt setup for sbt-scalabuff? The information that's out there seems incomplete. I'm currently trying to use addSbtPlugin("com.github.sbt" % "sbt-scalabuff" % "0.2"), but I get sbt.ResolveException: unresolved dependency: net.sandrogrzicic#scalabuff-runtime_2.9.2;1.3.6: not found. I guess I'm missing a repository.
Why is it using 2.9.2, though? I have scalaVersion := 2.10.3.
build.sbt
organization := "com.confabulous"
name := "protobuf"
version := "0.0.1-SNAPSHOT"
scalaVersion := "2.10.4"
scalacOptions += "-deprecation"
resolvers ++= Seq(
"sonatype releases" at "https://oss.sonatype.org/content/repositories/releas
"sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapsh
"typesafe repo" at "http://repo.typesafe.com/typesafe/releases/"
)
libraryDependencies += "net.sandrogrzicic" %% "scalabuff-runtime" % "1.3.6"
plugins/plugins.sbt
addSbtPlugin("com.github.sbt" % "sbt-scalabuff" % "0.2")
project/Build.scala
import sbt._
import scalabuff.ScalaBuffPlugin._
object build extends Build {
lazy val root = Project("main", file("."), settings = Defaults.defaultSetting
}
Output
$ sbt compile
Loading /usr/share/sbt/bin/sbt-launch-lib.bash
[info] Loading project definition from /home/dan/projects/confabulous/protobuf/project
[info] Updating {file:/home/dan/projects/confabulous/protobuf/project/}default-6a3ff1...
[info] Resolving org.scala-sbt#precompiled-2_10_1;0.12.4 ...
[info] Done updating.
[info] Set current project to protobuf (in build file:/home/dan/projects/confabulous/protobuf/)
[info] Compiling 1 Scala source to /home/dan/projects/confabulous/protobuf/target/scala-2.10/classes...
[error] /home/dan/projects/confabulous/protobuf/target/scala-2.10/src_managed/scala/com/confabulous/protobuf/ConfabulousProtobuf.scala:11: not found: value net
[error] with net.sandrogrzicic.scalabuff.Message[Pair] {
[error] ^
[error] /home/dan/projects/confabulous/protobuf/target/scala-2.10/src_managed/scala/com/confabulous/protobuf/ConfabulousProtobuf.scala:76: not found: value net
[error] with net.sandrogrzicic.scalabuff.Message[Notice] {
[error] ^
Add https://dl.bintray.com/actor/maven to your SBT resolver
resolvers ++= Seq("sonatype releases" at "https://oss.sonatype.org/content/repositories/releas
"sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapsh
"typesafe repo" at "http://repo.typesafe.com/typesafe/releases/"
"bintrayRepo" at "https://dl.bintray.com/actor/maven"
)