I want to create a sbt plugin
this is my project
build.sbt file:
lazy val root = (project in file(".")).
settings(
name := "test-plagin",
version := "0.1.0",
organization := "com.test",
scalaVersion := "2.13.0",
sbtPlugin := true,
)
main file with task
import sbt.{AutoPlugin, TaskKey}
object HelloPlugin extends AutoPlugin {
object autoImport {
val sayHello: TaskKey[Unit] = TaskKey("saying hello")
}
import autoImport._
override def projectSettings = Seq(
sayHello := {
println("hello")
}
)
}
During compiling I get an error:
java.lang.NoClassDefFoundError: scala/collection/immutable/StringOps
When I change the version to 2.12.6 - compiling is success.
How I can fix error in 2.13?
sbt is written in Scala 2.12
https://github.com/sbt/sbt/blob/develop/project/Dependencies.scala#L9
https://github.com/sbt/sbt/issues/5032
So you should use Scala 2.12 for sbt plugins.
Related
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 can't figure out how to do benchmarks of Scala programs in Intellij with JMH.
Here's what I've done so far:
Added the JMH SBT-Plugin
// build.sbt
name := "Project"
version := "1.0"
scalaVersion := "2.11.8"
enablePlugins(JmhPlugin)
// project/plugins.sbt
logLevel := Level.Warn
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.2.10")
Here is the plugin's website
Created a benchmark class
// src/main/scala/MyBenchmark.scala
import org.openjdk.jmh.annotations.Benchmark
class MyBenchmark {
#Benchmark
def test(): Unit = println("test")
}
Created an SBT-Task in Intellij
But after running the task I just get an exception:
Annotation generator had thrown the exception.
java.lang.NullPointerException
at org.openjdk.jmh.generators.reflection.RFClassInfo.getPackageName(RFClassInfo.java:51)
at org.openjdk.jmh.generators.core.BenchmarkGenerator.validateBenchmark(BenchmarkGenerator.java:243)
at org.openjdk.jmh.generators.core.BenchmarkGenerator.generate(BenchmarkGenerator.java:90)
....
What am I doing wrong?
Try to add package name in the benchmark class.
Because JMH is complaining about package name is not found.
org.openjdk.jmh.generators.reflection.RFClassInfo.getPackageName(RFClassInfo.java:51)
you should add the line like:
package your.path;
I tried my hand on macros, and I keep running into the error
macro implementation not found: W
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
I believe I've set up a two pass compilation with the macro implementation being compiled first, and the usage second.
Here is part of the /build.sbt:
lazy val root = (project in file(".")).
settings(rootSettings: _*).
settings(name := "Example").
aggregate(macros, core).
dependsOn(macros, core)
lazy val macros = (project in file("src/main/com/example/macros")).
settings(macrosSettings: _*).
settings(name := "Macros")
lazy val core = (project in file("src/main/com/example/core")).
settings(coreSettings: _*).
settings (name := "Core").
dependsOn(macros)
lazy val commonSettings = Seq(
organization := Organization,
version := Version,
scalaVersion := ScalaVersion
)
lazy val rootSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ rootDeps ++ macrosDeps ++ coreDeps
)
lazy val macrosSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ macrosDeps
)
lazy val coreSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ coreDeps
)
The macro implementation looks like this:
/src/main/com/example/macros/Macros.scala
object Macros {
object Color {
def ColorWhite(c: Context): c.Expr[ObjectColor] = c.Expr[ObjectColor](c.universe.reify(ObjectColor(White())).tree)
}
}
The usage looks like this:
/src/main/com/example/core/Main.scala
object Macros {
import com.example.macros.Macros._
def W: ObjectColor = macro Color.ColorWhite
}
object Main extends App {
import Macros._
println(W)
}
Scala 2.11.6. SBT 0.13.8.
What am I doing wrong?
Thanks for your advice!
Fawlty Project:
The Project on Github
Working Project:
Rearranged the projects to a more correct form:
The cleanedup working project
Your macros and core projects don't contain any files, so they don't cause the problem. The error happens when sbt compiles root, which contains both Main.scala and Macros.scala by the virtue of you saying project in file(".") in the sbt build.
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("=========================================")
}
I have the following build.sbt file:
version := "0.0.1"
version in Test := "0.0.1-DEBUG"
name <<= (version) apply { v:String => "demo-%s".format(v) }
and while the version seems to be right in the "test" configuration,
> show test:version
[info] 0.0.1-DEBUG
the name doesn't seem to look at the more-specific setting.
> show name
[info] demo-0.0.1
> show test:name
[info] demo-0.0.1
This is obviously a greatly-simplified example of what i'm really trying to do, but i think it illustrates the problem/misunderstanding.
EDIT (2013-07-04): What i'm really trying to do is change javaOptions in the IntegrationTest configuration (b/c we spin up a service and then run testing code against it, and i'd like the service being tested to run in a slightly sandboxed mode). Setting javaOptions in IntegrationTest is easy enough (and show it:java-options confirms), but doesn't actually get used by runner unless i go to the trouble of explicitly defining it:runner to use it:java-options. I would have expected *:runner to prefer the most-specific dependent vars.
Here's your Build.scala translated to use inConfig as suggested by #MarkHarrah:
import sbt._
import sbt.Keys._
object DemoBuild extends Build {
val mySettings = Seq(
name <<= version { v => "demo-%s".format(v) }
)
lazy val demo = Project(
id = "demo",
base = file("."),
settings = Project.defaultSettings ++ Seq(
organization := "com.demo",
scalaVersion := "2.10.0",
version := "0.0.1",
version in Test <<= version { v => "%s-DEBUG".format(v) }
) ++ mySettings
++ inConfig(Test)(mySettings)
)
}
I tried this in sbt 0.11 and 0.12.1 and it worked:
version := "0.0.1"
version in Test := "0.0.1-DEBUG"
name <<= (version) apply { v:String => "demo-%s".format(v) }
name in Test <<= (version in Test) apply { v:String => "demo-%s".format(v) }
UPDATE
If you're using a Build.scala file you can generalize this task across projects. Here's an example:
import sbt._
import sbt.Keys._
object DemoBuild extends Build {
lazy val demo = Project(
id = "demo",
base = file("."),
settings = Project.defaultSettings ++ Seq(
organization := "com.demo",
scalaVersion := "2.10.0"
) ++ addNameAndVersion("0.0.1", "demo")
)
def addNameAndVersion(projectVersion:String, projectName:String):Seq[sbt.Project.Setting[_]] = {
Seq(
version := projectVersion,
version in Test := projectVersion + "-DEBUG",
name <<= version.apply(s => "%s-%s".format(projectName, s)),
name in Test <<= (version in Test).apply(s => "%s-%s".format(projectName, s))
)
}
}