mirror of https://github.com/sbt/sbt.git
Merge pull request #3133 from eed3si9n/wip/sbtcrossbuilding
[sbt 0.13] Port sbt-cross-building's ^ and ^^ commands
This commit is contained in:
commit
4ab11d7948
|
|
@ -326,4 +326,32 @@ $SwitchCommand [<scala-version>=]<scala-home> [<command>]
|
||||||
|
|
||||||
See also `help $CrossCommand`
|
See also `help $CrossCommand`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
val PluginCrossCommand = "^"
|
||||||
|
val PluginSwitchCommand = "^^"
|
||||||
|
|
||||||
|
def pluginCrossHelp: Help = Help.more(PluginCrossCommand, PluginCrossDetailed)
|
||||||
|
def pluginSwitchHelp: Help = Help.more(PluginSwitchCommand, PluginSwitchDetailed)
|
||||||
|
|
||||||
|
def PluginCrossDetailed =
|
||||||
|
s"""$PluginCrossCommand <command>
|
||||||
|
Runs <command> for each sbt version specified for cross-building.
|
||||||
|
|
||||||
|
For each string in `crossSbtVersions` in the current project, this command sets the
|
||||||
|
`sbtVersion in pluginCrossBuild` of all projects to that version, reloads the build,
|
||||||
|
and executes <command>. When finished, it reloads the build with the original
|
||||||
|
Scala version.
|
||||||
|
|
||||||
|
See also `help $PluginSwitchCommand`
|
||||||
|
"""
|
||||||
|
|
||||||
|
def PluginSwitchDetailed =
|
||||||
|
s"""$PluginSwitchCommand <sbt-version> [<command>]
|
||||||
|
Changes the sbt version and runs a command.
|
||||||
|
|
||||||
|
Sets the `sbtVersion in pluginCrossBuild` of all projects to <sbt-version> and
|
||||||
|
reloads the build. If <command> is provided, it is then executed.
|
||||||
|
|
||||||
|
See also `help $CrossCommand`
|
||||||
|
"""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,10 @@ object Defaults extends BuildCommon {
|
||||||
envVars :== Map.empty,
|
envVars :== Map.empty,
|
||||||
sbtVersion := appConfiguration.value.provider.id.version,
|
sbtVersion := appConfiguration.value.provider.id.version,
|
||||||
sbtBinaryVersion := binarySbtVersion(sbtVersion.value),
|
sbtBinaryVersion := binarySbtVersion(sbtVersion.value),
|
||||||
|
// `pluginCrossBuild` scoping is based on sbt-cross-building plugin.
|
||||||
|
// The idea here is to be able to define a `sbtVersion in pluginCrossBuild`, which
|
||||||
|
// directs the dependencies of the plugin to build to the specified sbt plugin version.
|
||||||
|
sbtVersion in pluginCrossBuild := sbtVersion.value,
|
||||||
watchingMessage := Watched.defaultWatchingMessage,
|
watchingMessage := Watched.defaultWatchingMessage,
|
||||||
triggeredMessage := Watched.defaultTriggeredMessage,
|
triggeredMessage := Watched.defaultTriggeredMessage,
|
||||||
onLoad := idFun[State],
|
onLoad := idFun[State],
|
||||||
|
|
@ -190,7 +194,16 @@ object Defaults extends BuildCommon {
|
||||||
sourceManaged := configSrcSub(sourceManaged).value,
|
sourceManaged := configSrcSub(sourceManaged).value,
|
||||||
scalaSource := sourceDirectory.value / "scala",
|
scalaSource := sourceDirectory.value / "scala",
|
||||||
javaSource := sourceDirectory.value / "java",
|
javaSource := sourceDirectory.value / "java",
|
||||||
unmanagedSourceDirectories := makeCrossSources(scalaSource.value, javaSource.value, scalaBinaryVersion.value, crossPaths.value),
|
unmanagedSourceDirectories := {
|
||||||
|
makeCrossSources(scalaSource.value,
|
||||||
|
javaSource.value,
|
||||||
|
scalaBinaryVersion.value,
|
||||||
|
crossPaths.value) ++
|
||||||
|
makePluginCrossSources(sbtPlugin.value,
|
||||||
|
scalaSource.value,
|
||||||
|
(sbtBinaryVersion in pluginCrossBuild).value,
|
||||||
|
crossPaths.value)
|
||||||
|
},
|
||||||
unmanagedSources := collectFiles(unmanagedSourceDirectories, includeFilter in unmanagedSources, excludeFilter in unmanagedSources).value,
|
unmanagedSources := collectFiles(unmanagedSourceDirectories, includeFilter in unmanagedSources, excludeFilter in unmanagedSources).value,
|
||||||
watchSources in ConfigGlobal ++= unmanagedSources.value,
|
watchSources in ConfigGlobal ++= unmanagedSources.value,
|
||||||
managedSourceDirectories := Seq(sourceManaged.value),
|
managedSourceDirectories := Seq(sourceManaged.value),
|
||||||
|
|
@ -231,17 +244,31 @@ object Defaults extends BuildCommon {
|
||||||
sbt.inc.ClassfileManager.transactional(crossTarget.value / "classes.bak", sbt.Logger.Null)),
|
sbt.inc.ClassfileManager.transactional(crossTarget.value / "classes.bak", sbt.Logger.Null)),
|
||||||
scalaInstance := scalaInstanceTask.value,
|
scalaInstance := scalaInstanceTask.value,
|
||||||
crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.Disabled),
|
crossVersion := (if (crossPaths.value) CrossVersion.binary else CrossVersion.Disabled),
|
||||||
crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, sbtBinaryVersion.value, sbtPlugin.value, crossPaths.value),
|
scalaVersion := {
|
||||||
|
val scalaV = scalaVersion.value
|
||||||
|
val sv = (sbtBinaryVersion in pluginCrossBuild).value
|
||||||
|
if (sbtPlugin.value) scalaVersionFromSbtBinaryVersion(sv)
|
||||||
|
else scalaV
|
||||||
|
},
|
||||||
|
sbtBinaryVersion in pluginCrossBuild := binarySbtVersion((sbtVersion in pluginCrossBuild).value),
|
||||||
|
crossSbtVersions := Vector((sbtVersion in pluginCrossBuild).value),
|
||||||
|
crossTarget := makeCrossTarget(target.value,
|
||||||
|
scalaBinaryVersion.value,
|
||||||
|
(sbtBinaryVersion in pluginCrossBuild).value,
|
||||||
|
sbtPlugin.value,
|
||||||
|
crossPaths.value),
|
||||||
clean := {
|
clean := {
|
||||||
val _ = clean.value
|
val _ = clean.value
|
||||||
IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
|
IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
|
||||||
},
|
},
|
||||||
scalaCompilerBridgeSource := {
|
scalaCompilerBridgeSource := {
|
||||||
|
// This is a workaround for sbtVersion getting set to another value.
|
||||||
|
val sv = appConfiguration.value.provider.id.version
|
||||||
if (ScalaInstance.isDotty(scalaVersion.value))
|
if (ScalaInstance.isDotty(scalaVersion.value))
|
||||||
// Maintained at https://github.com/lampepfl/dotty/tree/master/sbt-bridge
|
// Maintained at https://github.com/lampepfl/dotty/tree/master/sbt-bridge
|
||||||
ModuleID(scalaOrganization.value, "dotty-sbt-bridge", scalaVersion.value, Some("component")).sources()
|
ModuleID(scalaOrganization.value, "dotty-sbt-bridge", scalaVersion.value, Some("component")).sources()
|
||||||
else
|
else
|
||||||
ModuleID(xsbti.ArtifactInfo.SbtOrganization, "compiler-interface", sbtVersion.value, Some("component")).sources()
|
ModuleID(xsbti.ArtifactInfo.SbtOrganization, "compiler-interface", sv, Some("component")).sources()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// must be a val: duplication detected by object identity
|
// must be a val: duplication detected by object identity
|
||||||
|
|
@ -258,6 +285,14 @@ object Defaults extends BuildCommon {
|
||||||
derive(scalaBinaryVersion := binaryScalaVersion(scalaVersion.value))
|
derive(scalaBinaryVersion := binaryScalaVersion(scalaVersion.value))
|
||||||
))
|
))
|
||||||
|
|
||||||
|
private[sbt] def scalaVersionFromSbtBinaryVersion(sv: String): String =
|
||||||
|
VersionNumber(sv) match {
|
||||||
|
case VersionNumber(Seq(0, 12, _*), _, _) => "2.9.2"
|
||||||
|
case VersionNumber(Seq(0, 13, _*), _, _) => "2.10.6"
|
||||||
|
case VersionNumber(Seq(1, 0, _*), _, _) => "2.12.2"
|
||||||
|
case _ => sys.error(s"Unsupported sbt binary version: $sv")
|
||||||
|
}
|
||||||
|
|
||||||
def makeCrossSources(scalaSrcDir: File, javaSrcDir: File, sv: String, cross: Boolean): Seq[File] = {
|
def makeCrossSources(scalaSrcDir: File, javaSrcDir: File, sv: String, cross: Boolean): Seq[File] = {
|
||||||
if (cross)
|
if (cross)
|
||||||
Seq(scalaSrcDir.getParentFile / s"${scalaSrcDir.name}-$sv", scalaSrcDir, javaSrcDir)
|
Seq(scalaSrcDir.getParentFile / s"${scalaSrcDir.name}-$sv", scalaSrcDir, javaSrcDir)
|
||||||
|
|
@ -265,6 +300,12 @@ object Defaults extends BuildCommon {
|
||||||
Seq(scalaSrcDir, javaSrcDir)
|
Seq(scalaSrcDir, javaSrcDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def makePluginCrossSources(isPlugin: Boolean, scalaSrcDir: File,
|
||||||
|
sbtBinaryV: String, cross: Boolean): Seq[File] = {
|
||||||
|
if (cross && isPlugin) Vector(scalaSrcDir.getParentFile / s"${scalaSrcDir.name}-sbt-$sbtBinaryV")
|
||||||
|
else Vector()
|
||||||
|
}
|
||||||
|
|
||||||
def makeCrossTarget(t: File, sv: String, sbtv: String, plugin: Boolean, cross: Boolean): File =
|
def makeCrossTarget(t: File, sv: String, sbtv: String, plugin: Boolean, cross: Boolean): File =
|
||||||
{
|
{
|
||||||
val scalaBase = if (cross) t / ("scala-" + sv) else t
|
val scalaBase = if (cross) t / ("scala-" + sv) else t
|
||||||
|
|
@ -1033,7 +1074,20 @@ object Defaults extends BuildCommon {
|
||||||
projectCore ++ disableAggregation ++ Seq(
|
projectCore ++ disableAggregation ++ Seq(
|
||||||
// Missing but core settings
|
// Missing but core settings
|
||||||
baseDirectory := thisProject.value.base,
|
baseDirectory := thisProject.value.base,
|
||||||
target := baseDirectory.value / "target"
|
target := baseDirectory.value / "target",
|
||||||
|
// Use (sbtVersion in pluginCrossBuild) to pick the sbt module to depend from the plugin.
|
||||||
|
// Because `sbtVersion in pluginCrossBuild` can be scoped to project level,
|
||||||
|
// this setting needs to be set here too.
|
||||||
|
sbtDependency in pluginCrossBuild := {
|
||||||
|
val app = appConfiguration.value
|
||||||
|
val id = app.provider.id
|
||||||
|
val sv = (sbtVersion in pluginCrossBuild).value
|
||||||
|
val scalaV = (scalaVersion in pluginCrossBuild).value
|
||||||
|
val binVersion = (scalaBinaryVersion in pluginCrossBuild).value
|
||||||
|
val cross = if (id.crossVersioned) CrossVersion.binary else CrossVersion.Disabled
|
||||||
|
val base = ModuleID(id.groupID, id.name, sv, crossVersion = cross)
|
||||||
|
CrossVersion(scalaV, binVersion)(base).copy(crossVersion = CrossVersion.Disabled)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
// build.sbt is treated a Scala source of metabuild, so to enable deprecation flag on build.sbt we set the option here.
|
// build.sbt is treated a Scala source of metabuild, so to enable deprecation flag on build.sbt we set the option here.
|
||||||
lazy val deprecationSettings: Seq[Setting[_]] =
|
lazy val deprecationSettings: Seq[Setting[_]] =
|
||||||
|
|
@ -1301,7 +1355,7 @@ object Classpaths {
|
||||||
// Override the default to handle mixing in the sbtPlugin + scala dependencies.
|
// Override the default to handle mixing in the sbtPlugin + scala dependencies.
|
||||||
allDependencies := {
|
allDependencies := {
|
||||||
val base = projectDependencies.value ++ libraryDependencies.value
|
val base = projectDependencies.value ++ libraryDependencies.value
|
||||||
val pluginAdjust = if (sbtPlugin.value) sbtDependency.value.copy(configurations = Some(Provided.name)) +: base else base
|
val pluginAdjust = if (sbtPlugin.value) (sbtDependency in pluginCrossBuild).value.copy(configurations = Some(Provided.name)) +: base else base
|
||||||
if (scalaHome.value.isDefined || ivyScala.value.isEmpty || !managedScalaInstance.value)
|
if (scalaHome.value.isDefined || ivyScala.value.isEmpty || !managedScalaInstance.value)
|
||||||
pluginAdjust
|
pluginAdjust
|
||||||
else {
|
else {
|
||||||
|
|
@ -1328,10 +1382,13 @@ object Classpaths {
|
||||||
case _ => base
|
case _ => base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
def pluginProjectID: Initialize[ModuleID] =
|
||||||
def pluginProjectID: Initialize[ModuleID] = (sbtBinaryVersion in update, scalaBinaryVersion in update, projectID, sbtPlugin) {
|
Def.setting {
|
||||||
(sbtBV, scalaBV, pid, isPlugin) =>
|
if (sbtPlugin.value)
|
||||||
if (isPlugin) sbtPluginExtra(pid, sbtBV, scalaBV) else pid
|
sbtPluginExtra(projectID.value,
|
||||||
|
(sbtBinaryVersion in pluginCrossBuild).value,
|
||||||
|
(scalaBinaryVersion in pluginCrossBuild).value)
|
||||||
|
else projectID.value
|
||||||
}
|
}
|
||||||
def ivySbt0: Initialize[Task[IvySbt]] =
|
def ivySbt0: Initialize[Task[IvySbt]] =
|
||||||
(ivyConfiguration, credentials, streams) map { (conf, creds, s) =>
|
(ivyConfiguration, credentials, streams) map { (conf, creds, s) =>
|
||||||
|
|
@ -1351,8 +1408,18 @@ object Classpaths {
|
||||||
val explicit = buildStructure.value.units(thisProjectRef.value.build).unit.plugins.pluginData.resolvers
|
val explicit = buildStructure.value.units(thisProjectRef.value.build).unit.plugins.pluginData.resolvers
|
||||||
explicit orElse bootRepositories(appConfiguration.value) getOrElse externalResolvers.value
|
explicit orElse bootRepositories(appConfiguration.value) getOrElse externalResolvers.value
|
||||||
},
|
},
|
||||||
ivyConfiguration := new InlineIvyConfiguration(ivyPaths.value, externalResolvers.value, Nil, Nil, offline.value, Option(lock(appConfiguration.value)),
|
ivyConfiguration := new InlineIvyConfiguration(
|
||||||
checksums.value, Some(target.value / "resolution-cache"), UpdateOptions(), streams.value.log),
|
ivyPaths.value,
|
||||||
|
externalResolvers.value.toVector,
|
||||||
|
Vector.empty,
|
||||||
|
Vector.empty,
|
||||||
|
offline.value,
|
||||||
|
Option(lock(appConfiguration.value)),
|
||||||
|
checksums.value.toVector,
|
||||||
|
Some(crossTarget.value / "resolution-cache"),
|
||||||
|
UpdateOptions(),
|
||||||
|
streams.value.log
|
||||||
|
),
|
||||||
ivySbt := ivySbt0.value,
|
ivySbt := ivySbt0.value,
|
||||||
classifiersModule := ((projectID, sbtDependency, transitiveClassifiers, loadedBuild, thisProjectRef) map { (pid, sbtDep, classifiers, lb, ref) =>
|
classifiersModule := ((projectID, sbtDependency, transitiveClassifiers, loadedBuild, thisProjectRef) map { (pid, sbtDep, classifiers, lb, ref) =>
|
||||||
val pluginClasspath = lb.units(ref.build).unit.plugins.fullClasspath
|
val pluginClasspath = lb.units(ref.build).unit.plugins.fullClasspath
|
||||||
|
|
@ -1695,12 +1762,23 @@ object Classpaths {
|
||||||
def unmanagedDependencies: Initialize[Task[Classpath]] =
|
def unmanagedDependencies: Initialize[Task[Classpath]] =
|
||||||
(thisProjectRef, configuration, settingsData, buildDependencies) flatMap unmanagedDependencies0
|
(thisProjectRef, configuration, settingsData, buildDependencies) flatMap unmanagedDependencies0
|
||||||
def mkIvyConfiguration: Initialize[Task[IvyConfiguration]] =
|
def mkIvyConfiguration: Initialize[Task[IvyConfiguration]] =
|
||||||
(fullResolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, checksums in update, appConfiguration,
|
Def.task {
|
||||||
target, updateOptions, streams) map { (rs, paths, other, moduleConfs, off, check, app, t, uo, s) =>
|
val (rs, other) = (fullResolvers.value.toVector, otherResolvers.value.toVector)
|
||||||
|
val s = streams.value
|
||||||
warnResolversConflict(rs ++: other, s.log)
|
warnResolversConflict(rs ++: other, s.log)
|
||||||
val resCacheDir = t / "resolution-cache"
|
val resCacheDir = crossTarget.value / "resolution-cache"
|
||||||
|
new InlineIvyConfiguration(
|
||||||
new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Option(lock(app)), check, Some(resCacheDir), uo, s.log)
|
ivyPaths.value,
|
||||||
|
rs,
|
||||||
|
other,
|
||||||
|
moduleConfigurations.value.toVector,
|
||||||
|
offline.value,
|
||||||
|
Option(lock(appConfiguration.value)),
|
||||||
|
(checksums in update).value.toVector,
|
||||||
|
Some(resCacheDir),
|
||||||
|
updateOptions.value,
|
||||||
|
s.log
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,8 @@ object Keys {
|
||||||
val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.", CTask)
|
val definedSbtPlugins = TaskKey[Set[String]]("defined-sbt-plugins", "The set of names of Plugin implementations defined by this project.", CTask)
|
||||||
val discoveredSbtPlugins = TaskKey[PluginDiscovery.DiscoveredNames]("discovered-sbt-plugins", "The names of sbt plugin-related modules (modules that extend Build, Plugin, AutoPlugin) defined by this project.", CTask)
|
val discoveredSbtPlugins = TaskKey[PluginDiscovery.DiscoveredNames]("discovered-sbt-plugins", "The names of sbt plugin-related modules (modules that extend Build, Plugin, AutoPlugin) defined by this project.", CTask)
|
||||||
val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.", BMinusSetting)
|
val sbtPlugin = SettingKey[Boolean]("sbt-plugin", "If true, enables adding sbt as a dependency and auto-generation of the plugin descriptor file.", BMinusSetting)
|
||||||
|
val pluginCrossBuild = TaskKey[Unit]("pluginCrossBuild", "Dummy task to scope `sbtVersion in pluginCrossBuild`, which gets used for plugin compilation.")
|
||||||
|
val crossSbtVersions = SettingKey[Seq[String]]("crossSbtVersions", "The versions of Sbt used when cross-building an sbt plugin.")
|
||||||
val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask)
|
val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask)
|
||||||
val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting)
|
val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting)
|
||||||
val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting)
|
val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting)
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,8 @@ object BuiltinCommands {
|
||||||
def ConsoleCommands: Seq[Command] = Seq(ignore, exit, IvyConsole.command, setLogLevel, early, act, nop)
|
def ConsoleCommands: Seq[Command] = Seq(ignore, exit, IvyConsole.command, setLogLevel, early, act, nop)
|
||||||
def ScriptCommands: Seq[Command] = Seq(ignore, exit, Script.command, setLogLevel, early, act, nop)
|
def ScriptCommands: Seq[Command] = Seq(ignore, exit, Script.command, setLogLevel, early, act, nop)
|
||||||
def DefaultCommands: Seq[Command] = Seq(ignore, help, completionsCommand, about, tasks, settingsCommand, loadProject, templateCommand,
|
def DefaultCommands: Seq[Command] = Seq(ignore, help, completionsCommand, about, tasks, settingsCommand, loadProject, templateCommand,
|
||||||
projects, project, reboot, read, history, set, sessionCommand, inspect, loadProjectImpl, loadFailed, Cross.crossBuild, Cross.switchVersion,
|
projects, project, reboot, read, history, set, sessionCommand, inspect, loadProjectImpl, loadFailed,
|
||||||
|
Cross.crossBuild, Cross.switchVersion, PluginCross.pluginCross, PluginCross.pluginSwitch,
|
||||||
setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, setLogLevel, plugin, plugins,
|
setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, setLogLevel, plugin, plugins,
|
||||||
ifLast, multi, shell, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, early, initialize, act) ++
|
ifLast, multi, shell, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, early, initialize, act) ++
|
||||||
compatCommands
|
compatCommands
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* sbt -- Simple Build Tool
|
||||||
|
* Copyright 2011 Mark Harrah
|
||||||
|
* Copyright 2012 Johannes Rudolph
|
||||||
|
*
|
||||||
|
* This was basically copied from the sbt source code and then adapted to use
|
||||||
|
* `sbtVersion in pluginCrossBuild`.
|
||||||
|
*/
|
||||||
|
package sbt
|
||||||
|
|
||||||
|
import complete.DefaultParsers._
|
||||||
|
import complete.Parser
|
||||||
|
import sbt.Keys._
|
||||||
|
import Project._
|
||||||
|
import Scope.GlobalScope
|
||||||
|
import Def.ScopedKey
|
||||||
|
import CommandStrings._
|
||||||
|
import Cross.{ spacedFirst, requireSession }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module responsible for plugin cross building.
|
||||||
|
*/
|
||||||
|
private[sbt] object PluginCross {
|
||||||
|
lazy val pluginSwitch: Command = {
|
||||||
|
def switchParser(state: State): Parser[(String, String)] = {
|
||||||
|
val knownVersions = Nil
|
||||||
|
lazy val switchArgs = token(NotSpace.examples(knownVersions: _*)) ~ (token(Space ~> matched(state.combinedParser)) ?? "")
|
||||||
|
lazy val nextSpaced = spacedFirst(PluginSwitchCommand)
|
||||||
|
token(PluginSwitchCommand ~ OptSpace) flatMap { _ =>
|
||||||
|
switchArgs & nextSpaced
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def crossExclude(s: Def.Setting[_]): Boolean =
|
||||||
|
s.key match {
|
||||||
|
case ScopedKey(Scope(_, _, pluginCrossBuild.key, _), sbtVersion.key) => true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
Command.arb(requireSession(switchParser), pluginSwitchHelp) {
|
||||||
|
case (state, (version, command)) =>
|
||||||
|
val x = Project.extract(state)
|
||||||
|
import x._
|
||||||
|
state.log.info(s"Setting `sbtVersion in pluginCrossBuild` to $version")
|
||||||
|
val add = (sbtVersion in GlobalScope in pluginCrossBuild :== version) :: Nil
|
||||||
|
val cleared = session.mergeSettings.filterNot(crossExclude)
|
||||||
|
val newStructure = Load.reapply(cleared ++ add, structure)
|
||||||
|
Project.setProject(session, newStructure, command :: state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val pluginCross: Command = {
|
||||||
|
def crossParser(state: State): Parser[String] =
|
||||||
|
token(PluginCrossCommand <~ OptSpace) flatMap { _ =>
|
||||||
|
token(matched(state.combinedParser &
|
||||||
|
spacedFirst(PluginCrossCommand)))
|
||||||
|
}
|
||||||
|
def crossVersions(state: State): Seq[String] = {
|
||||||
|
val x = Project.extract(state)
|
||||||
|
import x._
|
||||||
|
crossSbtVersions in currentRef get structure.data getOrElse Nil
|
||||||
|
}
|
||||||
|
Command.arb(requireSession(crossParser), pluginCrossHelp) {
|
||||||
|
case (state, command) =>
|
||||||
|
val x = Project.extract(state)
|
||||||
|
import x._
|
||||||
|
val versions = crossVersions(state)
|
||||||
|
val current = (sbtVersion in pluginCrossBuild)
|
||||||
|
.get(structure.data)
|
||||||
|
.map(PluginSwitchCommand + " " + _).toList
|
||||||
|
if (versions.isEmpty) command :: state
|
||||||
|
else versions.map(PluginSwitchCommand + " " + _ + " " + command) ::: current ::: state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
- Ports sbt-cross-building's `^` and `^^` commands for plugin cross building. See below.
|
||||||
|
|
||||||
|
### sbt-cross-building
|
||||||
|
|
||||||
|
[@jrudolph][@jrudolph]'s sbt-cross-building is a plugin author's plugin.
|
||||||
|
It adds cross command `^` and sbtVersion switch command `^^`, similar to `+` and `++`,
|
||||||
|
but for switching between multiple sbt versions across major versions.
|
||||||
|
sbt 0.13.16 merges these commands into sbt because the feature it provides is useful as we migrate plugins to sbt 1.0.
|
||||||
|
|
||||||
|
To switch the `sbtVersion in pluginCrossBuild` from the shell use:
|
||||||
|
|
||||||
|
```
|
||||||
|
^^ 1.0.0-M5
|
||||||
|
```
|
||||||
|
|
||||||
|
Your plugin will now build with sbt 1.0.0-M5 (and its Scala version 2.12.2).
|
||||||
|
|
||||||
|
If you need to make changes specific to a sbt version, you can now include them into `src/main/scala-sbt-0.13`,
|
||||||
|
and `src/main/scala-sbt-1.0.0-M5`, where the binary sbt version number is used as postfix.
|
||||||
|
|
||||||
|
To run a command across multiple sbt versions, set:
|
||||||
|
|
||||||
|
```scala
|
||||||
|
crossSbtVersions := Vector("0.13.15", "1.0.0-M5")
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
^ compile
|
||||||
|
```
|
||||||
|
|
||||||
|
[@jrudolph]: https://github.com/jrudolph
|
||||||
|
[@eed3si9n]: https://github.com/eed3si9n
|
||||||
|
|
@ -2,6 +2,8 @@ libraryDependencies += "log4j" % "log4j" % "1.2.16" % "compile"
|
||||||
|
|
||||||
autoScalaLibrary := false
|
autoScalaLibrary := false
|
||||||
|
|
||||||
|
crossPaths := false
|
||||||
|
|
||||||
TaskKey[Unit]("check-last-update-time") := (streams map { (s) =>
|
TaskKey[Unit]("check-last-update-time") := (streams map { (s) =>
|
||||||
val fullUpdateOutput = s.cacheDirectory / "out"
|
val fullUpdateOutput = s.cacheDirectory / "out"
|
||||||
val timeDiff = System.currentTimeMillis()-fullUpdateOutput.lastModified()
|
val timeDiff = System.currentTimeMillis()-fullUpdateOutput.lastModified()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
val baseSbt = "0.13"
|
||||||
|
|
||||||
|
lazy val root = (project in file("."))
|
||||||
|
.settings(
|
||||||
|
sbtPlugin := true,
|
||||||
|
|
||||||
|
TaskKey[Unit]("check") := {
|
||||||
|
val crossV = (sbtVersion in pluginCrossBuild).value
|
||||||
|
val sv = projectID.value.extraAttributes("e:scalaVersion")
|
||||||
|
assert(sbtVersion.value startsWith baseSbt, s"Wrong sbt version: ${sbtVersion.value}")
|
||||||
|
assert(sv == "2.10", s"Wrong e:scalaVersion: $sv")
|
||||||
|
assert(scalaBinaryVersion.value == "2.10", s"Wrong Scala binary version: ${scalaBinaryVersion.value}")
|
||||||
|
assert(crossV startsWith "0.13", s"Wrong `sbtVersion in pluginCrossBuild`: $crossV")
|
||||||
|
},
|
||||||
|
|
||||||
|
TaskKey[Unit]("check2") := {
|
||||||
|
val crossV = (sbtVersion in pluginCrossBuild).value
|
||||||
|
val sv = projectID.value.extraAttributes("e:scalaVersion")
|
||||||
|
assert(sbtVersion.value startsWith baseSbt, s"Wrong sbt version: ${sbtVersion.value}")
|
||||||
|
assert(sv == "2.12", s"Wrong e:scalaVersion: $sv")
|
||||||
|
assert(scalaBinaryVersion.value == "2.12", s"Wrong Scala binary version: ${scalaBinaryVersion.value}")
|
||||||
|
assert(crossV startsWith "1.0.", s"Wrong `sbtVersion in pluginCrossBuild`: $crossV")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
> check
|
||||||
|
|
||||||
|
> ^^ 1.0.0-M5
|
||||||
|
|
||||||
|
> check2
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
lazy val root = (project in file("."))
|
||||||
|
.settings(
|
||||||
|
sbtPlugin := true,
|
||||||
|
sbtVersion in pluginCrossBuild := "0.12.4",
|
||||||
|
resolvers += Resolver.typesafeIvyRepo("releases")
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// folder mustn't be included
|
||||||
|
trait B
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
trait A
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
trait B
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
object Test extends A with B
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
// should fail because the project is building for
|
||||||
|
// 0.12.4 where E is not included
|
||||||
|
object ErrorTest extends E
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
> show pluginCrossBuild::sbtDependency
|
||||||
|
> compile
|
||||||
|
-> test:compile
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
lazy val root = (project in file("."))
|
||||||
|
.settings(
|
||||||
|
scriptedSettings,
|
||||||
|
sbtPlugin := true,
|
||||||
|
resolvers += Resolver.typesafeIvyRepo("releases")
|
||||||
|
)
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
# This tests that this sbt scripted plugin can launch the next one
|
# This tests that this sbt scripted plugin can launch the next one
|
||||||
# It is currently disabled because there is no next plugin version
|
# It is currently disabled because it requires JDK8 to run sbt 1.0.
|
||||||
|
|
||||||
|
> ^^1.0.0-M5
|
||||||
|
|
||||||
$ copy-file changes/A.scala src/sbt-test/a/b/A.scala
|
$ copy-file changes/A.scala src/sbt-test/a/b/A.scala
|
||||||
> scripted
|
> scripted
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
libraryDependencies += {
|
||||||
|
"org.scala-sbt" % "scripted-plugin" % sbtVersion.value
|
||||||
|
}
|
||||||
|
|
||||||
|
offline := true
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
scriptedSettings
|
|
||||||
|
|
||||||
scriptedSbt := sbtVersion.value
|
|
||||||
|
|
||||||
sbtPlugin := true
|
|
||||||
|
|
||||||
sbtVersion in Global := "0.13.0-Beta2"
|
|
||||||
|
|
||||||
scalaVersion in Global := "2.10.2-RC2"
|
|
||||||
|
|
||||||
offline := true
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
libraryDependencies += {
|
|
||||||
"org.scala-sbt" %% "scripted-plugin" % sbtVersion.value
|
|
||||||
}
|
|
||||||
|
|
||||||
offline := true
|
|
||||||
|
|
@ -9,6 +9,7 @@ import complete.{ Parser, DefaultParsers }
|
||||||
import classpath.ClasspathUtilities
|
import classpath.ClasspathUtilities
|
||||||
import java.lang.reflect.{ InvocationTargetException, Method }
|
import java.lang.reflect.{ InvocationTargetException, Method }
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
|
import CrossVersion.binarySbtVersion
|
||||||
|
|
||||||
object ScriptedPlugin extends Plugin {
|
object ScriptedPlugin extends Plugin {
|
||||||
def scriptedConf = config("scripted-sbt") hide
|
def scriptedConf = config("scripted-sbt") hide
|
||||||
|
|
@ -97,13 +98,23 @@ object ScriptedPlugin extends Plugin {
|
||||||
|
|
||||||
val scriptedSettings = Seq(
|
val scriptedSettings = Seq(
|
||||||
ivyConfigurations ++= Seq(scriptedConf, scriptedLaunchConf),
|
ivyConfigurations ++= Seq(scriptedConf, scriptedLaunchConf),
|
||||||
scriptedSbt := sbtVersion.value,
|
scriptedSbt := (sbtVersion in pluginCrossBuild).value,
|
||||||
sbtLauncher <<= getJars(scriptedLaunchConf).map(_.get.head),
|
sbtLauncher <<= getJars(scriptedLaunchConf).map(_.get.head),
|
||||||
sbtTestDirectory := sourceDirectory.value / "sbt-test",
|
sbtTestDirectory := sourceDirectory.value / "sbt-test",
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= {
|
||||||
|
binarySbtVersion(scriptedSbt.value) match {
|
||||||
|
case "0.13" =>
|
||||||
|
Seq(
|
||||||
"org.scala-sbt" % "scripted-sbt" % scriptedSbt.value % scriptedConf.toString,
|
"org.scala-sbt" % "scripted-sbt" % scriptedSbt.value % scriptedConf.toString,
|
||||||
"org.scala-sbt" % "sbt-launch" % scriptedSbt.value % scriptedLaunchConf.toString
|
"org.scala-sbt" % "sbt-launch" % scriptedSbt.value % scriptedLaunchConf.toString
|
||||||
),
|
)
|
||||||
|
case sv if sv startsWith "1.0." =>
|
||||||
|
Seq(
|
||||||
|
"org.scala-sbt" %% "scripted-sbt" % scriptedSbt.value % scriptedConf.toString,
|
||||||
|
"org.scala-sbt" % "sbt-launch" % scriptedSbt.value % scriptedLaunchConf.toString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
scriptedBufferLog := true,
|
scriptedBufferLog := true,
|
||||||
scriptedClasspath := getJars(scriptedConf).value,
|
scriptedClasspath := getJars(scriptedConf).value,
|
||||||
scriptedTests <<= scriptedTestsTask,
|
scriptedTests <<= scriptedTestsTask,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue