diff --git a/.travis.yml b/.travis.yml index b0026deac..d180a58ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,9 @@ env: - SBT_CMD="scripted java/* package/* reporter/* run/* project-load/*" - SBT_CMD="scripted project/*1of2" - SBT_CMD="scripted project/*2of2" - - SBT_CMD="scripted source-dependencies/*" + - SBT_CMD="scripted source-dependencies/*1of3" + - SBT_CMD="scripted source-dependencies/*2of3" + - SBT_CMD="scripted source-dependencies/*3of3" - SBT_CMD="scripted tests/*" - SBT_CMD="repoOverrideTest:scripted dependency-management/*" diff --git a/build.sbt b/build.sbt index 2be47d5f0..2affa420a 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,7 @@ import Util._ import Dependencies._ import Sxr.sxr +import com.typesafe.tools.mima.core._, ProblemFilters._ // ThisBuild settings take lower precedence, // but can be shared across the multi projects. @@ -66,7 +67,7 @@ def testedBaseSettings: Seq[Setting[_]] = val mimaSettings = Def settings ( mimaPreviousArtifacts := Set( - organization.value % moduleName.value % "1.0.0-RC3" + organization.value % moduleName.value % "1.0.0" cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled) ) ) @@ -382,9 +383,18 @@ lazy val sbtProj = (project in file("sbt")) crossScalaVersions := Seq(baseScalaVersion), crossPaths := false, mimaSettings, + mimaBinaryIssueFilters ++= sbtIgnoredProblems, ) .configure(addSbtCompilerBridge) +lazy val sbtIgnoredProblems = { + Seq( + // Added more items to Import trait. + exclude[ReversedMissingMethodProblem]("sbt.Import.sbt$Import$_setter_$WatchSource_="), + exclude[ReversedMissingMethodProblem]("sbt.Import.WatchSource") + ) +} + def scriptedTask: Def.Initialize[InputTask[Unit]] = Def.inputTask { val result = scriptedSource(dir => (s: State) => Scripted.scriptedParser(dir)).parsed // publishLocalBinAll.value // TODO: Restore scripted needing only binary jars. diff --git a/main-command/src/main/scala/sbt/Watched.scala b/main-command/src/main/scala/sbt/Watched.scala index d65a32708..08a1c5838 100644 --- a/main-command/src/main/scala/sbt/Watched.scala +++ b/main-command/src/main/scala/sbt/Watched.scala @@ -6,11 +6,12 @@ package sbt import BasicCommandStrings.ClearOnFailure import State.FailureWall import annotation.tailrec +import java.io.File import java.nio.file.FileSystems import scala.concurrent.duration._ -import sbt.io.WatchService +import sbt.io.{ AllPassFilter, NothingFilter, FileFilter, WatchService } import sbt.internal.io.{ Source, SourceModificationWatch, WatchState } import sbt.internal.util.AttributeKey import sbt.internal.util.Types.const @@ -18,7 +19,7 @@ import sbt.internal.util.Types.const trait Watched { /** The files watched when an action is run with a preceeding ~ */ - def watchSources(s: State): Seq[Source] = Nil + def watchSources(s: State): Seq[Watched.WatchSource] = Nil def terminateWatch(key: Int): Boolean = Watched.isEnter(key) /** @@ -44,6 +45,30 @@ object Watched { val clearWhenTriggered: WatchState => String = const(clearScreen) def clearScreen: String = "\u001b[2J\u001b[0;0H" + type WatchSource = Source + object WatchSource { + + /** + * Creates a new `WatchSource` for watching files, with the given filters. + * + * @param base The base directory from which to include files. + * @param includeFilter Choose what children of `base` to include. + * @param excludeFilter Choose what children of `base` to exclude. + * @return An instance of `Source`. + */ + def apply(base: File, includeFilter: FileFilter, excludeFilter: FileFilter): Source = + new Source(base, includeFilter, excludeFilter) + + /** + * Creates a new `WatchSource` for watching files. + * + * @param base The base directory from which to include files. + * @return An instance of `Source`. + */ + def apply(base: File): Source = + apply(base, AllPassFilter, NothingFilter) + } + private[this] class AWatched extends Watched def multi(base: Watched, paths: Seq[Watched]): Watched = diff --git a/main-settings/src/main/scala/sbt/Append.scala b/main-settings/src/main/scala/sbt/Append.scala index 4b2c1987f..bb50f52fa 100644 --- a/main-settings/src/main/scala/sbt/Append.scala +++ b/main-settings/src/main/scala/sbt/Append.scala @@ -6,6 +6,8 @@ import scala.annotation.implicitNotFound import sbt.internal.util.Attributed import Def.Initialize import reflect.internal.annotations.compileTimeOnly +import sbt.internal.io.Source +import sbt.io.{ AllPassFilter, NothingFilter } object Append { @implicitNotFound( @@ -96,4 +98,11 @@ object Append { def appendValue(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a :+ _) def appendValues(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a :+ _) } + implicit def appendSource: Sequence[Seq[Source], Seq[File], File] = + new Sequence[Seq[Source], Seq[File], File] { + def appendValue(a: Seq[Source], b: File): Seq[Source] = + appendValues(a, Seq(b)) + def appendValues(a: Seq[Source], b: Seq[File]): Seq[Source] = + a ++ b.map(new Source(_, AllPassFilter, NothingFilter)) + } } diff --git a/main/src/main/scala/sbt/BackgroundJobService.scala b/main/src/main/scala/sbt/BackgroundJobService.scala index 58d3f25e1..7b7b30955 100644 --- a/main/src/main/scala/sbt/BackgroundJobService.scala +++ b/main/src/main/scala/sbt/BackgroundJobService.scala @@ -5,6 +5,7 @@ import sbt.util.Logger import Def.{ ScopedKey, Classpath } import sbt.internal.util.complete._ import java.io.File +import scala.util.Try abstract class BackgroundJobService extends Closeable { @@ -24,6 +25,12 @@ abstract class BackgroundJobService extends Closeable { def shutdown(): Unit def jobs: Vector[JobHandle] def stop(job: JobHandle): Unit + + def waitForTry(job: JobHandle): Try[Unit] = { + // This implementation is provided only for backward compatibility. + Try(waitFor(job)) + } + def waitFor(job: JobHandle): Unit /** Copies classpath to temporary directories. */ diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 599ece90d..8cd7720b7 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -3,7 +3,7 @@ */ package sbt -import Keys._ +import Keys.{ version, _ } import sbt.internal.util.complete.{ DefaultParsers, Parser } import sbt.internal.util.AttributeKey import DefaultParsers._ @@ -18,6 +18,7 @@ import sbt.internal.CommandStrings.{ } import java.io.File +import sbt.internal.Act import sbt.internal.inc.ScalaInstance import sbt.io.IO import sbt.librarymanagement.CrossVersion @@ -125,10 +126,13 @@ object Cross { case Left(cmd) => (resolveAggregates(x), cmd) } + val projCrossVersions = aggs map { proj => + proj -> crossVersions(x, proj) + } // if we support scalaVersion, projVersions should be cached somewhere since // running ++2.11.1 is at the root level is going to mess with the scalaVersion for the aggregated subproj - val projVersions = (aggs flatMap { proj => - crossVersions(x, proj) map { (proj.project, _) } + val projVersions = (projCrossVersions flatMap { + case (proj, versions) => versions map { proj.project -> _ } }).toList val verbose = if (args.verbose) "-v" else "" @@ -136,19 +140,51 @@ object Cross { if (projVersions.isEmpty) { state } else { - // Group all the projects by scala version - val allCommands = projVersions.groupBy(_._2).mapValues(_.map(_._1)).toSeq.flatMap { - case (version, Seq(project)) => - // If only one project for a version, issue it directly - Seq(s"$SwitchCommand $verbose $version $project/$aggCommand") - case (version, projects) if aggCommand.contains(" ") => - // If the command contains a space, then the all command won't work because it doesn't support issuing - // commands with spaces, so revert to running the command on each project one at a time - s"$SwitchCommand $verbose $version" :: projects.map(project => s"$project/$aggCommand") - case (version, projects) => - // First switch scala version, then use the all command to run the command on each project concurrently - Seq(s"$SwitchCommand $verbose $version", - projects.map(_ + "/" + aggCommand).mkString("all ", " ", "")) + // Detect whether a task or command has been issued + val allCommands = Parser.parse(aggCommand, Act.aggregatedKeyParser(x)) match { + case Left(_) => + // It's definitely not a task, check if it's a valid command, because we don't want to emit the warning + // message below for typos. + val validCommand = Parser.parse(aggCommand, state.combinedParser).isRight + + val distinctCrossConfigs = projCrossVersions.map(_._2.toSet).distinct + if (validCommand && distinctCrossConfigs.size > 1) { + state.log.warn( + "Issuing a cross building command, but not all sub projects have the same cross build " + + "configuration. This could result in subprojects cross building against Scala versions that they are " + + "not compatible with. Try issuing cross building command with tasks instead, since sbt will be able " + + "to ensure that cross building is only done using configured project and Scala version combinations " + + "that are configured.") + state.log.debug("Scala versions configuration is:") + projCrossVersions.foreach { + case (project, versions) => state.log.debug(s"$project: $versions") + } + } + + // Execute using a blanket switch + projCrossVersions.toMap.apply(currentRef).flatMap { version => + // Force scala version + Seq(s"$SwitchCommand $verbose $version!", aggCommand) + } + + case Right(_) => + // We have a key, we're likely to be able to cross build this using the per project behaviour. + + // Group all the projects by scala version + projVersions.groupBy(_._2).mapValues(_.map(_._1)).toSeq.flatMap { + case (version, Seq(project)) => + // If only one project for a version, issue it directly + Seq(s"$SwitchCommand $verbose $version $project/$aggCommand") + case (version, projects) if aggCommand.contains(" ") => + // If the command contains a space, then the `all` command won't work because it doesn't support issuing + // commands with spaces, so revert to running the command on each project one at a time + s"$SwitchCommand $verbose $version" :: projects.map(project => + s"$project/$aggCommand") + case (version, projects) => + // First switch scala version, then use the all command to run the command on each project concurrently + Seq(s"$SwitchCommand $verbose $version", + projects.map(_ + "/" + aggCommand).mkString("all ", " ", "")) + } } allCommands.toList ::: CrossRestoreSessionCommand :: captureCurrentSession(state, x) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index d2153cc41..d4f5ba1f2 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -316,7 +316,9 @@ object Defaults extends BuildCommon { includeFilter in unmanagedSources, excludeFilter in unmanagedSources).value, watchSources in ConfigGlobal ++= { - val bases = unmanagedSourceDirectories.value + val baseDir = baseDirectory.value + val bases = unmanagedSourceDirectories.value ++ (if (sourcesInBase.value) Seq(baseDir) + else Seq.empty) val include = (includeFilter in unmanagedSources).value val exclude = (excludeFilter in unmanagedSources).value bases.map(b => new Source(b, include, exclude)) @@ -388,14 +390,7 @@ object Defaults extends BuildCommon { val _ = clean.value IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log) }, - scalaCompilerBridgeSource := { - if (ScalaInstance.isDotty(scalaVersion.value)) - // Maintained at https://github.com/lampepfl/dotty/tree/master/sbt-bridge - ModuleID(scalaOrganization.value, "dotty-sbt-bridge", scalaVersion.value) - .withConfigurations(Some("component")) - .sources() - else ZincUtil.getDefaultBridgeModule(scalaVersion.value) - } + scalaCompilerBridgeSource := ZincUtil.getDefaultBridgeModule(scalaVersion.value) ) // must be a val: duplication detected by object identity private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults( @@ -501,8 +496,8 @@ object Defaults extends BuildCommon { selectMainClass := mainClass.value orElse askForMainClass(discoveredMainClasses.value), mainClass in run := (selectMainClass in run).value, mainClass := pickMainClassOrWarn(discoveredMainClasses.value, streams.value.log), - runMain := runMainTask(fullClasspath, runner in run).evaluated, - run := runTask(fullClasspath, mainClass in run, runner in run).evaluated, + runMain := foregroundRunMainTask.evaluated, + run := foregroundRunTask.evaluated, copyResources := copyResourcesTask.value, // note that we use the same runner and mainClass as plain run bgRunMain := bgRunMainTask(exportedProductJars, @@ -1166,14 +1161,14 @@ object Defaults extends BuildCommon { Def.inputTask { val handle = bgRunMain.evaluated val service = bgJobService.value - service.waitFor(handle) + service.waitForTry(handle).get } // run calls bgRun in the background and waits for the result. def foregroundRunTask: Initialize[InputTask[Unit]] = Def.inputTask { val handle = bgRun.evaluated val service = bgJobService.value - service.waitFor(handle) + service.waitForTry(handle).get } def runMainTask(classpath: Initialize[Task[Classpath]], scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = { @@ -1538,8 +1533,11 @@ object Defaults extends BuildCommon { lazy val configSettings : Seq[Setting[_]] = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig ++ deprecationSettings - lazy val compileSettings - : Seq[Setting[_]] = configSettings ++ (mainBgRunMainTask +: mainBgRunTask +: addBaseSources) ++ Classpaths.addUnmanagedLibrary + lazy val compileSettings: Seq[Setting[_]] = + configSettings ++ + (mainBgRunMainTask +: mainBgRunTask +: addBaseSources) ++ + Classpaths.addUnmanagedLibrary + lazy val testSettings: Seq[Setting[_]] = configSettings ++ testTasks lazy val itSettings: Seq[Setting[_]] = inConfig(IntegrationTest)(testSettings) @@ -2961,7 +2959,7 @@ trait BuildExtra extends BuildCommon with DefExtra { */ def addSbtPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] = libraryDependencies += { - val sbtV = (sbtBinaryVersion in update).value + val sbtV = (sbtBinaryVersion in pluginCrossBuild).value val scalaV = (scalaBinaryVersion in update).value sbtPluginExtra(dependency, sbtV, scalaV) } diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index d85a131fc..a011fd938 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -37,7 +37,7 @@ import sbt.internal.{ LogManager } import sbt.io.{ FileFilter, WatchService } -import sbt.internal.io.{ Source, WatchState } +import sbt.internal.io.WatchState import sbt.internal.util.{ AttributeKey, SourcePosition } import sbt.librarymanagement.Configurations.CompilerPlugin @@ -132,8 +132,8 @@ object Keys { val suppressSbtShellNotification = settingKey[Boolean]("""True to suppress the "Executing in batch mode.." message.""").withRank(CSetting) val pollInterval = settingKey[FiniteDuration]("Interval between checks for modified sources by the continuous execution command.").withRank(BMinusSetting) val watchService = settingKey[() => WatchService]("Service to use to monitor file system changes.").withRank(BMinusSetting) - val watchSources = taskKey[Seq[Source]]("Defines the sources in this project for continuous execution to watch for changes.").withRank(BMinusSetting) - val watchTransitiveSources = taskKey[Seq[Source]]("Defines the sources in all projects for continuous execution to watch.").withRank(CSetting) + val watchSources = taskKey[Seq[Watched.WatchSource]]("Defines the sources in this project for continuous execution to watch for changes.").withRank(BMinusSetting) + val watchTransitiveSources = taskKey[Seq[Watched.WatchSource]]("Defines the sources in all projects for continuous execution to watch.").withRank(CSetting) val watchingMessage = settingKey[WatchState => String]("The message to show when triggered execution waits for sources to change.").withRank(DSetting) val triggeredMessage = settingKey[WatchState => String]("The message to show before triggered execution executes an action after sources change.").withRank(DSetting) diff --git a/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala b/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala index b2680a729..ea08836a9 100644 --- a/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala +++ b/main/src/main/scala/sbt/internal/DefaultBackgroundJobService.scala @@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicLong import java.io.Closeable import Def.{ ScopedKey, Setting, Classpath } import scala.concurrent.ExecutionContext +import scala.util.Try import Scope.GlobalScope import java.io.File import sbt.io.{ IO, Hash } @@ -18,6 +19,13 @@ import sbt.internal.util.{ Attributed, ManagedLogger } private[sbt] abstract class BackgroundJob { def humanReadableName: String def awaitTermination(): Unit + + /** This waits till the job ends, and returns inner error via `Try`. */ + def awaitTerminationTry(): Try[Unit] = { + // This implementation is provided only for backward compatibility. + Try(awaitTermination()) + } + def shutdown(): Unit // this should be true on construction and stay true until // the job is complete @@ -132,15 +140,27 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe private def withHandle(job: JobHandle)(f: ThreadJobHandle => Unit): Unit = job match { case handle: ThreadJobHandle @unchecked => f(handle) - case dead: DeadHandle @unchecked => () // nothing to stop or wait for + case _: DeadHandle @unchecked => () // nothing to stop or wait for case other => sys.error( s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other") } + private def withHandleTry(job: JobHandle)(f: ThreadJobHandle => Try[Unit]): Try[Unit] = + job match { + case handle: ThreadJobHandle @unchecked => f(handle) + case _: DeadHandle @unchecked => Try(()) // nothing to stop or wait for + case other => + Try(sys.error( + s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other")) + } + override def stop(job: JobHandle): Unit = withHandle(job)(_.job.shutdown()) + override def waitForTry(job: JobHandle): Try[Unit] = + withHandleTry(job)(_.job.awaitTerminationTry()) + override def waitFor(job: JobHandle): Unit = withHandle(job)(_.job.awaitTermination()) @@ -212,6 +232,9 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable { @volatile private var status: Status = Waiting + // This is used to capture exceptions that are caught in this background job. + private var exitTry: Option[Try[Unit]] = None + // double-finally for extra paranoia that we will finishedLatch.countDown override def run() = try { @@ -226,7 +249,11 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable { throw new RuntimeException("Impossible status of bg thread") } } - try { if (go) body() } finally cleanup() + try { + if (go) { + exitTry = Option(Try(body())) + } + } finally cleanup() } finally finishedLatch.countDown() private class StopListener(val callback: () => Unit, val executionContext: ExecutionContext) @@ -269,6 +296,12 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable { result } override def awaitTermination(): Unit = finishedLatch.await() + + override def awaitTerminationTry(): Try[Unit] = { + awaitTermination() + exitTry.getOrElse(Try(())) + } + override def humanReadableName: String = taskName override def isRunning(): Boolean = status match { diff --git a/notes/0.13.17/addSbtPlugin-cross.markdown b/notes/0.13.17/addSbtPlugin-cross.markdown new file mode 100644 index 000000000..aba7194a4 --- /dev/null +++ b/notes/0.13.17/addSbtPlugin-cross.markdown @@ -0,0 +1,7 @@ +### Bug fixes + +- Fixes `addSbtPlugin` to use the correct version of sbt. [#3393][]/[#3397][] by [@dwijnand][] + + [#3393]: https://github.com/sbt/sbt/issues/3393 + [#3397]: https://github.com/sbt/sbt/pull/3397 + [@dwijnand]: http://github.com/dwijnand diff --git a/notes/1.0.1.markdown b/notes/1.0.1.markdown new file mode 100644 index 000000000..63735dfac --- /dev/null +++ b/notes/1.0.1.markdown @@ -0,0 +1,49 @@ +This is a hotfix release for sbt 1.0.x series. + +### Improvements + +- Various improves around watch source feature. See below. + +### Bug fixes + +- Fixes command support for cross building `+` command. The `+` added to sbt 1.0 traveres over the subprojects, respecting `crossScalaVersions`; however, it no longer accepted commands as arguments. This brings back the support for it. [#3446][3446] by [@jroper][@jroper] +- Fixes `addSbtPlugin` to use the correct version of sbt during cross building. [#3442][3442] by [@dwijnand][@dwijnand] +- Fixes `run in Compile` task not including `Runtime` configuration, by reimplementing `run` in terms of `bgRun`. [#3477][3477] by [@eed3si9n][@eed3si9n] +- Shows `actual` as a potential option of `inspect` [#3335][3335] by [@Duhemm][@Duhemm] +- Includes base directory to watched sources. [#3439][3439] by [@Duhemm][@Duhemm] +- Adds an attempt to workaround intermittent `NullPointerException` arround logging. [util#121][util121] by [@eed3si9n][@eed3si9n] +- Reverts a bad forward porting. [#3481][3481] by [@eed3si9n][@eed3si9n] + +### WatchSource + +The watch source feature went through a major change from sbt 0.13 to sbt 1.0 using NIO; however, it did not have clear migration path, so we are rectifying that in sbt 1.0.1. + +First, `sbt.WatchSource` is a new alias for `sbt.internal.io.Source`. Hopefully this is easy enough to remember because the key is named `watchSources`. Next, `def apply(base: File)` and `def apply(base: File, includeFilter: FileFilter, excludeFilter: FileFilter)` constructors were added to the companion object of `sbt.WatchSource`. + +For backward compatiblity, sbt 1.0.1 adds `+=` support (`Append` instance) from `File` to `Seq[WatchSource]`. + +So, if you have a directory you want to watch: + + watchSources += WatchSource(sourceDirectory.value) + +If you have a list of files: + + watchSources ++= (sourceDirectory.value ** "*.scala").get + +[#3438][3438] by [@Duhemm][@Duhemm]; [#3478][3478] and [io#74][io74] by [@eed3si9n][@eed3si9n] + + [3335]: https://github.com/sbt/sbt/pull/3335 + [3438]: https://github.com/sbt/sbt/pull/3438 + [3478]: https://github.com/sbt/sbt/pull/3478 + [3439]: https://github.com/sbt/sbt/pull/3439 + [io74]: https://github.com/sbt/io/pull/74 + [3442]: https://github.com/sbt/sbt/pull/3442 + [3446]: https://github.com/sbt/sbt/pull/3446 + [3477]: https://github.com/sbt/sbt/pull/3477 + [3481]: https://github.com/sbt/sbt/pull/3481 + [util121]: https://github.com/sbt/util/pull/121 + [@eed3si9n]: https://github.com/eed3si9n + [@dwijnand]: http://github.com/dwijnand + [@jvican]: https://github.com/jvican + [@Duhemm]: https://github.com/Duhemm + [@jroper]: https://github.com/jroper diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 08fca951f..571b6b9be 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -12,8 +12,8 @@ object Dependencies { val baseScalaVersion = scala212 // sbt modules - private val ioVersion = "1.0.0" - private val utilVersion = "1.0.0" + private val ioVersion = "1.0.1" + private val utilVersion = "1.0.1" private val lmVersion = "1.0.0" private val zincVersion = "1.0.0" diff --git a/project/build.properties b/project/build.properties index 12c38d389..94005e587 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.0.0-RC3 +sbt.version=1.0.0 diff --git a/sbt/src/main/scala/Import.scala b/sbt/src/main/scala/Import.scala index 896271f17..b3ab3b9e1 100644 --- a/sbt/src/main/scala/Import.scala +++ b/sbt/src/main/scala/Import.scala @@ -50,6 +50,8 @@ trait Import { type RichFile = sbt.io.RichFile type SimpleFileFilter = sbt.io.SimpleFileFilter type SimpleFilter = sbt.io.SimpleFilter + type WatchSource = sbt.internal.io.Source + val WatchSource = sbt.internal.io.Source // sbt.util type AbstractLogger = sbt.util.AbstractLogger diff --git a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt index 4d434aabd..117efa724 100644 --- a/sbt/src/sbt-test/actions/cross-multiproject/build.sbt +++ b/sbt/src/sbt-test/actions/cross-multiproject/build.sbt @@ -19,3 +19,5 @@ lazy val fooPlugin =(project in file("sbt-foo")). scalaVersion := "2.12.1", crossScalaVersions := Seq("2.12.1") ) + +addCommandAlias("build", "compile") diff --git a/sbt/src/sbt-test/actions/cross-multiproject/test b/sbt/src/sbt-test/actions/cross-multiproject/test index ea4079cf0..154e71c2c 100644 --- a/sbt/src/sbt-test/actions/cross-multiproject/test +++ b/sbt/src/sbt-test/actions/cross-multiproject/test @@ -36,3 +36,13 @@ $ exists lib/target/scala-2.11 # -$ exists lib/target/scala-2.12 # -$ exists sbt-foo/target/scala-2.12 # $ exists sbt-foo/target/scala-2.11 + +> clean +# Test legacy cross build with command support +> + build + +# Uses the root project scala version config, which is only configured to build for Scala 2.12 +$ exists lib/target/scala-2.12 +-$ exists lib/target/scala-2.11 +$ exists sbt-foo/target/scala-2.12 +-$ exists sbt-foo/target/scala-2.11 diff --git a/sbt/src/sbt-test/compiler-project/run-test/build.sbt b/sbt/src/sbt-test/compiler-project/run-test/build.sbt index 52cd6d1f6..1e2352020 100644 --- a/sbt/src/sbt-test/compiler-project/run-test/build.sbt +++ b/sbt/src/sbt-test/compiler-project/run-test/build.sbt @@ -1,6 +1,9 @@ +scalaVersion in ThisBuild := "2.12.3" + libraryDependencies ++= Seq( - "com.novocode" % "junit-interface" % "0.5" % "test", - "junit" % "junit" % "4.8" % "test" + "com.novocode" % "junit-interface" % "0.5" % Test, + "junit" % "junit" % "4.8" % Test, + "commons-io" % "commons-io" % "2.5" % Runtime, ) libraryDependencies += scalaVersion("org.scala-lang" % "scala-compiler" % _ ).value diff --git a/sbt/src/sbt-test/compiler-project/run-test/src/main/scala/Foo.scala b/sbt/src/sbt-test/compiler-project/run-test/src/main/scala/Foo.scala index 872ab523e..4f45a02cc 100644 --- a/sbt/src/sbt-test/compiler-project/run-test/src/main/scala/Foo.scala +++ b/sbt/src/sbt-test/compiler-project/run-test/src/main/scala/Foo.scala @@ -28,10 +28,11 @@ class Foo { catch { case _: URISyntaxException => new File(url.getPath) } } -object Test -{ - def main(args: Array[String]) - { +object Test { + def main(args: Array[String]): Unit = { + // test that Runtime configuration is included + Class.forName("org.apache.commons.io.ByteOrderMark") + val foo = new Foo args.foreach { arg => foo.eval(arg) == arg.toInt } } diff --git a/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt b/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt index 8bd47a1e2..b1d361b5a 100644 --- a/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt +++ b/sbt/src/sbt-test/project/cross-plugins-defaults/build.sbt @@ -4,39 +4,38 @@ val buildCrossList = List("2.10.6", "2.11.11", "2.12.2") scalaVersion in ThisBuild := "2.12.2" crossScalaVersions in ThisBuild := buildCrossList +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.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") - - // crossScalaVersions in app should not be affected - val appCrossScalaVersions = (crossScalaVersions in app).value.toList - val appScalaVersion = (scalaVersion in app).value - assert(appCrossScalaVersions == buildCrossList, s"Wrong `crossScalaVersions in app`: $appCrossScalaVersions") - assert(appScalaVersion startsWith "2.12", s"Wrong `scalaVersion in app`: $appScalaVersion") - }, - - 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") - - // ^^ should not affect app's crossScalaVersions - val appCrossScalaVersions = (crossScalaVersions in app).value.toList - val appScalaVersion = (scalaVersion in app).value - assert(appCrossScalaVersions == buildCrossList, s"Wrong `crossScalaVersions in app`: $appCrossScalaVersions") - assert(appScalaVersion startsWith "2.12", s"Wrong `scalaVersion in app`: $appScalaVersion") - } + TaskKey[Unit]("check") := mkCheck("2.12", "1.0").value, + TaskKey[Unit]("check2") := mkCheck("2.10", "0.13").value ) lazy val app = (project in file("app")) + +def mkCheck(scalaBinV: String, sbtBinVer: String) = Def task { + val crossV = (sbtVersion in pluginCrossBuild).value + val crossBinV = (sbtBinaryVersion in pluginCrossBuild).value + val sv = projectID.value.extraAttributes("e:scalaVersion") + assert(sbtVersion.value startsWith baseSbt, s"Wrong sbt version: ${sbtVersion.value}") + assert(sv == scalaBinV, s"Wrong e:scalaVersion: $sv") + assert(scalaBinaryVersion.value == scalaBinV, s"Wrong Scala binary version: ${scalaBinaryVersion.value}") + assert(crossV startsWith sbtBinVer, s"Wrong `sbtVersion in pluginCrossBuild`: $crossV") + + val ur = update.value + val cr = ur.configuration(Compile).get + val mr = cr.modules.find(mr => mr.module.organization == "com.eed3si9n" && mr.module.name == "sbt-buildinfo").get + val plugSv = mr.module.extraAttributes("scalaVersion") + val plugSbtV = mr.module.extraAttributes("sbtVersion") + assert(plugSv == scalaBinV, s"Wrong plugin scalaVersion: $plugSv") + assert(plugSbtV == sbtBinVer, s"Wrong plugin scalaVersion: $sbtBinVer") + + // crossScalaVersions in app should not be affected, per se or after ^^ + val appCrossScalaVersions = (crossScalaVersions in app).value.toList + val appScalaVersion = (scalaVersion in app).value + assert(appCrossScalaVersions == buildCrossList, s"Wrong `crossScalaVersions in app`: $appCrossScalaVersions") + assert(appScalaVersion startsWith "2.12", s"Wrong `scalaVersion in app`: $appScalaVersion") +} diff --git a/sbt/src/sbt-test/project/flatten/build.sbt b/sbt/src/sbt-test/project/flatten/build.sbt index 819170f8e..bbe93fbcc 100644 --- a/sbt/src/sbt-test/project/flatten/build.sbt +++ b/sbt/src/sbt-test/project/flatten/build.sbt @@ -17,7 +17,10 @@ def unpackageSettings(name: String) = Seq( unmanagedSourceDirectories := (baseDirectory.value / name) :: Nil, excludeFilter in unmanagedResources := (includeFilter in unmanagedSources).value, unmanagedResourceDirectories := unmanagedSourceDirectories.value, - unpackage := IO.unzip(artifactPath in packageSrc value, baseDirectory.value / name) + unpackage := { + IO.unzip(artifactPath in packageSrc value, baseDirectory.value / name) + IO.delete(baseDirectory.value / name / "META-INF") + } ) val unpackage = TaskKey[Unit]("unpackage")