Merge pull request #3529 from sbt/1.0.x

Merge 1.0.x
This commit is contained in:
eugene yokota 2017-09-16 15:54:18 -04:00 committed by GitHub
commit 4b8d31a9ea
33 changed files with 402 additions and 161 deletions

View File

@ -1,5 +1,6 @@
# Use Docker-based container (instead of OpenVZ)
sudo: false
dist: trusty
group: stable
cache:
directories:
@ -36,6 +37,10 @@ notifications:
email:
- sbt-dev-bot@googlegroups.com
# Undo _JAVA_OPTIONS environment variable
before_script:
- _JAVA_OPTIONS=
script:
# It doesn't need that much memory because compile and run are forked
- sbt -J-XX:ReservedCodeCacheSize=128m -J-Xmx800M -J-Xms800M -J-server "$SBT_CMD"

View File

@ -9,7 +9,7 @@ def buildLevelSettings: Seq[Setting[_]] =
inThisBuild(
Seq(
organization := "org.scala-sbt",
version := "1.0.1-SNAPSHOT",
version := "1.0.3-SNAPSHOT",
description := "sbt is an interactive build tool",
bintrayOrganization := Some("sbt"),
bintrayRepository := {

View File

@ -120,7 +120,9 @@ private[sbt] object JLine {
def usingTerminal[T](f: jline.Terminal => T): T =
withTerminal { t =>
t.restore
f(t)
val result = f(t)
t.restore
result
}
def createReader(): ConsoleReader = createReader(None, JLine.makeInputStream(true))

View File

@ -161,6 +161,12 @@ $AliasCommand name=
def ShellDetailed =
"Provides an interactive prompt and network server from which commands can be run."
def StartServer = "startServer"
def StartServerDetailed =
s"""$StartServer
Starts the server if it has not been started. This is intended to be used with
-Dsbt.server.autostart=false."""
def OldShell = "oldshell"
def OldShellDetailed = "Provides an interactive prompt from which commands can be run."

View File

@ -16,7 +16,6 @@ import sbt.internal.util.{
}
import sbt.internal.util.complete.HistoryCommands
import sbt.internal.inc.classpath.ClassLoaderCache
import sbt.BasicCommandStrings.Shell
/**
* Data structure representing all command execution information.

View File

@ -30,8 +30,8 @@ abstract class ServerConnection(connection: Socket) {
bytesRead = in.read(readBuffer)
buffer = buffer ++ readBuffer.toVector.take(bytesRead)
// handle un-framing
val delimPos = buffer.indexOf(delimiter)
if (delimPos > 0) {
var delimPos = buffer.indexOf(delimiter)
while (delimPos > -1) {
val chunk = buffer.take(delimPos)
buffer = buffer.drop(delimPos + 1)
@ -47,6 +47,7 @@ abstract class ServerConnection(connection: Socket) {
case event: StringEvent => onLogEntry(event)
}
)
delimPos = buffer.indexOf(delimiter)
}
} catch {

View File

@ -27,26 +27,35 @@ object Def extends Init[Scope] with TaskMacroExtra {
Invisible)
lazy val showFullKey: Show[ScopedKey[_]] = showFullKey(None)
def showFullKey(keyNameColor: Option[String]): Show[ScopedKey[_]] =
Show[ScopedKey[_]]((key: ScopedKey[_]) => displayFull(key, keyNameColor))
def showRelativeKey(current: ProjectRef,
multi: Boolean,
keyNameColor: Option[String] = None): Show[ScopedKey[_]] =
def showRelativeKey(
current: ProjectRef,
multi: Boolean,
keyNameColor: Option[String] = None
): Show[ScopedKey[_]] =
Show[ScopedKey[_]](
(key: ScopedKey[_]) =>
Scope.display(key.scope,
withColor(key.key.label, keyNameColor),
ref => displayRelative(current, multi, ref)))
key =>
Scope.display(
key.scope,
withColor(key.key.label, keyNameColor),
ref => displayRelative(current, multi, ref)
))
def showBuildRelativeKey(currentBuild: URI,
multi: Boolean,
keyNameColor: Option[String] = None): Show[ScopedKey[_]] =
def showBuildRelativeKey(
currentBuild: URI,
multi: Boolean,
keyNameColor: Option[String] = None
): Show[ScopedKey[_]] =
Show[ScopedKey[_]](
(key: ScopedKey[_]) =>
Scope.display(key.scope,
withColor(key.key.label, keyNameColor),
ref => displayBuildRelative(currentBuild, multi, ref)))
key =>
Scope.display(
key.scope,
withColor(key.key.label, keyNameColor),
ref => displayBuildRelative(currentBuild, multi, ref)
))
def displayRelative(current: ProjectRef, multi: Boolean, project: Reference): String =
project match {
@ -55,15 +64,19 @@ object Def extends Init[Scope] with TaskMacroExtra {
case ProjectRef(current.build, x) => x + "/"
case _ => Reference.display(project) + "/"
}
def displayBuildRelative(currentBuild: URI, multi: Boolean, project: Reference): String =
project match {
case BuildRef(`currentBuild`) => "{.}/"
case ProjectRef(`currentBuild`, x) => x + "/"
case _ => Reference.display(project) + "/"
}
def displayFull(scoped: ScopedKey[_]): String = displayFull(scoped, None)
def displayFull(scoped: ScopedKey[_], keyNameColor: Option[String]): String =
Scope.display(scoped.scope, withColor(scoped.key.label, keyNameColor))
def displayMasked(scoped: ScopedKey[_], mask: ScopeMask): String =
Scope.displayMasked(scoped.scope, scoped.key.label, mask)

View File

@ -124,16 +124,22 @@ object Scope {
}
def display(config: ConfigKey): String = config.name + ":"
def display(scope: Scope, sep: String): String =
displayMasked(scope, sep, showProject, ScopeMask())
def displayMasked(scope: Scope, sep: String, mask: ScopeMask): String =
displayMasked(scope, sep, showProject, mask)
def display(scope: Scope, sep: String, showProject: Reference => String): String =
displayMasked(scope, sep, showProject, ScopeMask())
def displayMasked(scope: Scope,
sep: String,
showProject: Reference => String,
mask: ScopeMask): String = {
def displayMasked(
scope: Scope,
sep: String,
showProject: Reference => String,
mask: ScopeMask
): String = {
import scope.{ project, config, task, extra }
val configPrefix = config.foldStrict(display, "*:", ".:")
val taskPrefix = task.foldStrict(_.label + "::", "", ".::")
@ -148,9 +154,12 @@ object Scope {
(!mask.task || a.task == b.task) &&
(!mask.extra || a.extra == b.extra)
def projectPrefix(project: ScopeAxis[Reference],
show: Reference => String = showProject): String =
def projectPrefix(
project: ScopeAxis[Reference],
show: Reference => String = showProject
): String =
project.foldStrict(show, "*/", "./")
def showProject = (ref: Reference) => Reference.display(ref) + "/"
def transformTaskName(s: String) = {

View File

@ -1,10 +1,12 @@
package sbt
/** Specifies the Scope axes that should be used for an operation. `true` indicates an axis should be used. */
final case class ScopeMask(project: Boolean = true,
config: Boolean = true,
task: Boolean = true,
extra: Boolean = true) {
final case class ScopeMask(
project: Boolean = true,
config: Boolean = true,
task: Boolean = true,
extra: Boolean = true
) {
def concatShow(p: String, c: String, t: String, sep: String, x: String): String = {
val sb = new StringBuilder
if (project) sb.append(p)

View File

@ -2,7 +2,7 @@ package sbt.std
import sbt.SettingKey
import sbt.internal.util.ConsoleAppender
import sbt.internal.util.appmacro.{ Convert, Converted, LinterDSL }
import sbt.internal.util.appmacro.{ Convert, LinterDSL }
import scala.collection.mutable.{ HashSet => MutableSet }
import scala.io.AnsiColor
@ -27,7 +27,7 @@ abstract class BaseTaskLinterDSL extends LinterDSL {
def handleUncheckedAnnotation(exprAtUseSite: Tree, tt: TypeTree): Unit = {
tt.original match {
case Annotated(annot, arg) =>
case Annotated(annot, _) =>
Option(annot.tpe) match {
case Some(AnnotatedType(annotations, _)) =>
val tpeAnnotations = annotations.flatMap(ann => Option(ann.tree.tpe).toList)
@ -65,7 +65,7 @@ abstract class BaseTaskLinterDSL extends LinterDSL {
val wrapperName = nme.decodedName.toString
val (qualName, isSettingKey) =
Option(qual.symbol)
.map(sym => (sym.name.decodedName.toString, sym.info <:< typeOf[SettingKey[_]]))
.map(sym => (sym.name.decodedName.toString, qual.tpe <:< typeOf[SettingKey[_]]))
.getOrElse((ap.pos.lineContent, false))
if (!isSettingKey && !shouldIgnore && isTask(wrapperName, tpe.tpe, qual)) {

View File

@ -54,7 +54,7 @@ object FullInstance
KeyRanks.DTask)
def flatten[T](in: Initialize[Task[Initialize[Task[T]]]]): Initialize[Task[T]] = {
import Scoped._, TupleSyntax._
import TupleSyntax._
(in, settingsData, Def.capturedTransformations) {
(a: Task[Initialize[Task[T]]], data: Task[SS], f) =>
import TaskExtra.multT2Task
@ -63,7 +63,7 @@ object FullInstance
}
def flattenFun[S, T](in: Initialize[Task[S => Initialize[Task[T]]]]): Initialize[S => Task[T]] = {
import Scoped._, TupleSyntax._
import TupleSyntax._
(in, settingsData, Def.capturedTransformations) {
(a: Task[S => Initialize[Task[T]]], data: Task[SS], f) => (s: S) =>
import TaskExtra.multT2Task

View File

@ -151,6 +151,15 @@ class TaskPosSpec {
}
}
locally {
import sbt._, Def._
def withKey(foo: => SettingKey[String]) = {
Def.task { if (true) foo.value }
}
val foo = settingKey[String]("")
withKey(foo)
}
locally {
import sbt._
import sbt.Def._
@ -171,4 +180,17 @@ class TaskPosSpec {
(1 to 10).map(_ => foo.value)
}
}
locally {
import sbt._, Def._
def withKey(bar: => SettingKey[Int]) = {
Def.task {
List(42).map { _ =>
if (true) bar.value
}
}
}
val bar = settingKey[Int]("bar")
withKey(bar)
}
}

View File

@ -3,23 +3,16 @@
*/
package sbt
import Keys.{ version, _ }
import sbt.internal.util.complete.{ DefaultParsers, Parser }
import sbt.internal.util.AttributeKey
import DefaultParsers._
import Def.{ ScopedKey, Setting }
import sbt.internal.CommandStrings.{
CrossCommand,
CrossRestoreSessionCommand,
SwitchCommand,
crossHelp,
crossRestoreSessionHelp,
switchHelp
}
import java.io.File
import sbt.Def.{ ScopedKey, Setting }
import sbt.Keys._
import sbt.internal.Act
import sbt.internal.CommandStrings._
import sbt.internal.inc.ScalaInstance
import sbt.internal.util.AttributeKey
import sbt.internal.util.complete.DefaultParsers._
import sbt.internal.util.complete.{ DefaultParsers, Parser }
import sbt.io.IO
import sbt.librarymanagement.CrossVersion
@ -94,7 +87,7 @@ object Cross {
(currentRef :: currentProject.aggregate.toList.flatMap(findAggregates)).distinct
}
private def crossVersions(extracted: Extracted, proj: ProjectRef): Seq[String] = {
private def crossVersions(extracted: Extracted, proj: ResolvedReference): Seq[String] = {
import extracted._
(crossScalaVersions in proj get structure.data) getOrElse {
// reading scalaVersion is a one-time deal
@ -225,12 +218,14 @@ object Cross {
}
private def switchScalaVersion(switch: Switch, state: State): State = {
val x = Project.extract(state)
import x._
val extracted = Project.extract(state)
import extracted._
type ScalaVersion = String
val (version, instance) = switch.version match {
case ScalaHomeVersion(homePath, resolveVersion, _) =>
val home = IO.resolve(x.currentProject.base, homePath)
val home = IO.resolve(extracted.currentProject.base, homePath)
if (home.exists()) {
val instance = ScalaInstance(home)(state.classLoaderCache.apply _)
val version = resolveVersion.getOrElse(instance.actualVersion)
@ -241,10 +236,10 @@ object Cross {
case NamedScalaVersion(v, _) => (v, None)
}
val binaryVersion = CrossVersion.binaryScalaVersion(version)
def logSwitchInfo(included: Seq[(ProjectRef, Seq[String])],
excluded: Seq[(ProjectRef, Seq[String])]) = {
def logSwitchInfo(
included: Seq[(ProjectRef, Seq[ScalaVersion])],
excluded: Seq[(ProjectRef, Seq[ScalaVersion])]
) = {
instance.foreach {
case (home, instance) =>
@ -262,7 +257,7 @@ object Cross {
def detailedLog(msg: => String) =
if (switch.verbose) state.log.info(msg) else state.log.debug(msg)
def logProject: (ProjectRef, Seq[String]) => Unit = (proj, scalaVersions) => {
def logProject: (ProjectRef, Seq[ScalaVersion]) => Unit = (proj, scalaVersions) => {
val current = if (proj == currentRef) "*" else " "
detailedLog(s" $current ${proj.project} ${scalaVersions.mkString("(", ", ", ")")}")
}
@ -272,57 +267,67 @@ object Cross {
excluded.foreach(logProject.tupled)
}
val projects: Seq[Reference] = {
val projects: Seq[(ResolvedReference, Seq[ScalaVersion])] = {
val projectScalaVersions =
structure.allProjectRefs.map(proj => proj -> crossVersions(x, proj))
structure.allProjectRefs.map(proj => proj -> crossVersions(extracted, proj))
if (switch.version.force) {
logSwitchInfo(projectScalaVersions, Nil)
structure.allProjectRefs ++ structure.units.keys.map(BuildRef.apply)
projectScalaVersions ++ structure.units.keys
.map(BuildRef.apply)
.map(proj => proj -> crossVersions(extracted, proj))
} else {
val binaryVersion = CrossVersion.binaryScalaVersion(version)
val (included, excluded) = projectScalaVersions.partition {
case (proj, scalaVersions) =>
case (_, scalaVersions) =>
scalaVersions.exists(v => CrossVersion.binaryScalaVersion(v) == binaryVersion)
}
logSwitchInfo(included, excluded)
included.map(_._1)
included
}
}
setScalaVersionForProjects(version, instance, projects, state, x)
setScalaVersionForProjects(version, instance, projects, state, extracted)
}
private def setScalaVersionForProjects(version: String,
instance: Option[(File, ScalaInstance)],
projects: Seq[Reference],
state: State,
extracted: Extracted): State = {
private def setScalaVersionForProjects(
version: String,
instance: Option[(File, ScalaInstance)],
projects: Seq[(ResolvedReference, Seq[String])],
state: State,
extracted: Extracted
): State = {
import extracted._
val newSettings = projects.flatMap { project =>
val scope = Scope(Select(project), Zero, Zero, Zero)
val newSettings = projects.flatMap {
case (project, scalaVersions) =>
val scope = Scope(Select(project), Zero, Zero, Zero)
instance match {
case Some((home, inst)) =>
Seq(
scalaVersion in scope := version,
scalaHome in scope := Some(home),
scalaInstance in scope := inst
)
case None =>
Seq(
scalaVersion in scope := version,
scalaHome in scope := None
)
}
instance match {
case Some((home, inst)) =>
Seq(
scalaVersion in scope := version,
crossScalaVersions in scope := scalaVersions,
scalaHome in scope := Some(home),
scalaInstance in scope := inst
)
case None =>
Seq(
scalaVersion in scope := version,
crossScalaVersions in scope := scalaVersions,
scalaHome in scope := None
)
}
}
val filterKeys: Set[AttributeKey[_]] = Set(scalaVersion, scalaHome, scalaInstance).map(_.key)
val projectsContains: Reference => Boolean = projects.map(_._1).toSet.contains
// Filter out any old scala version settings that were added, this is just for hygiene.
val filteredRawAppend = session.rawAppend.filter(_.key match {
case ScopedKey(Scope(Select(ref), Zero, Zero, Zero), key)
if filterKeys.contains(key) && projects.contains(ref) =>
if filterKeys.contains(key) && projectsContains(ref) =>
false
case _ => true
})

View File

@ -82,7 +82,6 @@ import xsbti.compile.{
CompileOrder,
CompileResult,
DefinesClass,
IncOptionsUtil,
Inputs,
MiniSetup,
PerClasspathEntryLookup,
@ -500,15 +499,8 @@ object Defaults extends BuildCommon {
run := foregroundRunTask.evaluated,
copyResources := copyResourcesTask.value,
// note that we use the same runner and mainClass as plain run
bgRunMain := bgRunMainTask(exportedProductJars,
fullClasspathAsJars,
bgCopyClasspath in bgRunMain,
runner in run).evaluated,
bgRun := bgRunTask(exportedProductJars,
fullClasspathAsJars,
mainClass in run,
bgCopyClasspath in bgRun,
runner in run).evaluated
mainBgRunMainTaskForConfig(This),
mainBgRunTaskForConfig(This)
) ++ inTask(run)(runnerSettings)
private[this] lazy val configGlobal = globalDefaults(
@ -1119,10 +1111,12 @@ object Defaults extends BuildCommon {
toClean
}
def bgRunMainTask(products: Initialize[Task[Classpath]],
classpath: Initialize[Task[Classpath]],
copyClasspath: Initialize[Boolean],
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[JobHandle]] = {
def bgRunMainTask(
products: Initialize[Task[Classpath]],
classpath: Initialize[Task[Classpath]],
copyClasspath: Initialize[Boolean],
scalaRun: Initialize[Task[ScalaRun]]
): Initialize[InputTask[JobHandle]] = {
val parser = Defaults.loadForParser(discoveredMainClasses)((s, names) =>
Defaults.runMainParser(s, names getOrElse Nil))
Def.inputTask {
@ -1137,11 +1131,14 @@ object Defaults extends BuildCommon {
}
}
}
def bgRunTask(products: Initialize[Task[Classpath]],
classpath: Initialize[Task[Classpath]],
mainClassTask: Initialize[Task[Option[String]]],
copyClasspath: Initialize[Boolean],
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[JobHandle]] = {
def bgRunTask(
products: Initialize[Task[Classpath]],
classpath: Initialize[Task[Classpath]],
mainClassTask: Initialize[Task[Option[String]]],
copyClasspath: Initialize[Boolean],
scalaRun: Initialize[Task[ScalaRun]]
): Initialize[InputTask[JobHandle]] = {
import Def.parserToInput
val parser = Def.spaceDelimited()
Def.inputTask {
@ -1156,6 +1153,7 @@ object Defaults extends BuildCommon {
}
}
}
// runMain calls bgRunMain in the background and waits for the result.
def foregroundRunMainTask: Initialize[InputTask[Unit]] =
Def.inputTask {
@ -1163,6 +1161,7 @@ object Defaults extends BuildCommon {
val service = bgJobService.value
service.waitForTry(handle).get
}
// run calls bgRun in the background and waits for the result.
def foregroundRunTask: Initialize[InputTask[Unit]] =
Def.inputTask {
@ -1170,8 +1169,11 @@ object Defaults extends BuildCommon {
val service = bgJobService.value
service.waitForTry(handle).get
}
def runMainTask(classpath: Initialize[Task[Classpath]],
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = {
def runMainTask(
classpath: Initialize[Task[Classpath]],
scalaRun: Initialize[Task[ScalaRun]]
): Initialize[InputTask[Unit]] = {
val parser =
loadForParser(discoveredMainClasses)((s, names) => runMainParser(s, names getOrElse Nil))
Def.inputTask {
@ -1179,9 +1181,12 @@ object Defaults extends BuildCommon {
scalaRun.value.run(mainClass, data(classpath.value), args, streams.value.log).get
}
}
def runTask(classpath: Initialize[Task[Classpath]],
mainClassTask: Initialize[Task[Option[String]]],
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = {
def runTask(
classpath: Initialize[Task[Classpath]],
mainClassTask: Initialize[Task[Option[String]]],
scalaRun: Initialize[Task[ScalaRun]]
): Initialize[InputTask[Unit]] = {
import Def.parserToInput
val parser = Def.spaceDelimited()
Def.inputTask {
@ -1189,7 +1194,9 @@ object Defaults extends BuildCommon {
scalaRun.value.run(mainClass, data(classpath.value), parser.parsed, streams.value.log).get
}
}
def runnerTask: Setting[Task[ScalaRun]] = runner := runnerInit.value
def runnerInit: Initialize[Task[ScalaRun]] = Def.task {
val tmp = taskTemporaryDirectory.value
val resolvedScope = resolvedScoped.value.scope
@ -1217,7 +1224,8 @@ object Defaults extends BuildCommon {
}
private def foreachJobTask(
f: (BackgroundJobService, JobHandle) => Unit): Initialize[InputTask[Unit]] = {
f: (BackgroundJobService, JobHandle) => Unit
): Initialize[InputTask[Unit]] = {
val parser: Initialize[State => Parser[Seq[JobHandle]]] = Def.setting { (s: State) =>
val extracted = Project.extract(s)
val service = extracted.get(bgJobService)
@ -1232,6 +1240,7 @@ object Defaults extends BuildCommon {
}
}
}
def psTask: Initialize[Task[Seq[JobHandle]]] =
Def.task {
val xs = bgList.value
@ -1241,9 +1250,11 @@ object Defaults extends BuildCommon {
}
xs
}
def bgStopTask: Initialize[InputTask[Unit]] = foreachJobTask { (manager, handle) =>
manager.stop(handle)
}
def bgWaitForTask: Initialize[InputTask[Unit]] = foreachJobTask { (manager, handle) =>
manager.waitFor(handle)
}
@ -1294,17 +1305,25 @@ object Defaults extends BuildCommon {
}
))
def mainBgRunTask =
bgRun := bgRunTask(exportedProductJars,
fullClasspathAsJars in Runtime,
mainClass in run,
bgCopyClasspath in bgRun,
runner in run).evaluated
def mainBgRunMainTask =
bgRunMain := bgRunMainTask(exportedProductJars,
fullClasspathAsJars in Runtime,
bgCopyClasspath in bgRunMain,
runner in run).evaluated
def mainBgRunTask = mainBgRunTaskForConfig(Select(Runtime))
def mainBgRunMainTask = mainBgRunMainTaskForConfig(Select(Runtime))
private[this] def mainBgRunTaskForConfig(c: ScopeAxis[ConfigKey]) =
bgRun := bgRunTask(
exportedProductJars,
fullClasspathAsJars in (This, c, This),
mainClass in run,
bgCopyClasspath in bgRun,
runner in run
).evaluated
private[this] def mainBgRunMainTaskForConfig(c: ScopeAxis[ConfigKey]) =
bgRunMain := bgRunMainTask(
exportedProductJars,
fullClasspathAsJars in (This, c, This),
bgCopyClasspath in bgRunMain,
runner in run
).evaluated
def discoverMainClasses(analysis: CompileAnalysis): Seq[String] = analysis match {
case analysis: Analysis =>
@ -1316,6 +1335,7 @@ object Defaults extends BuildCommon {
ConsoleProject(state.value, (initialCommands in consoleProject).value)(streams.value.log)
println()
}
def consoleTask: Initialize[Task[Unit]] = consoleTask(fullClasspath, console)
def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick)
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[_]): Initialize[Task[Unit]] =
@ -1340,6 +1360,7 @@ object Defaults extends BuildCommon {
private[this] def exported(w: PrintWriter, command: String): Seq[String] => Unit =
args => w.println((command +: args).mkString(" "))
private[this] def exported(s: TaskStreams, command: String): Seq[String] => Unit = args => {
val w = s.text(ExportStream)
try exported(w, command)
@ -1530,8 +1551,10 @@ object Defaults extends BuildCommon {
lazy val runnerSettings: Seq[Setting[_]] = Seq(runnerTask, forkOptions := forkOptionsTask.value)
lazy val baseTasks: Seq[Setting[_]] = projectTasks ++ packageBase
lazy val configSettings
: Seq[Setting[_]] = Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++ Classpaths.compilerPluginConfig ++ deprecationSettings
lazy val configSettings: Seq[Setting[_]] =
Classpaths.configSettings ++ configTasks ++ configPaths ++ packageConfig ++
Classpaths.compilerPluginConfig ++ deprecationSettings
lazy val compileSettings: Seq[Setting[_]] =
configSettings ++
@ -1541,8 +1564,8 @@ object Defaults extends BuildCommon {
lazy val testSettings: Seq[Setting[_]] = configSettings ++ testTasks
lazy val itSettings: Seq[Setting[_]] = inConfig(IntegrationTest)(testSettings)
lazy val defaultConfigs: Seq[Setting[_]] = inConfig(Compile)(compileSettings) ++ inConfig(Test)(
testSettings) ++ inConfig(Runtime)(Classpaths.configSettings)
lazy val defaultConfigs: Seq[Setting[_]] = inConfig(Compile)(compileSettings) ++
inConfig(Test)(testSettings) ++ inConfig(Runtime)(Classpaths.configSettings)
// These are project level settings that MUST be on every project.
lazy val coreDefaultSettings: Seq[Setting[_]] =
@ -1690,8 +1713,9 @@ object Classpaths {
config.file.get
},
packagedArtifact in makePom := ((artifact in makePom).value -> makePom.value),
deliver := deliverTask(publishConfiguration).value,
deliverLocal := deliverTask(publishLocalConfiguration).value,
deliver := deliverTask(makeIvyXmlConfiguration).value,
deliverLocal := deliverTask(makeIvyXmlLocalConfiguration).value,
makeIvyXml := deliverTask(makeIvyXmlConfiguration).value,
publish := publishTask(publishConfiguration, deliver).value,
publishLocal := publishTask(publishLocalConfiguration, deliverLocal).value,
publishM2 := publishTask(publishM2Configuration, deliverLocal).value
@ -1871,6 +1895,17 @@ object Classpaths {
.withProcess(pomPostProcess.value)
.withFilterRepositories(pomIncludeRepository.value)
.withAllRepositories(pomAllRepositories.value),
makeIvyXmlConfiguration := {
makeIvyXmlConfig(
publishMavenStyle.value,
sbt.Classpaths.deliverPattern(crossTarget.value),
if (isSnapshot.value) "integration" else "release",
ivyConfigurations.value.map(c => ConfigRef(c.name)).toVector,
checksums.in(publish).value.toVector,
ivyLoggingLevel.value,
isSnapshot.value
)
},
publishConfiguration := {
publishConfig(
publishMavenStyle.value,
@ -1884,6 +1919,18 @@ object Classpaths {
isSnapshot.value
)
},
makeIvyXmlLocalConfiguration := {
makeIvyXmlConfig(
false, //publishMavenStyle.value,
sbt.Classpaths.deliverPattern(crossTarget.value),
if (isSnapshot.value) "integration" else "release",
ivyConfigurations.value.map(c => ConfigRef(c.name)).toVector,
checksums.in(publish).value.toVector,
ivyLoggingLevel.value,
isSnapshot.value,
optResolverName = Some("local")
)
},
publishLocalConfiguration := publishConfig(
false, //publishMavenStyle.value,
deliverPattern(crossTarget.value),
@ -2407,6 +2454,24 @@ object Classpaths {
logging,
overwrite)
def makeIvyXmlConfig(publishMavenStyle: Boolean,
deliverIvyPattern: String,
status: String,
configurations: Vector[ConfigRef],
checksums: Vector[String],
logging: sbt.librarymanagement.UpdateLogging = UpdateLogging.DownloadOnly,
overwrite: Boolean = false,
optResolverName: Option[String] = None) =
PublishConfiguration(publishMavenStyle,
Some(deliverIvyPattern),
Some(status),
Some(configurations),
optResolverName,
Vector.empty,
checksums,
Some(logging),
overwrite)
def deliverPattern(outputPath: File): String =
(outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath

View File

@ -363,6 +363,8 @@ object Keys {
val publishLocalConfiguration = taskKey[PublishConfiguration]("Configuration for publishing to the local Ivy repository.").withRank(DTask)
val publishM2Configuration = taskKey[PublishConfiguration]("Configuration for publishing to the local Maven repository.").withRank(DTask)
val makePomConfiguration = settingKey[MakePomConfiguration]("Configuration for generating a pom.").withRank(DSetting)
val makeIvyXmlConfiguration = taskKey[PublishConfiguration]("Configuration for generating ivy.xml.").withRank(DSetting)
val makeIvyXmlLocalConfiguration = taskKey[PublishConfiguration]("Configuration for generating ivy.xml.").withRank(DSetting)
val packagedArtifacts = taskKey[Map[Artifact, File]]("Packages all artifacts for publishing and maps the Artifact definition to the generated file.").withRank(CTask)
val publishMavenStyle = settingKey[Boolean]("Configures whether to generate and publish a pom (true) or Ivy file (false).").withRank(BSetting)
val credentials = taskKey[Seq[Credentials]]("The credentials to use for updating and publishing.").withRank(BMinusTask)
@ -370,6 +372,8 @@ object Keys {
val makePom = taskKey[File]("Generates a pom for publishing when publishing Maven-style.").withRank(BPlusTask)
val deliver = taskKey[File]("Generates the Ivy file for publishing to a repository.").withRank(BTask)
val deliverLocal = taskKey[File]("Generates the Ivy file for publishing to the local repository.").withRank(BTask)
// makeIvyXml is currently identical to the confusingly-named "deliver", which may be deprecated in the future
val makeIvyXml = taskKey[File]("Generates the Ivy file for publishing to a repository.").withRank(BTask)
val publish = taskKey[Unit]("Publishes artifacts to a repository.").withRank(APlusTask)
val publishLocal = taskKey[Unit]("Publishes artifacts to the local Ivy repository.").withRank(APlusTask)
val publishM2 = taskKey[Unit]("Publishes artifacts to the local Maven repository.").withRank(ATask)

View File

@ -195,6 +195,7 @@ object BuiltinCommands {
multi,
shell,
oldshell,
startServer,
BasicCommands.client,
continuous,
eval,
@ -737,6 +738,12 @@ object BuiltinCommands {
else newState.clearGlobalLog
}
def startServer: Command =
Command.command(StartServer, Help.more(StartServer, StartServerDetailed)) { s0 =>
val exchange = StandardMain.exchange
exchange.runServer(s0)
}
private val sbtVersionRegex = """sbt\.version\s*=.*""".r
private def isSbtVersionLine(s: String) = sbtVersionRegex.pattern matcher s matches ()

View File

@ -15,9 +15,8 @@ import Def.ScopedKey
import sbt.internal.Load
import sbt.internal.CommandStrings._
import Cross.{ spacedFirst, requireSession }
import sbt.librarymanagement.Configurations._
import sbt.librarymanagement.VersionNumber
import Project.{ inConfig, inScope }
import Project.{ inScope }
/**
* Module responsible for plugin cross building.

View File

@ -23,6 +23,9 @@ import scala.util.{ Success, Failure }
* this exchange, which could serve command request from either of the channel.
*/
private[sbt] final class CommandExchange {
private val autoStartServer = sys.props.get("sbt.server.autostart") map {
_.toLowerCase == "true"
} getOrElse true
private val lock = new AnyRef {}
private var server: Option[ServerInstance] = None
private var consoleChannel: Option[ConsoleChannel] = None
@ -61,13 +64,17 @@ private[sbt] final class CommandExchange {
consoleChannel = Some(x)
subscribe(x)
}
runServer(s)
if (autoStartServer) runServer(s)
else s
}
private def newChannelName: String = s"channel-${nextChannelId.incrementAndGet()}"
private def runServer(s: State): State = {
val port = (s get serverPort) match {
/**
* Check if a server instance is running already, and start one if it isn't.
*/
private[sbt] def runServer(s: State): State = {
def port = (s get serverPort) match {
case Some(x) => x
case None => 5001
}

View File

@ -2,15 +2,17 @@ package sbt
package internal
import java.util.concurrent.atomic.AtomicLong
import java.io.Closeable
import Def.{ ScopedKey, Setting, Classpath }
import java.io.{ Closeable, File, FileInputStream, IOException }
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.{ FileVisitResult, Files, Path, SimpleFileVisitor }
import java.security.{ DigestInputStream, MessageDigest }
import Def.{ Classpath, ScopedKey, Setting }
import scala.concurrent.ExecutionContext
import scala.util.Try
import Scope.GlobalScope
import java.io.File
import sbt.io.{ IO, Hash }
import sbt.io.{ Hash, IO }
import sbt.io.syntax._
import sbt.util.{ Logger, LogExchange }
import sbt.util.{ LogExchange, Logger }
import sbt.internal.util.{ Attributed, ManagedLogger }
/**
@ -167,20 +169,25 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
override def toString(): String = s"BackgroundJobService(jobs=${jobs.map(_.id).mkString})"
/**
* Copies products to the workind directory, and the rest to the serviceTempDir of this service,
* Copies products to the working directory, and the rest to the serviceTempDir of this service,
* both wrapped in SHA-1 hash of the file contents.
* This is intended to mimize the file copying and accumulation of the unused JAR file.
* This is intended to minimize the file copying and accumulation of the unused JAR file.
* Since working directory is wiped out when the background job ends, the product JAR is deleted too.
* Meanwhile, the rest of the dependencies are cached for the duration of this service.
*/
override def copyClasspath(products: Classpath,
full: Classpath,
workingDirectory: File): Classpath = {
override def copyClasspath(
products: Classpath,
full: Classpath,
workingDirectory: File
): Classpath = {
def syncTo(dir: File)(source0: Attributed[File]): Attributed[File] = {
val source = source0.data
val hash8 = Hash.toHex(Hash(source)).take(8)
val hash8 = Hash.toHex(hash(source)).take(8)
val dest = dir / hash8 / source.getName
if (!dest.exists) { IO.copyFile(source, dest) }
if (!dest.exists) {
if (source.isDirectory) IO.copyDirectory(source, dest)
else IO.copyFile(source, dest)
}
Attributed.blank(dest)
}
val xs = (products.toVector map { syncTo(workingDirectory / "target") }) ++
@ -188,6 +195,27 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
Thread.sleep(100)
xs
}
/** An alternative to sbt.io.Hash that handles java.io.File being a directory. */
private def hash(f: File) = {
val digest = MessageDigest.getInstance("SHA")
val buffer = new Array[Byte](8192)
Files.walkFileTree(
f.toPath,
new SimpleFileVisitor[Path]() {
override def visitFile(file: Path, attrs: BasicFileAttributes) = {
val dis = new DigestInputStream(new FileInputStream(file.toFile), digest)
try {
while (dis.read(buffer) >= 0) ()
FileVisitResult.CONTINUE
} catch {
case _: IOException => FileVisitResult.TERMINATE
} finally dis.close()
}
}
)
digest.digest
}
}
private[sbt] object BackgroundThreadPool {

View File

@ -29,8 +29,8 @@ final class NetworkChannel(val name: String, connection: Socket, structure: Buil
bytesRead = in.read(readBuffer)
buffer = buffer ++ readBuffer.toVector.take(bytesRead)
// handle un-framing
val delimPos = buffer.indexOf(delimiter)
if (delimPos > 0) {
var delimPos = buffer.indexOf(delimiter)
while (delimPos > -1) {
val chunk = buffer.take(delimPos)
buffer = buffer.drop(delimPos + 1)
@ -40,6 +40,7 @@ final class NetworkChannel(val name: String, connection: Socket, structure: Buil
errorDesc => println("Got invalid chunk from client: " + errorDesc),
onCommand
)
delimPos = buffer.indexOf(delimiter)
}
} catch {

37
notes/1.0.2.markdown Normal file
View File

@ -0,0 +1,37 @@
This is a hotfix release for sbt 1.0.x series.
### Bug fixes
- Fixes terminal echo issue. [#3507][3507] by [@kczulko][@kczulko]
- Fixes `deliver` task, and adds `makeIvyXml` as a more sensibly named task. [#3487][3487] by [@cunei][@cunei]
- Replaces the deprecated use of `OkUrlFactory`, and fixes connection leaks. [lm#164][lm164] by [@dpratt][@dpratt]
- Refixes false positive in DSL checker for setting keys. [#3513][3513] by [@dwijnand][@dwijnand]
- Fixes `run` and `bgRun` not picking up changes to directories in the classpath. [#3517][3517] by [@dwijnand][@dwijnand]
- Fixes `++` so it won't change the value of `crossScalaVersion`. [#3495][3495]/[#3526][3526] by [@dwijnand][@dwijnand]
- Fixes sbt server missing some messages. [#3523][3523] by [@guillaumebort][@guillaumebort]
- Refixes `consoleProject`. [zinc#386][zinc386] by [@dwijnand][@dwijnand]
- Adds JVM flag `sbt.gigahorse` to enable/disable the internal use of Gigahorse to workaround NPE in `JavaNetAuthenticator` when used in conjunction with `repositories` override. [lm#167][lm167] by [@cunei][@cunei]
- Adds JVM flag `sbt.server.autostart` to enable/disable the automatic starting of sbt server with the sbt shell. This also adds new `startServer` command to manually start the server. by [@eed3si9n][@eed3si9n]
### Internal
- Fixes unused import warnings. [#3533][3533] by [@razvan-panda][@razvan-panda]
[@dwijnand]: https://github.com/dwijnand
[@cunei]: https://github.com/cunei
[@eed3si9n]: https://github.com/eed3si9n
[@dpratt]: https://github.com/dpratt
[@kczulko]: https://github.com/kczulko
[@razvan-panda]: https://github.com/razvan-panda
[@guillaumebort]: https://github.com/guillaumebort
[3487]: https://github.com/sbt/sbt/pull/3487
[lm164]: https://github.com/sbt/librarymanagement/pull/164
[3495]: https://github.com/sbt/sbt/issues/3495
[3526]: https://github.com/sbt/sbt/pull/3526
[3513]: https://github.com/sbt/sbt/pull/3513
[3517]: https://github.com/sbt/sbt/pull/3517
[3507]: https://github.com/sbt/sbt/pull/3507
[3533]: https://github.com/sbt/sbt/pull/3533
[3523]: https://github.com/sbt/sbt/pull/3523
[zinc386]: https://github.com/sbt/zinc/pull/386
[lm167]: https://github.com/sbt/librarymanagement/pull/167

View File

@ -14,8 +14,8 @@ object Dependencies {
// sbt modules
private val ioVersion = "1.0.1"
private val utilVersion = "1.0.1"
private val lmVersion = "1.0.0"
private val zincVersion = "1.0.0"
private val lmVersion = "1.0.2"
private val zincVersion = "1.0.1"
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion

View File

@ -1,3 +1,3 @@
#!/bin/bash
rm -rf ~/.sbt/boot/scala-2.12.2/org.scala-sbt/sbt/1.0.0-SNAPSHOT/
rm -rf ~/.sbt/boot/scala-2.12.3/org.scala-sbt/sbt/1.0.3-SNAPSHOT/

View File

@ -1,23 +1,31 @@
inThisBuild(List(
crossScalaVersions := Seq("2.12.1", "2.11.8")
))
lazy val rootProj = (project in file(".")).
aggregate(libProj, fooPlugin).
settings(
lazy val rootProj = (project in file("."))
.aggregate(libProj, fooPlugin)
.settings(
scalaVersion := "2.12.1"
)
lazy val libProj = (project in file("lib")).
settings(
lazy val libProj = (project in file("lib"))
.settings(
name := "foo-lib",
scalaVersion := "2.12.1",
crossScalaVersions := Seq("2.12.1", "2.11.8")
)
lazy val fooPlugin =(project in file("sbt-foo")).
settings(
lazy val fooPlugin = (project in file("sbt-foo"))
.settings(
name := "sbt-foo",
sbtPlugin := true,
scalaVersion := "2.12.1",
crossScalaVersions := Seq("2.12.1")
)
lazy val extrasProj = (project in file("extras"))
.settings(
name := "foo-extras",
)
addCommandAlias("build", "compile")

View File

@ -46,3 +46,10 @@ $ 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
> clean
# Test ++ leaves crossScalaVersions unchanged
> ++2.12.1
> +extrasProj/compile
$ exists extras/target/scala-2.11
$ exists extras/target/scala-2.12

View File

@ -0,0 +1,9 @@
package t
import java.nio._, charset._, file._
object Main {
def main(args: Array[String]): Unit = {
println(new String(Files.readAllBytes(Paths.get(getClass().getResource("/a.txt").toURI()))))
}
}

View File

@ -0,0 +1 @@
externalDependencyClasspath in Runtime += file("conf")

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1 @@
> run

View File

@ -13,6 +13,7 @@ $ copy-file changes/ThreadRunError.scala src/main/scala/Run.scala
$ copy-file changes/RunExplicitSuccess.scala src/main/scala/Run.scala
> run
# explicitly calling System.exit(1) should fail the 'run' task
$ copy-file changes/RunExplicitFailure.scala src/main/scala/Run.scala
-> run
# https://github.com/sbt/sbt/issues/3543
# # explicitly calling System.exit(1) should fail the 'run' task
# $ copy-file changes/RunExplicitFailure.scala src/main/scala/Run.scala
# -> run

View File

@ -1,5 +1,6 @@
> test
-> check
# https://github.com/sbt/sbt/issues/3545
# > test
# -> check
> clean
> set testForkedParallel := true

View File

@ -2,7 +2,7 @@ package sbt.internal.testing
import sbt.testing.Status
import _root_.sjsonnew.{ deserializationError, serializationError, Builder, JsonFormat, Unbuilder }
import _root_.sjsonnew.{ deserializationError, Builder, JsonFormat, Unbuilder }
trait StatusFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val StatusFormat: JsonFormat[Status] = new JsonFormat[Status] {