Imports and ill-behaved SBT plugins - sbt

I'm trying to define parsers in a build.sbt file.
I'm using this plugin, by adding this line in plugins.sbt:
addSbtPlugin("com.gilt" % "sbt-dependency-graph-sugar" % "0.7.4")
When specifiying this in build.sbt:
import sbt.complete.DefaultParsers._
val servers = token(
literal("desarrollo") |
literal("parametrizacion")
)
SBT complains with this error message:
reference to literal is ambiguous;
reference to token is ambiguous;
it is imported twice in the same scope by
import sbt.complete.DefaultParsers._
and import _root_.gilt.DependencyGraph._
How can I avoid this namespace clashing of basic SBT classes?.

One solution is this:
import sbt.complete.{DefaultParsers ⇒ DP}
import sbt.complete.DefaultParsers._
val servers = DP.token(
DP.literal("desarrollo") |
DP.literal("parametrizacion")
)
I don't fully like it, because it adds clutter.
The ideal solution is to hide unwanted imports.

This solution creates a new scope, so there's no interference with imports:
name := "MyProject"
{
import sbt.complete.DefaultParsers._
val servers = token(
"desarrollo" | "parametrizacion"
)
}

Related

Best place to declare own settings so I can access them from sbt shell and my .sbt and .scala build files?

