mirror of https://github.com/sbt/sbt.git
commit
34945af631
|
|
@ -26,7 +26,9 @@ env:
|
||||||
- SBT_CMD="scripted java/* package/* reporter/* run/* project-load/*"
|
- SBT_CMD="scripted java/* package/* reporter/* run/* project-load/*"
|
||||||
- SBT_CMD="scripted project/*1of2"
|
- SBT_CMD="scripted project/*1of2"
|
||||||
- SBT_CMD="scripted project/*2of2"
|
- 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="scripted tests/*"
|
||||||
- SBT_CMD="repoOverrideTest:scripted dependency-management/*"
|
- SBT_CMD="repoOverrideTest:scripted dependency-management/*"
|
||||||
|
|
||||||
|
|
|
||||||
12
build.sbt
12
build.sbt
|
|
@ -1,6 +1,7 @@
|
||||||
import Util._
|
import Util._
|
||||||
import Dependencies._
|
import Dependencies._
|
||||||
import Sxr.sxr
|
import Sxr.sxr
|
||||||
|
import com.typesafe.tools.mima.core._, ProblemFilters._
|
||||||
|
|
||||||
// ThisBuild settings take lower precedence,
|
// ThisBuild settings take lower precedence,
|
||||||
// but can be shared across the multi projects.
|
// but can be shared across the multi projects.
|
||||||
|
|
@ -66,7 +67,7 @@ def testedBaseSettings: Seq[Setting[_]] =
|
||||||
|
|
||||||
val mimaSettings = Def settings (
|
val mimaSettings = Def settings (
|
||||||
mimaPreviousArtifacts := Set(
|
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)
|
cross (if (crossPaths.value) CrossVersion.binary else CrossVersion.disabled)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -382,9 +383,18 @@ lazy val sbtProj = (project in file("sbt"))
|
||||||
crossScalaVersions := Seq(baseScalaVersion),
|
crossScalaVersions := Seq(baseScalaVersion),
|
||||||
crossPaths := false,
|
crossPaths := false,
|
||||||
mimaSettings,
|
mimaSettings,
|
||||||
|
mimaBinaryIssueFilters ++= sbtIgnoredProblems,
|
||||||
)
|
)
|
||||||
.configure(addSbtCompilerBridge)
|
.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 {
|
def scriptedTask: Def.Initialize[InputTask[Unit]] = Def.inputTask {
|
||||||
val result = scriptedSource(dir => (s: State) => Scripted.scriptedParser(dir)).parsed
|
val result = scriptedSource(dir => (s: State) => Scripted.scriptedParser(dir)).parsed
|
||||||
// publishLocalBinAll.value // TODO: Restore scripted needing only binary jars.
|
// publishLocalBinAll.value // TODO: Restore scripted needing only binary jars.
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,12 @@ package sbt
|
||||||
import BasicCommandStrings.ClearOnFailure
|
import BasicCommandStrings.ClearOnFailure
|
||||||
import State.FailureWall
|
import State.FailureWall
|
||||||
import annotation.tailrec
|
import annotation.tailrec
|
||||||
|
import java.io.File
|
||||||
import java.nio.file.FileSystems
|
import java.nio.file.FileSystems
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
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.io.{ Source, SourceModificationWatch, WatchState }
|
||||||
import sbt.internal.util.AttributeKey
|
import sbt.internal.util.AttributeKey
|
||||||
import sbt.internal.util.Types.const
|
import sbt.internal.util.Types.const
|
||||||
|
|
@ -18,7 +19,7 @@ import sbt.internal.util.Types.const
|
||||||
trait Watched {
|
trait Watched {
|
||||||
|
|
||||||
/** The files watched when an action is run with a preceeding ~ */
|
/** 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)
|
def terminateWatch(key: Int): Boolean = Watched.isEnter(key)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,6 +45,30 @@ object Watched {
|
||||||
val clearWhenTriggered: WatchState => String = const(clearScreen)
|
val clearWhenTriggered: WatchState => String = const(clearScreen)
|
||||||
def clearScreen: String = "\u001b[2J\u001b[0;0H"
|
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
|
private[this] class AWatched extends Watched
|
||||||
|
|
||||||
def multi(base: Watched, paths: Seq[Watched]): Watched =
|
def multi(base: Watched, paths: Seq[Watched]): Watched =
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import scala.annotation.implicitNotFound
|
||||||
import sbt.internal.util.Attributed
|
import sbt.internal.util.Attributed
|
||||||
import Def.Initialize
|
import Def.Initialize
|
||||||
import reflect.internal.annotations.compileTimeOnly
|
import reflect.internal.annotations.compileTimeOnly
|
||||||
|
import sbt.internal.io.Source
|
||||||
|
import sbt.io.{ AllPassFilter, NothingFilter }
|
||||||
|
|
||||||
object Append {
|
object Append {
|
||||||
@implicitNotFound(
|
@implicitNotFound(
|
||||||
|
|
@ -96,4 +98,11 @@ object Append {
|
||||||
def appendValue(a: Seq[T], b: Option[T]): Seq[T] = b.fold(a)(a :+ _)
|
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 :+ _)
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import sbt.util.Logger
|
||||||
import Def.{ ScopedKey, Classpath }
|
import Def.{ ScopedKey, Classpath }
|
||||||
import sbt.internal.util.complete._
|
import sbt.internal.util.complete._
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
abstract class BackgroundJobService extends Closeable {
|
abstract class BackgroundJobService extends Closeable {
|
||||||
|
|
||||||
|
|
@ -24,6 +25,12 @@ abstract class BackgroundJobService extends Closeable {
|
||||||
def shutdown(): Unit
|
def shutdown(): Unit
|
||||||
def jobs: Vector[JobHandle]
|
def jobs: Vector[JobHandle]
|
||||||
def stop(job: JobHandle): Unit
|
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
|
def waitFor(job: JobHandle): Unit
|
||||||
|
|
||||||
/** Copies classpath to temporary directories. */
|
/** Copies classpath to temporary directories. */
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import Keys._
|
import Keys.{ version, _ }
|
||||||
import sbt.internal.util.complete.{ DefaultParsers, Parser }
|
import sbt.internal.util.complete.{ DefaultParsers, Parser }
|
||||||
import sbt.internal.util.AttributeKey
|
import sbt.internal.util.AttributeKey
|
||||||
import DefaultParsers._
|
import DefaultParsers._
|
||||||
|
|
@ -18,6 +18,7 @@ import sbt.internal.CommandStrings.{
|
||||||
}
|
}
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
import sbt.internal.Act
|
||||||
import sbt.internal.inc.ScalaInstance
|
import sbt.internal.inc.ScalaInstance
|
||||||
import sbt.io.IO
|
import sbt.io.IO
|
||||||
import sbt.librarymanagement.CrossVersion
|
import sbt.librarymanagement.CrossVersion
|
||||||
|
|
@ -125,10 +126,13 @@ object Cross {
|
||||||
case Left(cmd) => (resolveAggregates(x), cmd)
|
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
|
// 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
|
// 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 =>
|
val projVersions = (projCrossVersions flatMap {
|
||||||
crossVersions(x, proj) map { (proj.project, _) }
|
case (proj, versions) => versions map { proj.project -> _ }
|
||||||
}).toList
|
}).toList
|
||||||
|
|
||||||
val verbose = if (args.verbose) "-v" else ""
|
val verbose = if (args.verbose) "-v" else ""
|
||||||
|
|
@ -136,19 +140,51 @@ object Cross {
|
||||||
if (projVersions.isEmpty) {
|
if (projVersions.isEmpty) {
|
||||||
state
|
state
|
||||||
} else {
|
} else {
|
||||||
// Group all the projects by scala version
|
// Detect whether a task or command has been issued
|
||||||
val allCommands = projVersions.groupBy(_._2).mapValues(_.map(_._1)).toSeq.flatMap {
|
val allCommands = Parser.parse(aggCommand, Act.aggregatedKeyParser(x)) match {
|
||||||
case (version, Seq(project)) =>
|
case Left(_) =>
|
||||||
// If only one project for a version, issue it directly
|
// It's definitely not a task, check if it's a valid command, because we don't want to emit the warning
|
||||||
Seq(s"$SwitchCommand $verbose $version $project/$aggCommand")
|
// message below for typos.
|
||||||
case (version, projects) if aggCommand.contains(" ") =>
|
val validCommand = Parser.parse(aggCommand, state.combinedParser).isRight
|
||||||
// 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
|
val distinctCrossConfigs = projCrossVersions.map(_._2.toSet).distinct
|
||||||
s"$SwitchCommand $verbose $version" :: projects.map(project => s"$project/$aggCommand")
|
if (validCommand && distinctCrossConfigs.size > 1) {
|
||||||
case (version, projects) =>
|
state.log.warn(
|
||||||
// First switch scala version, then use the all command to run the command on each project concurrently
|
"Issuing a cross building command, but not all sub projects have the same cross build " +
|
||||||
Seq(s"$SwitchCommand $verbose $version",
|
"configuration. This could result in subprojects cross building against Scala versions that they are " +
|
||||||
projects.map(_ + "/" + aggCommand).mkString("all ", " ", ""))
|
"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)
|
allCommands.toList ::: CrossRestoreSessionCommand :: captureCurrentSession(state, x)
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,9 @@ object Defaults extends BuildCommon {
|
||||||
includeFilter in unmanagedSources,
|
includeFilter in unmanagedSources,
|
||||||
excludeFilter in unmanagedSources).value,
|
excludeFilter in unmanagedSources).value,
|
||||||
watchSources in ConfigGlobal ++= {
|
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 include = (includeFilter in unmanagedSources).value
|
||||||
val exclude = (excludeFilter in unmanagedSources).value
|
val exclude = (excludeFilter in unmanagedSources).value
|
||||||
bases.map(b => new Source(b, include, exclude))
|
bases.map(b => new Source(b, include, exclude))
|
||||||
|
|
@ -388,14 +390,7 @@ object Defaults extends BuildCommon {
|
||||||
val _ = clean.value
|
val _ = clean.value
|
||||||
IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
|
IvyActions.cleanCachedResolutionCache(ivyModule.value, streams.value.log)
|
||||||
},
|
},
|
||||||
scalaCompilerBridgeSource := {
|
scalaCompilerBridgeSource := ZincUtil.getDefaultBridgeModule(scalaVersion.value)
|
||||||
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)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
// must be a val: duplication detected by object identity
|
// must be a val: duplication detected by object identity
|
||||||
private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(
|
private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(
|
||||||
|
|
@ -501,8 +496,8 @@ object Defaults extends BuildCommon {
|
||||||
selectMainClass := mainClass.value orElse askForMainClass(discoveredMainClasses.value),
|
selectMainClass := mainClass.value orElse askForMainClass(discoveredMainClasses.value),
|
||||||
mainClass in run := (selectMainClass in run).value,
|
mainClass in run := (selectMainClass in run).value,
|
||||||
mainClass := pickMainClassOrWarn(discoveredMainClasses.value, streams.value.log),
|
mainClass := pickMainClassOrWarn(discoveredMainClasses.value, streams.value.log),
|
||||||
runMain := runMainTask(fullClasspath, runner in run).evaluated,
|
runMain := foregroundRunMainTask.evaluated,
|
||||||
run := runTask(fullClasspath, mainClass in run, runner in run).evaluated,
|
run := foregroundRunTask.evaluated,
|
||||||
copyResources := copyResourcesTask.value,
|
copyResources := copyResourcesTask.value,
|
||||||
// note that we use the same runner and mainClass as plain run
|
// note that we use the same runner and mainClass as plain run
|
||||||
bgRunMain := bgRunMainTask(exportedProductJars,
|
bgRunMain := bgRunMainTask(exportedProductJars,
|
||||||
|
|
@ -1166,14 +1161,14 @@ object Defaults extends BuildCommon {
|
||||||
Def.inputTask {
|
Def.inputTask {
|
||||||
val handle = bgRunMain.evaluated
|
val handle = bgRunMain.evaluated
|
||||||
val service = bgJobService.value
|
val service = bgJobService.value
|
||||||
service.waitFor(handle)
|
service.waitForTry(handle).get
|
||||||
}
|
}
|
||||||
// run calls bgRun in the background and waits for the result.
|
// run calls bgRun in the background and waits for the result.
|
||||||
def foregroundRunTask: Initialize[InputTask[Unit]] =
|
def foregroundRunTask: Initialize[InputTask[Unit]] =
|
||||||
Def.inputTask {
|
Def.inputTask {
|
||||||
val handle = bgRun.evaluated
|
val handle = bgRun.evaluated
|
||||||
val service = bgJobService.value
|
val service = bgJobService.value
|
||||||
service.waitFor(handle)
|
service.waitForTry(handle).get
|
||||||
}
|
}
|
||||||
def runMainTask(classpath: Initialize[Task[Classpath]],
|
def runMainTask(classpath: Initialize[Task[Classpath]],
|
||||||
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = {
|
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = {
|
||||||
|
|
@ -1538,8 +1533,11 @@ object Defaults extends BuildCommon {
|
||||||
lazy val configSettings
|
lazy val configSettings
|
||||||
: Seq[Setting[_]] = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig ++ deprecationSettings
|
: Seq[Setting[_]] = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig ++ deprecationSettings
|
||||||
|
|
||||||
lazy val compileSettings
|
lazy val compileSettings: Seq[Setting[_]] =
|
||||||
: Seq[Setting[_]] = configSettings ++ (mainBgRunMainTask +: mainBgRunTask +: addBaseSources) ++ Classpaths.addUnmanagedLibrary
|
configSettings ++
|
||||||
|
(mainBgRunMainTask +: mainBgRunTask +: addBaseSources) ++
|
||||||
|
Classpaths.addUnmanagedLibrary
|
||||||
|
|
||||||
lazy val testSettings: Seq[Setting[_]] = configSettings ++ testTasks
|
lazy val testSettings: Seq[Setting[_]] = configSettings ++ testTasks
|
||||||
|
|
||||||
lazy val itSettings: Seq[Setting[_]] = inConfig(IntegrationTest)(testSettings)
|
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]] =
|
def addSbtPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] =
|
||||||
libraryDependencies += {
|
libraryDependencies += {
|
||||||
val sbtV = (sbtBinaryVersion in update).value
|
val sbtV = (sbtBinaryVersion in pluginCrossBuild).value
|
||||||
val scalaV = (scalaBinaryVersion in update).value
|
val scalaV = (scalaBinaryVersion in update).value
|
||||||
sbtPluginExtra(dependency, sbtV, scalaV)
|
sbtPluginExtra(dependency, sbtV, scalaV)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import sbt.internal.{
|
||||||
LogManager
|
LogManager
|
||||||
}
|
}
|
||||||
import sbt.io.{ FileFilter, WatchService }
|
import sbt.io.{ FileFilter, WatchService }
|
||||||
import sbt.internal.io.{ Source, WatchState }
|
import sbt.internal.io.WatchState
|
||||||
import sbt.internal.util.{ AttributeKey, SourcePosition }
|
import sbt.internal.util.{ AttributeKey, SourcePosition }
|
||||||
|
|
||||||
import sbt.librarymanagement.Configurations.CompilerPlugin
|
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 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 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 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 watchSources = taskKey[Seq[Watched.WatchSource]]("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 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 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)
|
val triggeredMessage = settingKey[WatchState => String]("The message to show before triggered execution executes an action after sources change.").withRank(DSetting)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicLong
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import Def.{ ScopedKey, Setting, Classpath }
|
import Def.{ ScopedKey, Setting, Classpath }
|
||||||
import scala.concurrent.ExecutionContext
|
import scala.concurrent.ExecutionContext
|
||||||
|
import scala.util.Try
|
||||||
import Scope.GlobalScope
|
import Scope.GlobalScope
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import sbt.io.{ IO, Hash }
|
import sbt.io.{ IO, Hash }
|
||||||
|
|
@ -18,6 +19,13 @@ import sbt.internal.util.{ Attributed, ManagedLogger }
|
||||||
private[sbt] abstract class BackgroundJob {
|
private[sbt] abstract class BackgroundJob {
|
||||||
def humanReadableName: String
|
def humanReadableName: String
|
||||||
def awaitTermination(): Unit
|
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
|
def shutdown(): Unit
|
||||||
// this should be true on construction and stay true until
|
// this should be true on construction and stay true until
|
||||||
// the job is complete
|
// 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 {
|
private def withHandle(job: JobHandle)(f: ThreadJobHandle => Unit): Unit = job match {
|
||||||
case handle: ThreadJobHandle @unchecked => f(handle)
|
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 =>
|
case other =>
|
||||||
sys.error(
|
sys.error(
|
||||||
s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other")
|
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 =
|
override def stop(job: JobHandle): Unit =
|
||||||
withHandle(job)(_.job.shutdown())
|
withHandle(job)(_.job.shutdown())
|
||||||
|
|
||||||
|
override def waitForTry(job: JobHandle): Try[Unit] =
|
||||||
|
withHandleTry(job)(_.job.awaitTerminationTry())
|
||||||
|
|
||||||
override def waitFor(job: JobHandle): Unit =
|
override def waitFor(job: JobHandle): Unit =
|
||||||
withHandle(job)(_.job.awaitTermination())
|
withHandle(job)(_.job.awaitTermination())
|
||||||
|
|
||||||
|
|
@ -212,6 +232,9 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
|
||||||
@volatile
|
@volatile
|
||||||
private var status: Status = Waiting
|
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
|
// double-finally for extra paranoia that we will finishedLatch.countDown
|
||||||
override def run() =
|
override def run() =
|
||||||
try {
|
try {
|
||||||
|
|
@ -226,7 +249,11 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
|
||||||
throw new RuntimeException("Impossible status of bg thread")
|
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()
|
} finally finishedLatch.countDown()
|
||||||
|
|
||||||
private class StopListener(val callback: () => Unit, val executionContext: ExecutionContext)
|
private class StopListener(val callback: () => Unit, val executionContext: ExecutionContext)
|
||||||
|
|
@ -269,6 +296,12 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
override def awaitTermination(): Unit = finishedLatch.await()
|
override def awaitTermination(): Unit = finishedLatch.await()
|
||||||
|
|
||||||
|
override def awaitTerminationTry(): Try[Unit] = {
|
||||||
|
awaitTermination()
|
||||||
|
exitTry.getOrElse(Try(()))
|
||||||
|
}
|
||||||
|
|
||||||
override def humanReadableName: String = taskName
|
override def humanReadableName: String = taskName
|
||||||
override def isRunning(): Boolean =
|
override def isRunning(): Boolean =
|
||||||
status match {
|
status match {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -12,8 +12,8 @@ object Dependencies {
|
||||||
val baseScalaVersion = scala212
|
val baseScalaVersion = scala212
|
||||||
|
|
||||||
// sbt modules
|
// sbt modules
|
||||||
private val ioVersion = "1.0.0"
|
private val ioVersion = "1.0.1"
|
||||||
private val utilVersion = "1.0.0"
|
private val utilVersion = "1.0.1"
|
||||||
private val lmVersion = "1.0.0"
|
private val lmVersion = "1.0.0"
|
||||||
private val zincVersion = "1.0.0"
|
private val zincVersion = "1.0.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
sbt.version=1.0.0-RC3
|
sbt.version=1.0.0
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ trait Import {
|
||||||
type RichFile = sbt.io.RichFile
|
type RichFile = sbt.io.RichFile
|
||||||
type SimpleFileFilter = sbt.io.SimpleFileFilter
|
type SimpleFileFilter = sbt.io.SimpleFileFilter
|
||||||
type SimpleFilter = sbt.io.SimpleFilter
|
type SimpleFilter = sbt.io.SimpleFilter
|
||||||
|
type WatchSource = sbt.internal.io.Source
|
||||||
|
val WatchSource = sbt.internal.io.Source
|
||||||
|
|
||||||
// sbt.util
|
// sbt.util
|
||||||
type AbstractLogger = sbt.util.AbstractLogger
|
type AbstractLogger = sbt.util.AbstractLogger
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,5 @@ lazy val fooPlugin =(project in file("sbt-foo")).
|
||||||
scalaVersion := "2.12.1",
|
scalaVersion := "2.12.1",
|
||||||
crossScalaVersions := Seq("2.12.1")
|
crossScalaVersions := Seq("2.12.1")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addCommandAlias("build", "compile")
|
||||||
|
|
|
||||||
|
|
@ -36,3 +36,13 @@ $ exists lib/target/scala-2.11
|
||||||
# -$ exists lib/target/scala-2.12
|
# -$ exists lib/target/scala-2.12
|
||||||
# -$ exists sbt-foo/target/scala-2.12
|
# -$ exists sbt-foo/target/scala-2.12
|
||||||
# $ exists sbt-foo/target/scala-2.11
|
# $ 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
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
|
scalaVersion in ThisBuild := "2.12.3"
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"com.novocode" % "junit-interface" % "0.5" % "test",
|
"com.novocode" % "junit-interface" % "0.5" % Test,
|
||||||
"junit" % "junit" % "4.8" % "test"
|
"junit" % "junit" % "4.8" % Test,
|
||||||
|
"commons-io" % "commons-io" % "2.5" % Runtime,
|
||||||
)
|
)
|
||||||
|
|
||||||
libraryDependencies += scalaVersion("org.scala-lang" % "scala-compiler" % _ ).value
|
libraryDependencies += scalaVersion("org.scala-lang" % "scala-compiler" % _ ).value
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,11 @@ class Foo {
|
||||||
catch { case _: URISyntaxException => new File(url.getPath) }
|
catch { case _: URISyntaxException => new File(url.getPath) }
|
||||||
}
|
}
|
||||||
|
|
||||||
object Test
|
object Test {
|
||||||
{
|
def main(args: Array[String]): Unit = {
|
||||||
def main(args: Array[String])
|
// test that Runtime configuration is included
|
||||||
{
|
Class.forName("org.apache.commons.io.ByteOrderMark")
|
||||||
|
|
||||||
val foo = new Foo
|
val foo = new Foo
|
||||||
args.foreach { arg => foo.eval(arg) == arg.toInt }
|
args.foreach { arg => foo.eval(arg) == arg.toInt }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,39 +4,38 @@ val buildCrossList = List("2.10.6", "2.11.11", "2.12.2")
|
||||||
scalaVersion in ThisBuild := "2.12.2"
|
scalaVersion in ThisBuild := "2.12.2"
|
||||||
crossScalaVersions in ThisBuild := buildCrossList
|
crossScalaVersions in ThisBuild := buildCrossList
|
||||||
|
|
||||||
|
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")
|
||||||
|
|
||||||
lazy val root = (project in file("."))
|
lazy val root = (project in file("."))
|
||||||
.settings(
|
.settings(
|
||||||
sbtPlugin := true,
|
sbtPlugin := true,
|
||||||
|
|
||||||
TaskKey[Unit]("check") := {
|
TaskKey[Unit]("check") := mkCheck("2.12", "1.0").value,
|
||||||
val crossV = (sbtVersion in pluginCrossBuild).value
|
TaskKey[Unit]("check2") := mkCheck("2.10", "0.13").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")
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val app = (project in file("app"))
|
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")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,10 @@ def unpackageSettings(name: String) = Seq(
|
||||||
unmanagedSourceDirectories := (baseDirectory.value / name) :: Nil,
|
unmanagedSourceDirectories := (baseDirectory.value / name) :: Nil,
|
||||||
excludeFilter in unmanagedResources := (includeFilter in unmanagedSources).value,
|
excludeFilter in unmanagedResources := (includeFilter in unmanagedSources).value,
|
||||||
unmanagedResourceDirectories := unmanagedSourceDirectories.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")
|
val unpackage = TaskKey[Unit]("unpackage")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue