Scala sbt AutoPlugin with dependencies. Error while enablePlugins in another project - scala

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!

Related

How can I access sub-projects of an sbt-plugin by using it as dependency in a multi-project build?

I have an sbt plugin project that uses multi-project build. I would like to use this plugin as a dependency for the other sbt project and access sub-project of this sbt plugin. I have created a plugin and I added plugin to an sbt project, but i am not able to access sub-project of plugin there.
sbt-plugin
build.sbt
name := "sbt-plugin"
sbtPlugin := true
val commonSettings = Seq(
organization := "com.example",
version := "1.0",
scalaVersion := "2.11.7",
javacOptions := Seq("-source", "1.8", "-target", "1.8"),
scalacOptions := Seq("-target:jvm-1.8", "-unchecked","-deprecation", "-encoding", "utf8")
)
lazy val root = (project in file("."))
.settings(commonSettings: _*)
.dependsOn(plugin)
.aggregate(plugin)
lazy val plugin = (project in file("plugin"))
.settings(commonSettings: _*)
.settings(
name := "plugin" ,
mainClass in (Compile, run) := Some("com.example.Main")
)
sbt-plugin\plugin\src\main\scala\com\example\Main.scala
package com.example
object Main {
def main(args: Array[String]){
println("Hello from plugin in sbt-plugin");
}
}
sbt-plugin\plugin\src\main\scala\com\example\Hello.scala
package com.example
// Sample code I would like to access from another sbt project
object Hello {
def show = println("Hello, world!")
}
plugin-test
plugin-test is an sbt project which i used to test sbt-plugin
plugin-test\build.sbt
name := """plugin-test"""
val commonSettings = Seq(
version := "1.0",
scalaVersion := "2.11.7",
javacOptions := Seq("-source", "1.8", "-target", "1.8"),
scalacOptions := Seq("-target:jvm-1.8", "-unchecked", "-deprecation", "-encoding", "utf8"),
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test"
)
lazy val root = (project in file("."))
.settings(commonSettings: _*)
.dependsOn(pluginpro)
.aggregate(pluginpro)
.settings(
mainClass in (Compile, run) := Some("com.exam.Test")
)
lazy val pluginpro = (project in file("pluginpro"))
.settings(commonSettings: _*)
.settings(
libraryDependencies += "com.example" % "plugin_2.11" % "1.0"
)
plugin-test\src\main\scala\com\exam\Test.scala
package com.exam
object Test {
def result = com.example.Hello.show()
}
when i run plugin-test project from root it is running but with below mentioned log and i am not sure why is it showing this because according to me output would be only Hello, world!
background log: info: Running com.exam.Test
background log: debug: Waiting for threads to exit or System.exit to be called.
background log: debug: Waiting for thread run-main-0 to terminate.
background log: debug: Classpath:
E:\Play\SBT Plugin\sbt demo1\plugin-test\target\scala-2.11\classes
E:\Play\SBT Plugin\sbt demo1\plugin-test\pluginpro\target\scala-2.11\classes
C:\Users\Jeetu\.ivy2\cache\org.scala-lang\scala-library\jars\scala-library-2.11.7.jar
C:\Users\Jeetu\.ivy2\local\com.example\plugin_2.11\1.0\jars\plugin_2.11.jar
Hello, world!
()
background log: debug: Thread run-main-0 exited.
background log: debug: Interrupting remaining threads (should be all daemons).
background log: debug: Sandboxed run complete..
background log: debug: Exited with code 0
When i try to run sub-project of sbt-plugin via pluginpro/run, it can't find main class.
> pluginpro/run
[trace] Stack trace suppressed: run last pluginpro/compile:backgroundRun for the full output.
[error] (pluginpro/compile:backgroundRun) No main class detected.
i have created main class in sbt-plugin/plugin project.
I performed publish-local and plugin/publish-local on both projects and the artifacts resolved correctly.
What am I missing here?
I resolved it by adding following in build.sbt in pluginpro project:
mainClass in (Compile, run) := Some("com.example.Main")

SBT: How to define dependencies of subprojects in subprojects' build.sbt files?

The following build.sbt file works, but it defines the dependencies of all subprojects:
name := "myproject"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
"org.scalafx" %% "scalafx" % "8.0.60-R9"
)
lazy val aLib = (project in file("lib/a"))
lazy val bLib = (project in file("lib/b"))
.dependsOn(aLib)
.dependsOn(cLib)
lazy val cLib = (project in file("lib/c"))
.dependsOn(aLib)
lazy val myApp = (project in file("myapp"))
.dependsOn(aLib)
.dependsOn(bLib)
.dependsOn(cLib)
.aggregate(aLib, bLib, cLib)
Since each subproject (directories lib/a, lib/b, lib/c, myapp) has its own build.sbt file, I would like to use those build files to define the individual dependencies of each project.
I tried to move the dependsOn/aggregate statements to the subprojects' build files, but I am not able to make it work that way. What is the recommended way?

Adding module dependency information in sbt's build.sbt file

I have a multi module project in IntelliJ, as in this screen capture shows, contexProcessor module depends on contextSummary module.
IntelliJ takes care of everything once I setup the dependencies in Project Structure.
However, when I run sbt test with the following setup in build.sbt, I got an error complaining that it can't find the packages in contextSummary module.
name := "contextProcessor"
version := "1.0"
scalaVersion := "2.11.7"
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.2" % "test"
How to teach sbt that the missing modules are found?
I could use the build.sbt file in the main root directory.
lazy val root = (project in file(".")).aggregate(contextSummary, contextProcessor)
lazy val contextSummary = project
lazy val contextProcessor = project.dependsOn(contextSummary)
Reference: http://www.scala-sbt.org/0.13.5/docs/Getting-Started/Multi-Project.html
For testing only one project, I can use project command in sbt.
> sbt
[info] Set current project to root (in build file:/Users/smcho/Desktop/code/ContextSharingSimulation/)
> project contextProcessor
[info] Set current project to contextProcessor (in build file:/Users/smcho/Desktop/code/ContextSharingSimulation/)
> test
For batch mode as in How to pass command line args to program in SBT 0.13.1?
sbt "project contextProcessor" test
I think a simple build.sbt might not be enough for that.
You would need to create a more sophisticated project/Build.scala like that:
import sbt._
import sbt.Keys._
object Build extends Build {
lazy val root = Project(
id = "root",
base = file("."),
aggregate = Seq(module1, module2)
)
lazy val module1 = Project(
id = "module1",
base = file("module1-folder"),
settings = Seq(
name := "Module 1",
version := "1.0",
scalaVersion := "2.11.7",
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.2" % "test"
lazy val module2 = Project(
id = "module2",
base = file("module2-folder"),
dependencies = Seq(module1),
settings = Seq(
name := "Module 2",
version := "1.0",
scalaVersion := "2.11.7",
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.2" % "test"
}

How to write a plugin which depends on a task from another plugin?

There is a great sbt plugin sbt-dependency-graph, which provides a dependencyTree task to show the dependencies.
I want to write a sbt plugin which depends on it, but always fails.
build.sbt
sbtPlugin := true
name := "my-sbt-plugin-depends-on-another"
version := "0.1.2.1"
organization := "test20140913"
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5")
src/main/scala/MySbtPlugin.scala
import sbt._
object MySbtPlugin extends AutoPlugin {
object autoImport {
lazy val hello = taskKey[Unit]("hello task from my plugin")
lazy val hello2 = taskKey[Unit]("hello task from my plugin2")
}
import autoImport._
override def trigger = allRequirements
override def requires = plugins.JvmPlugin
val helloSetting = hello := println("Hello from my plugin")
val helloSetting2 = hello2 := {
println("hello2, task result from another plugins:")
println(net.virtualvoid.sbt.graph.Plugin.dependencyTree.value)
println("=========================================")
}
override def projectSettings = Seq(
helloSetting, helloSetting2
)
}
Then I published it to local, and use it in another project:
build.sbt
name := "sbt--plugin-test"
version := "1.0"
scalaVersion := "2.11.6"
net.virtualvoid.sbt.graph.Plugin.graphSettings
project/plugins.scala
logLevel := Level.Info
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5")
addSbtPlugin("test20140913" % "my-sbt-plugin-depends-on-another" % "0.1.2.1")
When I run sbt on the later project, it reports:
Reference to undefined setting:
*:dependencyTree from *:hello2 (/Users/twer/workspace/my-sbt-plugin-depends-on-another/src/main/scala/test20140913/MySbtPlugin.scala:38)
Did you mean provided:dependencyTree ?
at sbt.Init$class.Uninitialized(Settings.scala:262)
at sbt.Def$.Uninitialized(Def.scala:10)
at sbt.Init$class.delegate(Settings.scala:188)
at sbt.Def$.delegate(Def.scala:10)
Where is wrong?
PS: The plugin code is here: https://github.com/freewind/my-sbt-plugin-depends-on-another
dependencyTree is only defined for specific configurations (well all of them), but it automatically delegates to Compile in the shell.
Try defining hello2 like so:
val helloSetting2 = hello2 := {
println("hello2, task result from another plugins:")
import net.virtualvoid.sbt.graph.Plugin.dependencyTree
println((dependencyTree in Compile).value)
println("=========================================")
}

Why does sbt console not see packages from subproject in multi-module project?

This is my project/Build.scala:
package sutils
import sbt._
import Keys._
object SutilsBuild extends Build {
scalaVersion in ThisBuild := "2.10.0"
val scalazVersion = "7.0.6"
lazy val sutils = Project(
id = "sutils",
base = file(".")
).settings(
test := { },
publish := { }, // skip publishing for this root project.
publishLocal := { }
).aggregate(
core
)
lazy val core = Project(
id = "sutils-core",
base = file("sutils-core")
).settings(
libraryDependencies += "org.scalaz" % "scalaz-core_2.10" % scalazVersion
)
}
This seems to be compiling my project just fine, but when I go into the console, I can't import any of the code that just got compiled?!
$ sbt console
scala> import com.github.dcapwell.sutils.validate.Validation._
<console>:7: error: object github is not a member of package com
import com.github.dcapwell.sutils.validate.Validation._
What am I doing wrong here? Trying to look at the usage, I don't see a way to say which subproject to load while in the console
$ sbt about
[info] Loading project definition from /src/sutils/project
[info] Set current project to sutils (in build file:/src/sutils/)
[info] This is sbt 0.13.1
[info] The current project is {file:/src/sutils/}sutils 0.1-SNAPSHOT
[info] The current project is built against Scala 2.10.3
[info] Available Plugins: org.sbtidea.SbtIdeaPlugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.10.3
There's the solution from #Alexey-Romanov to start the console task in the project the classes to import are in.
sbt sutils/console
There's however another solution that makes the root sutils project depend on the other core. Use the following snippet to set up the project - note dependsOn core that will bring the classes from the core project to sutils's namespace.
lazy val sutils = Project(
id = "sutils",
base = file(".")
).settings(
test := { },
publish := { }, // skip publishing for this root project.
publishLocal := { }
).aggregate(
core
).dependsOn core
BTW, you should really use a simpler build.sbt for your use case as follows:
scalaVersion in ThisBuild := "2.10.0"
val scalazVersion = "7.0.6"
lazy val sutils = project.in(file(".")).settings(
test := {},
publish := {}, // skip publishing for this root project.
publishLocal := {}
).aggregate(core).dependsOn(core)
lazy val core = Project(
id = "sutils-core",
base = file("sutils-core")
).settings(
libraryDependencies += "org.scalaz" %% "scalaz-core" % scalazVersion
)
You could make it even easier when you'd split the build to two build.sbts, each for the projects.