From 0e979b4a3a0ccbd7c465347c88abf5567b0fdcf6 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 22 Apr 2017 04:12:03 -0400 Subject: [PATCH] Port sbt-cross-building's ^ and ^^ commands This ports sbt-cross-building's cross (`^`) and switch (`^^`) commands. Instead of making it a plugin, the default settings are now changed to use `sbtVersion in pluginCrossBuild` for the sbt dependency. --- main/src/main/scala/sbt/Cross.scala | 4 +- main/src/main/scala/sbt/Defaults.scala | 221 +++++++++++------- main/src/main/scala/sbt/Keys.scala | 2 + main/src/main/scala/sbt/Main.scala | 3 + main/src/main/scala/sbt/PluginCross.scala | 76 ++++++ .../scala/sbt/internal/CommandStrings.scala | 28 +++ notes/0.13.16/sbt-cross-building.markdown | 37 +++ .../force-update-period/build.sbt | 2 + .../project/cross-plugins-defaults/build.sbt | 24 ++ .../project/cross-plugins-defaults/test | 5 + .../project/cross-plugins-source/build.sbt | 6 + .../src/main/scala-sbt-0.13.x/B.scala | 2 + .../src/main/scala-sbt-0.13/A.scala | 1 + .../src/main/scala-sbt-0.13/B.scala | 1 + .../src/main/scala/Test.scala | 1 + .../src/test/scala/TestFile.scala | 3 + .../project/cross-plugins-source/test | 3 + sbt/src/sbt-test/project/scripted13/build.sbt | 16 +- .../project/scripted13/{disabled => test} | 6 +- .../src/main/scala/sbt/ScriptedPlugin.scala | 21 +- 20 files changed, 361 insertions(+), 101 deletions(-) create mode 100644 main/src/main/scala/sbt/PluginCross.scala create mode 100644 notes/0.13.16/sbt-cross-building.markdown create mode 100644 sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt create mode 100644 sbt/src/sbt-test/project/cross-plugins-defaults/test create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/build.sbt create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13.x/B.scala create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/A.scala create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/B.scala create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/src/main/scala/Test.scala create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/src/test/scala/TestFile.scala create mode 100644 sbt/src/sbt-test/project/cross-plugins-source/test rename sbt/src/sbt-test/project/scripted13/{disabled => test} (50%) diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 4b1ec2473..599ece90d 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -24,7 +24,7 @@ import sbt.librarymanagement.CrossVersion object Cross { - private def spacedFirst(name: String) = opOrIDSpaced(name) ~ any.+ + private[sbt] def spacedFirst(name: String) = opOrIDSpaced(name) ~ any.+ private case class Switch(version: ScalaVersion, verbose: Boolean, command: Option[String]) private trait ScalaVersion { @@ -77,7 +77,7 @@ object Cross { private def crossRestoreSessionParser(state: State): Parser[String] = token(CrossRestoreSessionCommand) - private def requireSession[T](p: State => Parser[T]): State => Parser[T] = + private[sbt] def requireSession[T](p: State => Parser[T]): State => Parser[T] = s => if (s get sessionSettings isEmpty) failure("No project loaded") else p(s) private def resolveAggregates(extracted: Extracted): Seq[ProjectRef] = { diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index ce673117c..7933200be 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -218,6 +218,10 @@ object Defaults extends BuildCommon { envVars :== Map.empty, sbtVersion := appConfiguration.value.provider.id.version, 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, triggeredMessage := Watched.defaultTriggeredMessage, onLoad := idFun[State], @@ -293,10 +297,16 @@ object Defaults extends BuildCommon { sourceManaged := configSrcSub(sourceManaged).value, scalaSource := sourceDirectory.value / "scala", 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, @@ -349,9 +359,22 @@ object Defaults extends BuildCommon { ), scalaInstance := scalaInstanceTask.value, crossVersion := (if (crossPaths.value) CrossVersion.binary else Disabled()), + scalaVersion := { + val scalaV = scalaVersion.value + val sv = (sbtBinaryVersion in pluginCrossBuild).value + val isPlugin = sbtPlugin.value + if (isPlugin) { + val x = scalaVersionFromSbtBinaryVersion(sv) + println(s"scalaVersionFromSbtBinaryVersion($sv) = $x") + x + } else scalaV + }, + sbtBinaryVersion in pluginCrossBuild := binarySbtVersion( + (sbtVersion in pluginCrossBuild).value), + crossSbtVersions := Vector((sbtVersion in pluginCrossBuild).value), crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, - sbtBinaryVersion.value, + (sbtBinaryVersion in pluginCrossBuild).value, sbtPlugin.value, crossPaths.value), clean := { @@ -359,6 +382,8 @@ object Defaults extends BuildCommon { IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log) }, scalaCompilerBridgeSource := { + // This is a workaround for sbtVersion getting set to another value. + val sv = appConfiguration.value.provider.id.version if (ScalaInstance.isDotty(scalaVersion.value)) // Maintained at https://github.com/lampepfl/dotty/tree/master/sbt-bridge ModuleID(scalaOrganization.value, "dotty-sbt-bridge", scalaVersion.value) @@ -382,6 +407,14 @@ object Defaults extends BuildCommon { 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, @@ -392,6 +425,15 @@ object Defaults extends BuildCommon { 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 = { val scalaBase = if (cross) t / ("scala-" + sv) else t if (plugin) scalaBase / ("sbt-" + sbtv) else scalaBase @@ -1470,7 +1512,20 @@ object Defaults extends BuildCommon { projectCore ++ disableAggregation ++ Seq( // Missing but core settings 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 Disabled() + val base = ModuleID(id.groupID, id.name, sv).withCrossVersion(cross) + CrossVersion(scalaV, binVersion)(base).withCrossVersion(Disabled()) + } ) // 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[_]] = @@ -1884,8 +1939,11 @@ object Classpaths { allDependencies := { val base = projectDependencies.value ++ libraryDependencies.value val dependency = sbtDependency.value + val isPlugin = sbtPlugin.value + val sbtdeps = + (sbtDependency in pluginCrossBuild).value.withConfigurations(Some(Provided.name)) val pluginAdjust = - if (sbtPlugin.value) dependency.withConfigurations(Some(Provided.name)) +: base + if (isPlugin) sbtdeps +: base else base val sbtOrg = scalaOrganization.value val version = scalaVersion.value @@ -1919,8 +1977,8 @@ object Classpaths { Def.setting { if (sbtPlugin.value) sbtPluginExtra(projectID.value, - (sbtBinaryVersion in update).value, - (scalaBinaryVersion in update).value) + (sbtBinaryVersion in pluginCrossBuild).value, + (scalaBinaryVersion in pluginCrossBuild).value) else projectID.value } private[sbt] def ivySbt0: Initialize[Task[IvySbt]] = @@ -1950,77 +2008,78 @@ object Classpaths { transitiveClassifiers in updateSbtClassifiers ~= (_.filter(_ != DocClassifier)) )) def sbtClassifiersTasks = - sbtClassifiersGlobalDefaults ++ inTask(updateSbtClassifiers)( - Seq( - externalResolvers := { - val explicit = buildStructure.value - .units(thisProjectRef.value.build) - .unit - .plugins - .pluginData - .resolvers - explicit orElse bootRepositories(appConfiguration.value) getOrElse externalResolvers.value - }, - ivyConfiguration := new InlineIvyConfiguration( - ivyPaths.value, - externalResolvers.value.toVector, - Vector.empty, - Vector.empty, - offline.value, - Option(lock(appConfiguration.value)), - checksums.value.toVector, - Some(target.value / "resolution-cache"), - UpdateOptions(), - streams.value.log - ), - ivySbt := ivySbt0.value, - classifiersModule := classifiersModuleTask.value, - // Redefine scalaVersion and scalaBinaryVersion specifically for the dependency graph used for updateSbtClassifiers task. - // to fix https://github.com/sbt/sbt/issues/2686 - scalaVersion := appConfiguration.value.provider.scalaProvider.version, - scalaBinaryVersion := binaryScalaVersion(scalaVersion.value), - ivyScala := { - Some( - IvyScala(scalaVersion.value, - scalaBinaryVersion.value, - Vector(), - checkExplicit = false, - filterImplicit = false, - overrideScalaVersion = true).withScalaOrganization(scalaOrganization.value)) - }, - updateSbtClassifiers in TaskGlobal := (Def.task { - val s = streams.value - val is = ivySbt.value - val mod = classifiersModule.value - val c = updateConfiguration.value - val app = appConfiguration.value - val srcTypes = sourceArtifactTypes.value - val docTypes = docArtifactTypes.value - val log = s.log - val out = is.withIvy(log)(_.getSettings.getDefaultIvyUserDir) - val uwConfig = (unresolvedWarningConfiguration in update).value - val depDir = dependencyCacheDirectory.value - val ivy = ivyScala.value - val st = state.value - withExcludes(out, mod.classifiers, lock(app)) { excludes => - val noExplicitCheck = ivy.map(_.withCheckExplicit(false)) - IvyActions.transitiveScratch( - is, - "sbt", - GetClassifiersConfiguration(mod, - excludes, - c.withArtifactFilter(c.artifactFilter.invert), - noExplicitCheck, - srcTypes, - docTypes), - uwConfig, - LogicalClock(st.hashCode), - Some(depDir), - log - ) - } - } tag (Tags.Update, Tags.Network)).value - )) ++ Seq(bootIvyConfiguration := (ivyConfiguration in updateSbtClassifiers).value) + sbtClassifiersGlobalDefaults ++ + inTask(updateSbtClassifiers)( + Seq( + externalResolvers := { + val explicit = buildStructure.value + .units(thisProjectRef.value.build) + .unit + .plugins + .pluginData + .resolvers + explicit orElse bootRepositories(appConfiguration.value) getOrElse externalResolvers.value + }, + ivyConfiguration := new InlineIvyConfiguration( + 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, + classifiersModule := classifiersModuleTask.value, + // Redefine scalaVersion and scalaBinaryVersion specifically for the dependency graph used for updateSbtClassifiers task. + // to fix https://github.com/sbt/sbt/issues/2686 + scalaVersion := appConfiguration.value.provider.scalaProvider.version, + scalaBinaryVersion := binaryScalaVersion(scalaVersion.value), + ivyScala := { + Some( + IvyScala(scalaVersion.value, + scalaBinaryVersion.value, + Vector(), + checkExplicit = false, + filterImplicit = false, + overrideScalaVersion = true).withScalaOrganization(scalaOrganization.value)) + }, + updateSbtClassifiers in TaskGlobal := (Def.task { + val s = streams.value + val is = ivySbt.value + val mod = classifiersModule.value + val c = updateConfiguration.value + val app = appConfiguration.value + val srcTypes = sourceArtifactTypes.value + val docTypes = docArtifactTypes.value + val log = s.log + val out = is.withIvy(log)(_.getSettings.getDefaultIvyUserDir) + val uwConfig = (unresolvedWarningConfiguration in update).value + val depDir = dependencyCacheDirectory.value + val ivy = ivyScala.value + val st = state.value + withExcludes(out, mod.classifiers, lock(app)) { excludes => + val noExplicitCheck = ivy.map(_.withCheckExplicit(false)) + IvyActions.transitiveScratch( + is, + "sbt", + GetClassifiersConfiguration(mod, + excludes, + c.withArtifactFilter(c.artifactFilter.invert), + noExplicitCheck, + srcTypes, + docTypes), + uwConfig, + LogicalClock(st.hashCode), + Some(depDir), + log + ) + } + } tag (Tags.Update, Tags.Network)).value + )) ++ Seq(bootIvyConfiguration := (ivyConfiguration in updateSbtClassifiers).value) def classifiersModuleTask: Initialize[Task[GetClassifiersModule]] = Def.task { @@ -2433,7 +2492,7 @@ object Classpaths { val (rs, other) = (fullResolvers.value.toVector, otherResolvers.value.toVector) val s = streams.value warnResolversConflict(rs ++: other, s.log) - val resCacheDir = target.value / "resolution-cache" + val resCacheDir = crossTarget.value / "resolution-cache" new InlineIvyConfiguration( ivyPaths.value, rs, diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 24b69956d..95cd444b0 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -200,6 +200,8 @@ object Keys { val classpathOptions = SettingKey[ClasspathOptions]("classpath-options", "Configures handling of Scala classpaths.", DSetting) 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 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 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) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 18511a428..ce8f2c59f 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -205,6 +205,7 @@ object BuiltinCommands { 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) @@ -230,6 +231,8 @@ object BuiltinCommands { loadFailed, Cross.crossBuild, Cross.switchVersion, + PluginCross.pluginCross, + PluginCross.pluginSwitch, Cross.crossRestoreSession, setOnFailure, clearOnFailure, diff --git a/main/src/main/scala/sbt/PluginCross.scala b/main/src/main/scala/sbt/PluginCross.scala new file mode 100644 index 000000000..b83e5294d --- /dev/null +++ b/main/src/main/scala/sbt/PluginCross.scala @@ -0,0 +1,76 @@ +/* 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 sbt.internal.util.complete.{ Parser, DefaultParsers } +import DefaultParsers._ +import sbt.Keys._ +import Project._ +import Scope.GlobalScope +import Def.ScopedKey +import sbt.internal.Load +import sbt.internal.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): List[String] = { + val x = Project.extract(state) + import x._ + ((crossSbtVersions in currentRef) get structure.data getOrElse Nil).toList + } + 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 + } + } +} diff --git a/main/src/main/scala/sbt/internal/CommandStrings.scala b/main/src/main/scala/sbt/internal/CommandStrings.scala index db54be31a..7b49966fe 100644 --- a/main/src/main/scala/sbt/internal/CommandStrings.scala +++ b/main/src/main/scala/sbt/internal/CommandStrings.scala @@ -373,4 +373,32 @@ $SwitchCommand [=][!] [-v] [] 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 + Runs 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 . When finished, it reloads the build with the original + Scala version. + + See also `help $PluginSwitchCommand` +""" + + def PluginSwitchDetailed = + s"""$PluginSwitchCommand [] + Changes the sbt version and runs a command. + + Sets the `sbtVersion in pluginCrossBuild` of all projects to and + reloads the build. If is provided, it is then executed. + + See also `help $CrossCommand` +""" } diff --git a/notes/0.13.16/sbt-cross-building.markdown b/notes/0.13.16/sbt-cross-building.markdown new file mode 100644 index 000000000..e389a17bc --- /dev/null +++ b/notes/0.13.16/sbt-cross-building.markdown @@ -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 diff --git a/sbt/src/sbt-test/dependency-management/force-update-period/build.sbt b/sbt/src/sbt-test/dependency-management/force-update-period/build.sbt index aa69bcfa2..1912a7fbb 100644 --- a/sbt/src/sbt-test/dependency-management/force-update-period/build.sbt +++ b/sbt/src/sbt-test/dependency-management/force-update-period/build.sbt @@ -2,6 +2,8 @@ libraryDependencies += "log4j" % "log4j" % "1.2.16" % "compile" autoScalaLibrary := false +crossPaths := false + TaskKey[Unit]("check-last-update-time") := (streams map { (s) => val fullUpdateOutput = s.cacheDirectory / "out" val timeDiff = System.currentTimeMillis()-fullUpdateOutput.lastModified() diff --git a/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt b/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt new file mode 100644 index 000000000..2b0ed7105 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt @@ -0,0 +1,24 @@ +val baseSbt = "1.0" + +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.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") + }, + + 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.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") + } + ) diff --git a/sbt/src/sbt-test/project/cross-plugins-defaults/test b/sbt/src/sbt-test/project/cross-plugins-defaults/test new file mode 100644 index 000000000..15a55b859 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-defaults/test @@ -0,0 +1,5 @@ +> check + +> ^^0.13.15 + +> check2 diff --git a/sbt/src/sbt-test/project/cross-plugins-source/build.sbt b/sbt/src/sbt-test/project/cross-plugins-source/build.sbt new file mode 100644 index 000000000..874d2da9d --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/build.sbt @@ -0,0 +1,6 @@ +lazy val root = (project in file(".")) + .settings( + sbtPlugin := true, + sbtVersion in pluginCrossBuild := "0.13.15", + resolvers += Resolver.typesafeIvyRepo("releases") + ) diff --git a/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13.x/B.scala b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13.x/B.scala new file mode 100644 index 000000000..0ed0a40b8 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13.x/B.scala @@ -0,0 +1,2 @@ +// folder mustn't be included +trait B diff --git a/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/A.scala b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/A.scala new file mode 100644 index 000000000..16c5ea484 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/A.scala @@ -0,0 +1 @@ +trait A \ No newline at end of file diff --git a/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/B.scala b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/B.scala new file mode 100644 index 000000000..1e59c35e7 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala-sbt-0.13/B.scala @@ -0,0 +1 @@ +trait B diff --git a/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala/Test.scala b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala/Test.scala new file mode 100644 index 000000000..3dc251c35 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/src/main/scala/Test.scala @@ -0,0 +1 @@ +object Test extends A with B \ No newline at end of file diff --git a/sbt/src/sbt-test/project/cross-plugins-source/src/test/scala/TestFile.scala b/sbt/src/sbt-test/project/cross-plugins-source/src/test/scala/TestFile.scala new file mode 100644 index 000000000..e2d081a36 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/src/test/scala/TestFile.scala @@ -0,0 +1,3 @@ +// should fail because the project is building for +// 0.13.15 where E is not included +object ErrorTest extends E diff --git a/sbt/src/sbt-test/project/cross-plugins-source/test b/sbt/src/sbt-test/project/cross-plugins-source/test new file mode 100644 index 000000000..f3f14e7b2 --- /dev/null +++ b/sbt/src/sbt-test/project/cross-plugins-source/test @@ -0,0 +1,3 @@ +> show pluginCrossBuild::sbtDependency +> compile +-> test:compile diff --git a/sbt/src/sbt-test/project/scripted13/build.sbt b/sbt/src/sbt-test/project/scripted13/build.sbt index 45efde4f0..8a7182a4c 100644 --- a/sbt/src/sbt-test/project/scripted13/build.sbt +++ b/sbt/src/sbt-test/project/scripted13/build.sbt @@ -1,11 +1,5 @@ -scriptedSettings - -scriptedSbt := sbtVersion.value - -sbtPlugin := true - -sbtVersion in Global := "0.13.0-Beta2" - -scalaVersion in Global := "2.10.2-RC2" - -offline := true +lazy val root = (project in file(".")) + .settings( + sbtPlugin := true, + resolvers += Resolver.typesafeIvyRepo("releases") + ) diff --git a/sbt/src/sbt-test/project/scripted13/disabled b/sbt/src/sbt-test/project/scripted13/test similarity index 50% rename from sbt/src/sbt-test/project/scripted13/disabled rename to sbt/src/sbt-test/project/scripted13/test index 3d9d074ff..7cf13e886 100644 --- a/sbt/src/sbt-test/project/scripted13/disabled +++ b/sbt/src/sbt-test/project/scripted13/test @@ -1,5 +1,7 @@ -# This tests that this sbt scripted plugin can launch the next one -# It is currently disabled because there is no next plugin version +# This tests that this sbt scripted plugin can launch the previous one + +> ++2.10.6 +> ^^0.13.16-M1 $ copy-file changes/A.scala src/sbt-test/a/b/A.scala > scripted diff --git a/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala b/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala index 7aa4edcc0..7bbf934b4 100644 --- a/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala +++ b/scripted/plugin/src/main/scala/sbt/ScriptedPlugin.scala @@ -9,6 +9,7 @@ import sbt.internal.util.complete.{ Parser, DefaultParsers } import sbt.internal.inc.classpath.ClasspathUtilities import sbt.internal.inc.ModuleUtilities import java.lang.reflect.Method +import sbt.librarymanagement.CrossVersion.binarySbtVersion object ScriptedPlugin extends AutoPlugin { override def requires = plugins.JvmPlugin @@ -32,13 +33,23 @@ object ScriptedPlugin extends AutoPlugin { import autoImport._ override lazy val projectSettings = Seq( ivyConfigurations ++= Seq(scriptedConf, scriptedLaunchConf), - scriptedSbt := sbtVersion.value, + scriptedSbt := (sbtVersion in pluginCrossBuild).value, sbtLauncher := getJars(scriptedLaunchConf).map(_.get.head).value, sbtTestDirectory := sourceDirectory.value / "sbt-test", - libraryDependencies ++= Seq( - "org.scala-sbt" %% "scripted-sbt" % scriptedSbt.value % scriptedConf.toString, - "org.scala-sbt" % "sbt-launch" % scriptedSbt.value % scriptedLaunchConf.toString - ), + libraryDependencies ++= { + binarySbtVersion(scriptedSbt.value) match { + case "0.13" => + Seq( + "org.scala-sbt" % "scripted-sbt" % scriptedSbt.value % scriptedConf.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, scriptedClasspath := getJars(scriptedConf).value, scriptedTests := scriptedTestsTask.value,