My settings are declared in project/Utils.scala in an object BuildSupport and are made available in .sbt and .scala files with import BuildSupport._.
However, this doesn't work for sbt shell as seen in above screenshot since I can't import them there. For completeness sake, I have tried eval import BuildSupport._ but all that got me was <eval>:1: error: illegal start of simple expression.
How do I have to define own settings and tasks so I can access them from:
project/*.scala,
*.sbt and
sbt shell?
I assume defining them in an AutoPlugin would work, but I'd rather not have to go to that length. Is there any other way?
Declaring an adhoc AutoPlugin (https://www.scala-sbt.org/1.x/docs/Plugins.html) is the way to go.
Auto plugins ...
can define autoImport object, which is automatically included into build.sbt. This can be used for keys.
can define globalSettings, buildSettings, or projectSettings to inject settings and tasks either at the build-level or at the subproject level. This should become available in sbt shell.
A plugin doesn't have to be a published on its own. You can declare one inside project/*.scala like any other Scala object.
The plugin in the linked documentation is great for copy-pasting:
package sbthello
import sbt._
import Keys._
object HelloPlugin extends AutoPlugin {
override def trigger = allRequirements
object autoImport {
val helloGreeting = settingKey[String]("greeting")
val hello = taskKey[Unit]("say hello")
}
import autoImport._
override lazy val globalSettings: Seq[Setting[_]] = Seq(
helloGreeting := "hi",
)
override lazy val projectSettings: Seq[Setting[_]] = Seq(
hello := {
val s = streams.value
val g = helloGreeting.value
s.log.info(g)
}
)
}

Adding sbt native packager plugin in SBT

I have a very organized build file that is composed of the following scala files:
Build.scala - the main Build file
Dependencies.scala - where I define the dependencies and the versions
BuildSettings.scala - where I define the build settings
plugins.sbt
A snippet of the Build.scala is as below:
import sbt._
import Keys._
object MyBuild extends Build {
import Dependencies._
import BuildSettings._
import NativePackagerHelper._
// Configure prompt to show current project
override lazy val settings = super.settings :+ {
shellPrompt := { s => Project.extract(s).currentProject.id + " > " }
}
// Define our project, with basic project information and library dependencies
lazy val project = Project("my-project", file("."))
.settings(buildSettings: _*)
.settings(
libraryDependencies ++= Seq(
Libraries.scalaAsync
// Add your additional libraries here (comma-separated)...
)
).enablePlugins(JavaAppPackaging, DockerPlugin)
}
All the 4 files that I mentioned above are in the same directory which is inside the project directory. But when I run this build file, I get the following error:
not found value: NativePackagerHelper
Any clues why his this?
I figured out what the problem was. I had to use the following in my build.properties
sbt.version=0.13.11
I originally had 0.13.6 and it was causing the import statements to fail!

Include a simple val in sbt build files from global.sbt

I wish to set my version numbers externally across several build.sbt files through a single include file.
Within build.sbt I can do this
val base = "1.1"
version := base + ".8-SNAPSHOT"
This works fine as a first step.
According the the online help I should be able to create a file global.sbt in my ~/.sbt/0.13 folder
I created the file global.sbt with single line
val base = "1.1"
and removed the corresponding line from build.sbt
But when I start up my sbt I get "error: not found: value base"
So either it's not finding the global sbt or this form of global setting doesn't work.
Any suggestions as to how I can resolve this?
Can I make an explicit include command in my build.sbt files?
It seems from your test that vals in global ~/.sbt/0.13/*.sbt files don't propagate to local *.sbt files.
Here's a setup that works:
~/.sbt/0.13/plugins/VersionBasePlugin.scala
import sbt._, Keys._
object VersionBasePlugin extends AutoPlugin {
override def requires = plugins.CorePlugin
override def trigger = allRequirements
object autoImport {
val versionBase = settingKey[String]("version base")
}
import autoImport._
override def projectSettings = Seq(versionBase := "1.1")
}
and then in your build.sbt:
version := (versionBase.value + ".8-SNAPSHOT")
Does that work for you?

How to execute task that calls clean on subprojects without using aggregation?

I want make a take cleanAll that executes the clean task on a number of subprojects. I don't want to use aggregation just for the sake of clean.
We've run into issues with play's asset routes when we've been using submodules.
It's well documented how to create a new task, but how do I call a task on a subproject?
Based on the example by Jacek Laskowski I've come up with the following plugin that should be placed in your /project folder:
import sbt._
import sbt.AutoPlugin
import sbt.Keys._
import sbt.plugins.JvmPlugin
object CleanAllPlugin extends AutoPlugin {
val cleanAll = taskKey[Unit]("Cleans all projects in a build, regardless of dependencies")
override def requires = JvmPlugin
override def projectSettings = Seq(
cleanAllTask
)
def cleanAllTask = cleanAll := Def.taskDyn {
val allProjects = ScopeFilter(inAnyProject)
clean.all(allProjects)
}.value
}
The plugin can now be added to the root project for usage:
val main = Project("root", file("."))
.enablePlugins(CleanAllPlugin)
It can be executed in SBT by calling: cleanAll
Use the following build.sbt:
val selectDeps = ScopeFilter(inDependencies(ThisProject))
clean in Compile := clean.all(selectDeps).value
It assumes that the build.sbt file is in the project that has clean executed on itself and dependsOn projects.
If you need it in project/Build.scala, just add the following:
val selectDeps = ScopeFilter(inDependencies(ThisProject))
val cleanInSubprojects = Seq(
clean in Compile := clean.all(selectDeps).value
)
and add cleanInSubprojects to settings of every project:
// definition of a project goes here
.settings(cleanInSubprojects: _*)

How does one build a custom Bootstrap WebJar with sbt?

I want to build a WebJar that contains a brand-customized version of Bootstrap from LESS source. I have sbt.version=0.13.5-M4 in project/build.properties and addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.0-M2a") in project/plugins.sbt. My build.sbt looks like this:
import com.typesafe.web.sbt.WebPlugin
import com.typesafe.jse.sbt.JsEnginePlugin
import com.typesafe.web.sbt.WebPlugin.WebKeys
name := "brand-assets"
organization := "com.example"
version := "0.0.1-SNAPSHOT"
WebPlugin.webSettings
JsEnginePlugin.jsEngineSettings
lazy val root = (project in file(".")).addPlugins(SbtWeb)
excludeFilter in Assets := new PatternFilter("""[^_].*\.less""".r.pattern)
The errors I get are:
build.sbt:1: error: object web is not a member of package com.typesafe
import com.typesafe.web.sbt.WebPlugin
^
build.sbt:2: error: object sbt is not a member of package com.typesafe.jse
import com.typesafe.jse.sbt.JsEnginePlugin
^
build.sbt:15: error: value addPlugins is not a member of sbt.Project
lazy val root = (project in file(".")).addPlugins(SbtWeb)
^
sbt.compiler.EvalException: Type error in expression
What am I missing?
So far i unserstand your question, you should add the following line to plugin.sbt:
resolvers += Resolver.typesafeRepo("releases")
as disused at https://github.com/sbt/sbt-less/issues/31

Resources