I am trying to build a plugin that automatically sets up a set of scalariform preferences.
My plugin's build.sbt:
name := "my-scalariform"
organization := "com.my"
version := "1.0-SNAPSHOT"
sbtPlugin := true
scalacOptions ++= Seq("-feature", "-deprecation", "-unchecked")
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
My initial plugin design:
package com.my.plugins
import com.typesafe.sbt.SbtScalariform
import com.typesafe.sbt.SbtScalariform.{
ScalariformKeys,
scalariformSettings
}
import sbt.AutoPlugin
import sbt.{ Compile, Test }
import sbt.Keys.{ compile, compileInputs }
import scalariform.formatter.preferences.{
DoubleIndentClassDeclaration,
FormattingPreferences,
IndentSpaces,
IndentWithTabs,
PreserveDanglingCloseParenthesis
}
object MyScalariformPlugin extends AutoPlugin {
override def trigger = allRequirements
lazy val formattingPreferences = {
import scalariform.formatter.preferences._
Seq(
ScalariformKeys.preferences := FormattingPreferences()
.setPreference(DoubleIndentClassDeclaration, true)
.setPreference(IndentSpaces, 2)
.setPreference(IndentWithTabs, false)
.setPreference(PreserveDanglingCloseParenthesis, true)
)
}
override lazy val projectSettings = scalariformSettings ++ formattingPreferences
}
When I added this plugin to my project I can see my scalariform settings:
> scalariform-preferences
[info] FormattingPreferences(Map(DoubleIndentClassDeclaration -> true, IndentSpaces -> 2, IndentWithTabs -> false, PreserveDanglingCloseParenthesis -> true))
However the compileInputs is missing the scalariform-format dependency:
> inspect compile:compile::compileInputs
...
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:792
[info] Dependencies:
[info] compile:compile::incCompileSetup
[info] compile:compile::streams
[info] compile:compile::dependencyClasspath
[info] compile:compile::compileOrder
[info] compile:compile::scalacOptions
[info] compile:compile::classDirectory
[info] compile:compile::javacOptions
[info] compile:compile::sourcePositionMappers
[info] compile:compile::compilers
[info] compile:compile::sources
[info] compile:compile::maxErrors
[info] Reverse dependencies:
[info] compile:compile
...
If I explicitly add the scalariform command overrides as a value in my plugin and then explicitly add it to my project I get the correct dependencies:
lazy val commandSettings = Seq(
compileInputs in (Compile, compile) <<= (compileInputs in (Compile, compile)) dependsOn (ScalariformKeys.format in Compile),
compileInputs in (Test, compile) <<= (compileInputs in (Test, compile)) dependsOn (ScalariformKeys.format in Test)
)
Dependencies:
> inspect compile:compile::compileInputs
...
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:792
[info] (com.my.plugins.MyScalariformPlugin) MyScalariformPlugin.scala:22
[info] Dependencies:
[info] compile:compile::incCompileSetup
[info] compile:compile::streams
[info] compile:compile::dependencyClasspath
[info] compile:scalariformFormat
[info] compile:compile::compileOrder
[info] compile:compile::scalacOptions
[info] compile:compile::classDirectory
[info] compile:compile::javacOptions
[info] compile:compile::sourcePositionMappers
[info] compile:compile::compilers
[info] compile:compile::sources
[info] compile:compile::maxErrors
[info] Reverse dependencies:
[info] compile:compile
...
I have tried specifying this dependency myself using an autoImport but that results in an error:
object autoImport {
lazy val commandSettings = Seq(
compileInputs in (Compile, compile) <<= (compileInputs in (Compile, compile)) dependsOn (ScalariformKeys.format in Compile),
compileInputs in (Test, compile) <<= (compileInputs in (Test, compile)) dependsOn (ScalariformKeys.format in Test)
)
}
import autoImport._
Errors:
[error] References to undefined settings:
[error]
[error] */test:compile::compileInputs from */test:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:24)
[error] Did you mean test:compile::compileInputs ?
[error]
[error] */test:scalariformFormat from */test:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:24)
[error] Did you mean test:scalariformFormat ?
[error]
[error] */compile:compile::compileInputs from */compile:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:23)
[error] Did you mean compile:compile::compileInputs ?
[error]
[error] */compile:scalariformFormat from */compile:compile::compileInputs ((com.my.plugins.MyScalariformPlugin.autoImport) MyScalariformPlugin.scala:23)
[error] Did you mean compile:scalariformFormat ?
[error]
Add this line to MyScalariformPlugin (don't ask me why :))
override def requires = plugins.JvmPlugin
Related
I am trying to publish my project on bintray for the first time. I read the documentation here
https://github.com/sbt/sbt-bintray
My plugins.sbt file is
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1")
This is my build.sbt. You can see that I have defined the license for my project
lazy val publishSettings = Seq(
licenses += ("MIT", url("http://opensource.org/licenses/MIT")),
bintrayOrganization := Some("abhishes"),
bintrayRepository := "AbhiTestRepo",
bintrayPackageLabels := Seq("foo", "bar")
)
lazy val commonSettings = Seq(
"organization" := "abhishes",
version := "1.0",
scalaVersion := "2.12.3"
)
lazy val project1 = (project in file("SubProject1")).settings(commonSettings)
.settings(publishSettings)
.settings(
name := "SubProject1"
)
lazy val project2 = (project in file("SubProject2")).settings(commonSettings)
.settings(publishSettings)
.settings(
name := "SubProject2"
)
lazy val rootProject = (project in file("."))
.settings(commonSettings)
.settings(publishSettings)
.settings(
name := "MyScalaProject"
).dependsOn(project1, project2)
when I say sbt publish I still get this error
> publish
[trace] Stack trace suppressed: run last rootProject/*:bintrayEnsureLicenses for the full output.
[error] (rootProject/*:bintrayEnsureLicenses) you must define at least one license for this project. Please choose one or more of
[error] AFL-3.0, AGPL-V3, APL-1.0, APSL-2.0, Apache-1.0, Apache-1.1, Apache-2.0, Artistic-License-2.0, Attribution, BSD, BSD New, BSD Simplified, BSL-1.0, Bouncy-Castle, CA-TOSL-1.1, CDDL-1.0, CPAL-1.0, CPL-1.0, CPOL-1.02, CUAOFFICE-1.0, Codehaus, Day, Day-Addendum, ECL2, EUDATAGRID, EUPL-1.1, Eclipse-1.0, Eiffel-2.0, Entessa-1.0, Fair, Frameworx-1.0, GPL-2.0, GPL-2.0+CE, GPL-3.0, HSQLDB, Historical, IBMPL-1.0, IPAFont-1.0, ISC, IU-Extreme-1.1.1, JA-SIG, JSON, JTidy, LGPL-2.1, LGPL-3.0, Lucent-1.02, MIT, MPL-2.0, MS-PL, MS-RL, MirOS, Motosoto-0.9.1, Mozilla-1.1, Multics, NASA-1.3, NAUMEN, NOSL-3.0, NTP, Nethack, Nokia-1.0a, OCLC-2.0, OSL-3.0, Openfont-1.1, Opengroup, PHP-3.0, PostgreSQL, Public Domain, Public Domain - SUN, PythonPL, PythonSoftFoundation, QTPL-1.0, RPL-1.5, Real-1.0, RicohPL, SUNPublic-1.0, SimPL-2.0, Sleepycat, Sybase-1.0, TMate, Unlicense, UoI-NCSA, VovidaPL-1.0, W3C, WTFPL, Xnet, ZLIB, ZPL-2.0, wxWindows
[error] Total time: 1 s, completed Aug 26, 2017 1:00:10 PM
>
EDIT: This is the output of inspect licenses
> inspect licenses
[info] Setting: scala.collection.Seq[scala.Tuple2[java.lang.String, java.net.URL]] = List()
[info] Description:
[info] Project licenses as (name, url) pairs.
[info] Provided by:
[info] */*:licenses
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1186
[info] Reverse dependencies:
[info] rootProject/*:bintrayEnsureBintrayPackageExists
[info] rootProject/*:projectInfo
[info] rootProject/*:bintrayEnsureLicenses
[info] Delegates:
[info] rootProject/*:licenses
[info] {.}/*:licenses
[info] */*:licenses
[info] Related:
[info] */*:licenses
>
Edit2: Here is the output of inspect rootProject/licenses
> inspect rootProject/licenses
[info] Setting: scala.collection.Seq[scala.Tuple2[java.lang.String, java.net.URL]] = List()
[info] Description:
[info] Project licenses as (name, url) pairs.
[info] Provided by:
[info] */*:licenses
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1186
[info] Reverse dependencies:
[info] rootProject/*:bintrayEnsureBintrayPackageExists
[info] rootProject/*:projectInfo
[info] rootProject/*:bintrayEnsureLicenses
[info] Delegates:
[info] rootProject/*:licenses
[info] {.}/*:licenses
[info] */*:licenses
[info] Related:
[info] */*:licenses
I was able to resolve the problem myself. If you look in the source code of the plugin
https://github.com/sbt/sbt-bintray/blob/7a14108bd273a8bb469ad118ccd7cce5b4042099/src/main/scala/Bintray.scala#L33
The data type of of licenses is Seq[(String, url)]
Based on this I changed my code accordingly by making the licenses as a sequence of tuples of type (String, url) and the problem got resolved.
lazy val publishSettings = Seq(
licenses ++= Seq(("MIT", url("http://opensource.org/licenses/MIT"))),
bintrayOrganization := Some("abhishes"),
bintrayRepository := "AbhiTestRepo",
bintrayPackageLabels := Seq("foo", "bar")
)
Overriding scalacOptions for the SBT console does not work for me, based on the discussion at: In sbt, how do you override scalacOptions for console in all configurations?
The contents of my build.sbt are as follows:
lazy val commonScalacOptions = Seq(
"-deprecation",
"-encoding", "UTF-8",
"-feature",
"-unchecked",
"-Xfatal-warnings",
"-Xlint:-missing-interpolator,_",
"-Yinline-warnings",
"-Yno-adapted-args",
"-Ywarn-dead-code",
"-Ywarn-numeric-widen",
"-Ywarn-value-discard",
"-Ywarn-unused-import",
"-language:existentials",
"-language:experimental.macros",
"-language:implicitConversions",
"-language:higherKinds",
"-Xfuture")
lazy val commonSettings = Seq(
scalaVersion := "2.11.11",
scalacOptions ++= commonScalacOptions,
scalacOptions in (Compile, console) := (scalacOptions in (Compile, console)).value filterNot ("-Ywarn-unused-import" == _),
scalacOptions in (Test, console) := (scalacOptions in (Compile, console)).value)
lazy val root = Project("brontosaurus-rex", file("." + "brontosaurus-rex")).in(file("."))
.settings(commonSettings: _*)
and when I run an SBT session, I can see that the -Ywarn-unused-imports option is not part of compile:console::scalacOptions
> show compile:console::scalacOptions
[info] * -deprecation
[info] * -encoding
[info] * UTF-8
[info] * -feature
[info] * -unchecked
[info] * -Xfatal-warnings
[info] * -Xlint:-missing-interpolator,_
[info] * -Yinline-warnings
[info] * -Yno-adapted-args
[info] * -Ywarn-dead-code
[info] * -Ywarn-numeric-widen
[info] * -Ywarn-value-discard
[info] * -language:existentials
[info] * -language:experimental.macros
[info] * -language:implicitConversions
[info] * -language:higherKinds
[info] * -Xfuture
However, attempting to run console with an unused import in one of my source code files, results in the unexpected error:
> console
[info] Compiling 1 Scala source to [PROJECT_DIR]/brontosaurus-rex/target/scala-2.11/classes...
[error] [PROJECT_DIR]/brontosaurus-rex/src/main/scala/com/dinosaurs/BrontosaurusRex.scala:3: Unused import
[error] import scala.util.matching.Regex
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 0 s, completed May 21, 2017 7:45:53 PM
It seems that the error is coming from compile:compileIncremental. When I show the contents of compile:compileIncremental::scalacOptions I see the option that I'm trying to filter out:
> show compile:compileIncremental::scalacOptions
[info] * -deprecation
[info] * -encoding
[info] * UTF-8
[info] * -feature
[info] * -unchecked
[info] * -Xfatal-warnings
[info] * -Xlint:-missing-interpolator,_
[info] * -Yinline-warnings
[info] * -Yno-adapted-args
[info] * -Ywarn-dead-code
[info] * -Ywarn-numeric-widen
[info] * -Ywarn-value-discard
[info] * -Ywarn-unused-import
[info] * -language:existentials
[info] * -language:experimental.macros
[info] * -language:implicitConversions
[info] * -language:higherKinds
[info] * -Xfuture
Now, if I inspect the above, it appears to be provided by compile:scalacOptions. What I'm confused about is why the compiler options in compile:console::scalacOptions don't appear to be used when running the console command.
I'd like to be able to run a less strict set of compiler options for console and this way of doing it seems fairly straightforward. However, I'm stumped as to why the existing solution no longer works. Can anyone help set me straight here?
First, scalacOptions in (Compile, console) it means setting scalacOptions to compile scala that you input in the Console.
As the your compile error, this is caused by before you go to the Scala console, the compiler will firstly try to compile current project and since you have setted scalacOptions for compile, so this error has throwed.
The following works on my side in SBT 1.3.2:
val unusedImports = "-Ywarn-unused:imports"
...
scalacOptions ++= Seq(
unusedImports,
"-Yrangepos",
"-Ywarn-unused:privates"
),
Compile / console / scalacOptions := (Compile / scalacOptions).value filterNot (_ eq unusedImports)
I like defining scalacOptions at the top level like so (as an example, ignoring project axis for now):
scalacOptions += "-Ywarn-unused-import"
But then I realised that's too strict for console. So I tried setting:
scalacOptions in console ~= (_ filterNot (_ == "-Ywarn-unused-import"))
But that didn't work (still got (fatal) warnings in the REPL).
I used inspect to try and understand why:
> inspect console
[info] Task: Unit
[info] Description:
[info] Starts the Scala interpreter with the project classes on the classpath.
[info] Provided by:
[info] {file:/a/}b/compile:console
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:261
[info] Dependencies:
[info] compile:console::compilers
[info] compile:console::initialCommands
[info] compile:console::fullClasspath
[info] compile:console::taskTemporaryDirectory
[info] compile:console::scalaInstance
[info] compile:console::streams
[info] compile:console::cleanupCommands
[info] compile:console::scalacOptions
[info] Delegates:
[info] compile:console
[info] *:console
[info] {.}/compile:console
[info] {.}/*:console
[info] */compile:console
[info] */*:console
[info] Related:
[info] test:console
Note: console is
provided by compile:console
depends on compile:console::scalacOptions
then:
> inspect compile:console::scalacOptions
[info] Task: scala.collection.Seq[java.lang.String]
[info] Description:
[info] Options for the Scala compiler.
[info] Provided by:
[info] {file:/a/}b/compile:scalacOptions
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1593
[info] Reverse dependencies:
[info] compile:console
[info] Delegates:
[info] compile:console::scalacOptions
[info] compile:scalacOptions
[info] *:console::scalacOptions
[info] *:scalacOptions
[info] {.}/compile:console::scalacOptions
[info] {.}/compile:scalacOptions
[info] {.}/*:console::scalacOptions
[info] {.}/*:scalacOptions
[info] */compile:console::scalacOptions
[info] */compile:scalacOptions
[info] */*:console::scalacOptions
[info] */*:scalacOptions
[info] Related:
[info] *:console::scalacOptions
[info] compile:scalacOptions
[info] *:scalacOptions
[info] */*:scalacOptions
[info] test:scalacOptions
Note: compile:console::scalacOptions is
provided by compile:scalacOptions
doesn't reach *:console::scalacOptions (which is what I defined) in the delegation chain
My question is how do I override scalacOptions for all configurations for console? Is it possible to change the delegation chain?
I'd like to avoid having to set scalacOptions in (Compile, console) (as it would be duplicated for (Test, console)) or define a val of scalac options.
My question is how do I override scalacOptions for all configurations for console?
I don't think we can given the presence of compile:scalacOptions provided by sbt's Defaults. The only scope that has higher precedence is compile:console::scalacOptions.
In most cases one would not want Compile and Test settings to cross wire, so configuration scoping higher precedence I don't think is a bad default.
lazy val commonSettings = Seq(
scalaVersion := "2.11.4",
scalacOptions += "-Ywarn-unused-import",
scalacOptions in (Compile, console) ~= (_ filterNot (_ == "-Ywarn-unused-import")),
scalacOptions in (Test, console) := (scalacOptions in (Compile, console)).value
)
Is it possible to change the delegation chain?
No, this is not possible.
There's a single instance of delegates function in BuildStructure, and it's initialized at the loading time and used for all tasks.
The ordering is done in Scope.delegates.
I fix the bad scalac options in an autoplugin:
package console
import sbt._
/** [[FixScalacOptionsInConsole]] is an [[AutoPlugin]] that removes
* noisy or unnecessary scalac options when running an sbt console.
*/
object FixScalacOptionsInConsole extends AutoPlugin {
import Keys._
override def requires = plugins.JvmPlugin
override def trigger = allRequirements
override lazy val projectSettings = Seq(
Compile / console / scalacOptions ~= filter,
Test / console / scalacOptions ~= filter
)
def filter: Seq[String] => Seq[String] =
_ .filterNot(_ == "-feature")
.filterNot(_.startsWith("-opt:"))
.filterNot(_ == "-unchecked")
.filterNot(_.startsWith("-Xlint:"))
.filterNot(_ == "-Xfatal-warnings")
.filterNot(_.startsWith("-Ywarn"))
}
Some of my tests require that they are sequentially executed. I read about custom configurations on http://www.scala-sbt.org/0.13.0/docs/Detailed-Topics/Testing.html but I am missing something because my configuration is not working properly.
Here it is:
import sbt._
import Keys._
object SchedulingBackendBuild extends Build {
lazy val SequentialTest = config("sequentialTest") extend(Test)
def sequentialTestFilter(name: String): Boolean = {
println("===seq test filter")
name endsWith "SeqSpec"
}
def unitTestFilter(name: String): Boolean = {
println("===unit test filter")
!sequentialTestFilter(name)
}
lazy val root = Project(id = "scheduling-backend",
base = file("."),
settings = Project.defaultSettings
).configs(SequentialTest)
.settings(inConfig(SequentialTest)(Defaults.testTasks): _*)
.settings(
testOptions in Test ++= Seq(Tests.Filter(unitTestFilter)),
testOptions in SequentialTest ++= Seq(Tests.Filter(sequentialTestFilter))
)
}
I want test to only execute tests that are not ending with SeqSpec and this is working, but when I try to execute sequentialTest:test no tests are executed. I added println to my filters and I can see that even if I execute sequentialTest:test I am getting
===unit test filter
===seq test filter
===seq test filter
so both filters are executed.
When I type inspect sequentialTest:testOptions I am getting
[info] Task: scala.collection.Seq[sbt.TestOption]
[info] Description:
[info] Options for running tests.
[info] Provided by:
[info] {file:/path/to/project/scheduling-backend/}scheduling-backend/sequentialTest:testOptions
[info] Defined at:
[info] /path/to/project/scheduling-backend/project/Build.scala:22
[info] Reverse dependencies:
[info] sequentialTest:testOnly::testOptions
[info] sequentialTest:testQuick::testOptions
[info] sequentialTest:test::testOptions
[info] Delegates:
[info] sequentialTest:testOptions
[info] test:testOptions
[info] runtime:testOptions
[info] compile:testOptions
[info] *:testOptions
[info] {.}/sequentialTest:testOptions
[info] {.}/test:testOptions
[info] {.}/runtime:testOptions
[info] {.}/compile:testOptions
[info] {.}/*:testOptions
[info] */sequentialTest:testOptions
[info] */test:testOptions
[info] */runtime:testOptions
[info] */compile:testOptions
[info] */*:testOptions
[info] Related:
[info] sequentialTest:testOnly::testOptions
[info] sequentialTest:testQuick::testOptions
[info] test:testOptions
[info] test:testQuick::testOptions
[info] */*:testOptions
[info] test:testOnly::testOptions
[info] test:test::testOptions
[info] sequentialTest:test::testOptions
so for me it looks ok, line 22 is testOptions in SequentialTest ++= Seq(Tests.Filter(sequentialTestFilter))
Partial answer: if I change ++= operator (appending to the sequence) to := (replacing the sequence) everything works fine (and := operators are used in the documentation). Even so I would want to know why ++= in this case is bad choice.
I'm trying to create a simple ant task, which depends on compile. The problem I'm having is that I can't seem to set the javacOptions from within my task (only in the global scope).
val metamodelSettings = TaskKey[Unit]("metamodelSettings")
val metamodel = TaskKey[Unit]("metamodel")
metamodelSettings := {
print("Metamodel generation started")
javacOptions := Seq(
"-verbose",
"-g",
"-processor", "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor",
"-s", "app",
"-proc:only"
)
}
metamodel := {
print("Metamodel generation complete")
}
metamodel <<= metamodel.dependsOn(metamodelSettings, compile in Compile)
How can I change the javacOptions just for my metamodel task?
Edit:
[info] This is sbt 0.13.0
$ inspect metamodelSettings:javacOptions
[info] Task: scala.collection.Seq[java.lang.String]
[info] Description:
[info] Options for the Java compiler.
[info] Provided by:
[info] */*:javacOptions
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:209
[info] Delegates:
[info] metamodelSettings:javacOptions
[info] *:javacOptions
[info] {.}/metamodelSettings:javacOptions
[info] {.}/*:javacOptions
[info] */metamodelSettings:javacOptions
[info] */*:javacOptions
[info] Related:
[info] *:metamodelSettings::javacOptions
[info] compile:javacOptions
[info] *:metamodel::javacOptions
[info] */*:javacOptions
[info] compile:doc::javacOptions
show metamodelSettings::javacOptions is showing the expected values, but still not using them.
[test] $ show metamodelSettings::javacOptions
[info] List(-verbose, -g, -processor, org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor, -s, app, -proc:only)
[success] Total time: 0 s, completed 04-Feb-2014 11:29:56
If you want to set javacOptions only for metamodelSettings then use in to provide a scope for settings:
javacOptions in metamodelSettings := Seq(...)
You can also use different style whith inTask;
inTask(metamodelSettings) {
// your settings
}
As I was unable to override the settings, I resorted to invoking the compiler directly. This seems like a nasty solution to me, but maybe somebody will find it useful.
val metamodel = TaskKey[Unit]("metamodel")
javacOptions := Seq("-proc:none")
cleanFiles <++= baseDirectory (_ ** "*_.java" get)
metamodel := {
managedClasspath in Compile <<= (classpathTypes, update) map {
(ct, report) =>
Classpaths.managedJars(Compile, Set("jar", "zip"), report)
}
val javac = (Keys.compileInputs in Keys.compile in Compile).value.compilers.javac
val src = (file("app") / "models") ** "*.java"
val cp = (managedClasspath in Compile).value.map(x => x.data)
val out = file("app/models")
val args = Seq(
"-processor", "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor",
"-s", "app",
"-proc:only"
)
javac(sources=src.get, classpath=cp, outputDirectory=out, options=args)(ConsoleLogger())
}