Merge branch '1.0.x' into topic/generators

This commit is contained in:
eugene yokota 2017-02-06 16:17:21 -05:00 committed by GitHub
commit ba28c00a1a
14 changed files with 130 additions and 55 deletions

View File

@ -12,6 +12,7 @@ Migration notes
- Removes no-longer-documented old operators `<<=`, `<+=`, and `<++=`. - Removes no-longer-documented old operators `<<=`, `<+=`, and `<++=`.
- Renames early command feature from `--<command>` to `early(<command>)`. - Renames early command feature from `--<command>` to `early(<command>)`.
- Log options `-error`, `-warn`, `-info`, `-debug` are added as shorthand for `"early(error)"` etc. - Log options `-error`, `-warn`, `-info`, `-debug` are added as shorthand for `"early(error)"` etc.
- `sbt.Process` and `sbt.ProcessExtra` are gone. Use `scala.sys.process` instead.
#### Additional import required #### Additional import required

View File

@ -155,6 +155,7 @@ object Defaults extends BuildCommon {
retrieveManagedSync :== false, retrieveManagedSync :== false,
configurationsToRetrieve :== None, configurationsToRetrieve :== None,
scalaOrganization :== ScalaArtifacts.Organization, scalaOrganization :== ScalaArtifacts.Organization,
scalaArtifacts :== ScalaArtifacts.Artifacts,
sbtResolver := { if (sbtVersion.value endsWith "-SNAPSHOT") Classpaths.sbtIvySnapshots else Classpaths.typesafeReleases }, sbtResolver := { if (sbtVersion.value endsWith "-SNAPSHOT") Classpaths.sbtIvySnapshots else Classpaths.typesafeReleases },
crossVersion :== Disabled(), crossVersion :== Disabled(),
buildDependencies := Classpaths.constructBuildDependencies.value, buildDependencies := Classpaths.constructBuildDependencies.value,
@ -368,7 +369,8 @@ object Defaults extends BuildCommon {
private[this] lazy val configGlobal = globalDefaults(Seq( private[this] lazy val configGlobal = globalDefaults(Seq(
initialCommands :== "", initialCommands :== "",
cleanupCommands :== "" cleanupCommands :== "",
asciiGraphWidth :== 40
)) ))
lazy val projectTasks: Seq[Setting[_]] = Seq( lazy val projectTasks: Seq[Setting[_]] = Seq(
@ -1431,7 +1433,9 @@ object Classpaths {
(scalaVersion in update).value, (scalaVersion in update).value,
(scalaBinaryVersion in update).value, (scalaBinaryVersion in update).value,
Vector.empty, filterImplicit = false, checkExplicit = true, overrideScalaVersion = true Vector.empty, filterImplicit = false, checkExplicit = true, overrideScalaVersion = true
).withScalaOrganization(scalaOrganization.value)) )
.withScalaOrganization(scalaOrganization.value)
.withScalaArtifacts(scalaArtifacts.value.toVector))
} }
)).value, )).value,
artifactPath in makePom := artifactPathSetting(artifact in makePom).value, artifactPath in makePom := artifactPathSetting(artifact in makePom).value,

View File

@ -150,8 +150,15 @@ object EvaluateTask {
import std.Transform import std.Transform
import Keys.state import Keys.state
lazy private val sharedProgress = new TaskTimings(shutdown = true)
private[sbt] def defaultProgress: ExecuteProgress[Task] = private[sbt] def defaultProgress: ExecuteProgress[Task] =
if (java.lang.Boolean.getBoolean("sbt.task.timings")) new TaskTimings else ExecuteProgress.empty[Task] if (java.lang.Boolean.getBoolean("sbt.task.timings")) {
if (java.lang.Boolean.getBoolean("sbt.task.timings.on.shutdown"))
sharedProgress
else
new TaskTimings(shutdown = false)
} else ExecuteProgress.empty[Task]
val SystemProcessors = Runtime.getRuntime.availableProcessors val SystemProcessors = Runtime.getRuntime.availableProcessors

View File

@ -179,6 +179,7 @@ object Keys {
val compileOrder = SettingKey[CompileOrder]("compile-order", "Configures the order in which Java and sources within a single compilation are compiled. Valid values are: JavaThenScala, ScalaThenJava, or Mixed.", BPlusSetting) val compileOrder = SettingKey[CompileOrder]("compile-order", "Configures the order in which Java and sources within a single compilation are compiled. Valid values are: JavaThenScala, ScalaThenJava, or Mixed.", BPlusSetting)
val initialCommands = SettingKey[String]("initial-commands", "Initial commands to execute when starting up the Scala interpreter.", AMinusSetting) val initialCommands = SettingKey[String]("initial-commands", "Initial commands to execute when starting up the Scala interpreter.", AMinusSetting)
val cleanupCommands = SettingKey[String]("cleanup-commands", "Commands to execute before the Scala interpreter exits.", BMinusSetting) val cleanupCommands = SettingKey[String]("cleanup-commands", "Commands to execute before the Scala interpreter exits.", BMinusSetting)
val asciiGraphWidth = SettingKey[Int]("asciiGraphWidth", "Determines maximum width of the settings graph in ASCII mode", AMinusSetting)
val compileOptions = TaskKey[CompileOptions]("compile-options", "Collects basic options to configure compilers", DTask) val compileOptions = TaskKey[CompileOptions]("compile-options", "Collects basic options to configure compilers", DTask)
val compileInputs = TaskKey[Inputs]("compile-inputs", "Collects all inputs needed for compilation.", DTask) val compileInputs = TaskKey[Inputs]("compile-inputs", "Collects all inputs needed for compilation.", DTask)
val scalaHome = SettingKey[Option[File]]("scala-home", "If Some, defines the local Scala installation to use for compilation, running, and testing.", ASetting) val scalaHome = SettingKey[Option[File]]("scala-home", "If Some, defines the local Scala installation to use for compilation, running, and testing.", ASetting)
@ -194,6 +195,7 @@ object Keys {
val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask) val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask)
val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting) val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting)
val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting) val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting)
val scalaArtifacts = SettingKey[Seq[String]]("scala-artifacts", "Configures the list of artifacts which should match the Scala binary version", CSetting)
val clean = TaskKey[Unit]("clean", "Deletes files produced by the build, such as generated sources, compiled classes, and task caches.", APlusTask) val clean = TaskKey[Unit]("clean", "Deletes files produced by the build, such as generated sources, compiled classes, and task caches.", APlusTask)
val console = TaskKey[Unit]("console", "Starts the Scala interpreter with the project classes on the classpath.", APlusTask) val console = TaskKey[Unit]("console", "Starts the Scala interpreter with the project classes on the classpath.", APlusTask)

View File

@ -27,7 +27,7 @@ import sbt.internal.{
import sbt.internal.util.{ AttributeKey, AttributeMap, complete, ConsoleOut, GlobalLogging, LineRange, MainAppender, SimpleReader, Types } import sbt.internal.util.{ AttributeKey, AttributeMap, complete, ConsoleOut, GlobalLogging, LineRange, MainAppender, SimpleReader, Types }
import sbt.util.{ Level, Logger } import sbt.util.{ Level, Logger }
import complete.{ DefaultParsers, Parser } import sbt.internal.util.complete.{ DefaultParsers, Parser }
import sbt.internal.inc.{ CompilerCache, ScalaInstance } import sbt.internal.inc.{ CompilerCache, ScalaInstance }
import sbt.compiler.EvalImports import sbt.compiler.EvalImports
import Types.{ const, idFun } import Types.{ const, idFun }
@ -221,7 +221,7 @@ object BuiltinCommands {
Some(index.keyMap(key)) Some(index.keyMap(key))
catch { catch {
case NonFatal(ex) => case NonFatal(ex) =>
s.log error ex.getMessage s.log debug ex.getMessage
None None
} }
}.collect { case Some(s) => s }.distinct }.collect { case Some(s) => s }.distinct
@ -356,7 +356,7 @@ object BuiltinCommands {
val extracted = Project extract s val extracted = Project extract s
import extracted.{ showKey, structure } import extracted.{ showKey, structure }
val keysParser = token(flag("--last" <~ Space)) ~ Act.aggregatedKeyParser(extracted) val keysParser = token(flag("--last" <~ Space)) ~ Act.aggregatedKeyParser(extracted)
val show = Aggregation.ShowConfig(settingValues = true, taskValues = false, print = println _, success = false) val show = Aggregation.ShowConfig(settingValues = true, taskValues = false, print = println(_), success = false)
for { for {
lastOnly_keys <- keysParser lastOnly_keys <- keysParser
kvs = Act.keyValues(structure)(lastOnly_keys._2) kvs = Act.keyValues(structure)(lastOnly_keys._2)

View File

@ -47,7 +47,7 @@ object Inspect {
Project.details(structure, actual, sk.scope, sk.key) Project.details(structure, actual, sk.scope, sk.key)
case DependencyTreeMode => case DependencyTreeMode =>
val basedir = new File(Project.session(s).current.build) val basedir = new File(Project.session(s).current.build)
Project.settingGraph(structure, basedir, sk).dependsAscii Project.settingGraph(structure, basedir, sk).dependsAscii(get(sbt.Keys.asciiGraphWidth))
case UsesMode => case UsesMode =>
Project.showUses(Project.usedBy(structure, true, sk.key)) Project.showUses(Project.usedBy(structure, true, sk.key))
case DefinitionsMode => case DefinitionsMode =>

View File

@ -4,7 +4,7 @@
package sbt package sbt
package internal package internal
import sbt.internal.util.Show import sbt.internal.util.{ Show, JLine }
import java.io.File import java.io.File
import Def.{ compiled, flattenLocals, ScopedKey } import Def.{ compiled, flattenLocals, ScopedKey }
@ -50,10 +50,11 @@ case class SettingGraph(
} getOrElse { d.typeName } } getOrElse { d.typeName }
} getOrElse { "" } } getOrElse { "" }
def dependsAscii: String = Graph.toAscii( def dependsAscii(defaultWidth: Int): String = Graph.toAscii(
this, this,
(x: SettingGraph) => x.depends.toSeq.sortBy(_.name), (x: SettingGraph) => x.depends.toSeq.sortBy(_.name),
(x: SettingGraph) => "%s = %s" format (x.definedIn getOrElse { "" }, x.dataString) (x: SettingGraph) => "%s = %s" format (x.definedIn getOrElse { "" }, x.dataString),
defaultWidth
) )
} }
@ -63,10 +64,8 @@ object Graph {
// [info] | +-baz // [info] | +-baz
// [info] | // [info] |
// [info] +-quux // [info] +-quux
def toAscii[A](top: A, children: A => Seq[A], display: A => String): String = { def toAscii[A](top: A, children: A => Seq[A], display: A => String, defaultWidth: Int): String = {
val defaultWidth = 40 val maxColumn = math.max(JLine.usingTerminal(_.getWidth), defaultWidth) - 8
// TODO: Fix JLine
val maxColumn = math.max( /*JLine.usingTerminal(_.getWidth)*/ 0, defaultWidth) - 8
val twoSpaces = " " + " " // prevent accidentally being converted into a tab val twoSpaces = " " + " " // prevent accidentally being converted into a tab
def limitLine(s: String): String = def limitLine(s: String): String =
if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".." if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".."

View File

@ -6,15 +6,45 @@ import sbt.internal.util.RMap
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import TaskName._ import TaskName._
private[sbt] final class TaskTimings extends ExecuteProgress[Task] { /**
* Measure the time elapsed for running tasks.
* This class is activated by adding -Dsbt.task.timing=true to the JVM options.
* Formatting options:
* - -Dsbt.task.timings.on.shutdown=true|false
* - -Dsbt.task.timings.unit=number
* - -Dsbt.task.timings.threshold=number
* @param shutdown Should the report be given when exiting the JVM (true) or immediatelly (false)?
*/
private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[Task] {
private[this] val calledBy = new ConcurrentHashMap[Task[_], Task[_]] private[this] val calledBy = new ConcurrentHashMap[Task[_], Task[_]]
private[this] val anonOwners = new ConcurrentHashMap[Task[_], Task[_]] private[this] val anonOwners = new ConcurrentHashMap[Task[_], Task[_]]
private[this] val timings = new ConcurrentHashMap[Task[_], Long] private[this] val timings = new ConcurrentHashMap[Task[_], Long]
private[this] var start = 0L private[this] var start = 0L
private[this] val threshold = java.lang.Long.getLong("sbt.task.timings.threshold", 0L)
private[this] val omitPaths = java.lang.Boolean.getBoolean("sbt.task.timings.omit.paths")
private[this] val (unit, divider) = System.getProperty("sbt.task.timings.unit", "ms") match {
case "ns" => ("ns", 0)
case "us" => ("µs", 3)
case "ms" => ("ms", 6)
case "s" => ("sec", 9)
case x =>
System.err.println(s"Unknown sbt.task.timings.unit: $x.\nUsing milliseconds.")
("ms", 6)
}
type S = Unit type S = Unit
def initial = { start = System.nanoTime } if (shutdown) {
start = System.nanoTime
Runtime.getRuntime.addShutdownHook(new Thread {
override def run() = report()
})
}
def initial = {
if (!shutdown)
start = System.nanoTime
}
def registered(state: Unit, task: Task[_], allDeps: Iterable[Task[_]], pendingDeps: Iterable[Task[_]]) = { def registered(state: Unit, task: Task[_], allDeps: Iterable[Task[_]], pendingDeps: Iterable[Task[_]]) = {
pendingDeps foreach { t => if (transformNode(t).isEmpty) anonOwners.put(t, task) } pendingDeps foreach { t => if (transformNode(t).isEmpty) anonOwners.put(t, task) }
} }
@ -26,16 +56,34 @@ private[sbt] final class TaskTimings extends ExecuteProgress[Task] {
} }
def completed[T](state: Unit, task: Task[T], result: Result[T]) = () def completed[T](state: Unit, task: Task[T], result: Result[T]) = ()
def allCompleted(state: Unit, results: RMap[Task, Result]) = def allCompleted(state: Unit, results: RMap[Task, Result]) =
{ if (!shutdown) {
val total = System.nanoTime - start report()
println("Total time: " + (total * 1e-6) + " ms")
import collection.JavaConverters._
def sumTimes(in: Seq[(Task[_], Long)]) = in.map(_._2).sum
val timingsByName = timings.asScala.toSeq.groupBy { case (t, time) => mappedName(t) } mapValues (sumTimes)
for ((taskName, time) <- timingsByName.toSeq.sortBy(_._2).reverse)
println(" " + taskName + ": " + (time * 1e-6) + " ms")
} }
private val reFilePath = raw"\{[^}]+\}".r
private[this] def report() = {
val total = divide(System.nanoTime - start)
println(s"Total time: $total $unit")
import collection.JavaConverters._
def sumTimes(in: Seq[(Task[_], Long)]) = in.map(_._2).sum
val timingsByName = timings.asScala.toSeq.groupBy { case (t, time) => mappedName(t) } mapValues (sumTimes)
val times = timingsByName.toSeq.sortBy(_._2).reverse
.map {
case (name, time) =>
(if (omitPaths) reFilePath.replaceFirstIn(name, "") else name, divide(time))
}.filter { _._2 > threshold }
if (times.size > 0) {
val maxTaskNameLength = times.map { _._1.length }.max
val maxTime = times.map { _._2 }.max.toString.length
times.foreach {
case (taskName, time) =>
println(s" ${taskName.padTo(maxTaskNameLength, ' ')}: ${"".padTo(maxTime - time.toString.length, ' ')}$time $unit")
}
}
}
private[this] def inferredName(t: Task[_]): Option[String] = nameDelegate(t) map mappedName private[this] def inferredName(t: Task[_]): Option[String] = nameDelegate(t) map mappedName
private[this] def nameDelegate(t: Task[_]): Option[Task[_]] = Option(anonOwners.get(t)) orElse Option(calledBy.get(t)) private[this] def nameDelegate(t: Task[_]): Option[Task[_]] = Option(anonOwners.get(t)) orElse Option(calledBy.get(t))
private[this] def mappedName(t: Task[_]): String = definedName(t) orElse inferredName(t) getOrElse anonymousName(t) private[this] def mappedName(t: Task[_]): String = definedName(t) orElse inferredName(t) getOrElse anonymousName(t)
private[this] def divide(time: Long) = (1L to divider.toLong).fold(time) { (a, b) => a / 10L }
} }

View File

@ -0,0 +1,9 @@
[@RomanIakovlev]: https://github.com/RomanIakovlev
### Fixes with compatibility implications
### Improvements
Add new global setting `asciiGraphWidth` that controls the maximum width of the ASCII graphs printed by commands like `inspect tree`. Default value corresponds to the previously hardcoded value of 40 characters. By [@RomanIakovlev][@RomanIakovlev].
### Bug fixes

View File

@ -46,8 +46,6 @@ case class LoggedOutput(logger: Logger) extends OutputStrategy
*/ */
case class CustomOutput(output: OutputStream) extends OutputStrategy case class CustomOutput(output: OutputStream) extends OutputStrategy
import java.lang.{ ProcessBuilder => JProcessBuilder }
/** /**
* Represents a command that can be forked. * Represents a command that can be forked.
* *
@ -75,20 +73,16 @@ final class Fork(val commandName: String, val runnerClass: Option[String]) {
val executable = Fork.javaCommand(javaHome, commandName).getAbsolutePath val executable = Fork.javaCommand(javaHome, commandName).getAbsolutePath
val preOptions = makeOptions(runJVMOptions, bootJars, arguments) val preOptions = makeOptions(runJVMOptions, bootJars, arguments)
val (classpathEnv, options) = Fork.fitClasspath(preOptions) val (classpathEnv, options) = Fork.fitClasspath(preOptions)
val command = (executable +: options).toArray val command = executable +: options
val builder = new JProcessBuilder(command: _*)
workingDirectory.foreach(wd => builder.directory(wd)) val environment = env ++ classpathEnv.map(value => Fork.ClasspathEnvKey -> value)
val environment = builder.environment val process = Process(command, workingDirectory, environment.toList: _*)
for ((key, value) <- env)
environment.put(key, value)
for (cpenv <- classpathEnv)
// overriding, not appending, is correct due to the specified priorities of -classpath and CLASSPATH
environment.put(Fork.ClasspathEnvKey, cpenv)
outputStrategy.getOrElse(StdoutOutput) match { outputStrategy.getOrElse(StdoutOutput) match {
case StdoutOutput => Process(builder).run(connectInput) case StdoutOutput => process.run(connectInput)
case BufferedOutput(logger) => logger.buffer { Process(builder).run(logger, connectInput) } case BufferedOutput(logger) => logger.buffer { process.run(logger, connectInput) }
case LoggedOutput(logger) => Process(builder).run(logger, connectInput) case LoggedOutput(logger) => process.run(logger, connectInput)
case CustomOutput(output) => (Process(builder) #> output).run(connectInput) case CustomOutput(output) => (process #> output).run(connectInput)
} }
} }
private[this] def makeOptions(jvmOptions: Seq[String], bootJars: Iterable[File], arguments: Seq[String]): Seq[String] = private[this] def makeOptions(jvmOptions: Seq[String], bootJars: Iterable[File], arguments: Seq[String]): Seq[String] =

View File

@ -1,15 +0,0 @@
package sbt
import java.lang.{ ProcessBuilder => JProcessBuilder }
trait ProcessExtra {
import scala.sys.process._
import scala.sys.process.Process._
implicit def builderToProcess(builder: JProcessBuilder): ProcessBuilder = apply(builder)
implicit def fileToProcess(file: File): ProcessBuilder.FileBuilder = apply(file)
implicit def urlToProcess(url: URL): ProcessBuilder.URLBuilder = apply(url)
implicit def buildersToProcess[T](builders: Seq[T])(implicit convert: T => ProcessBuilder.Source): Seq[ProcessBuilder.Source] = applySeq(builders)
implicit def stringToProcess(command: String): ProcessBuilder = apply(command)
implicit def stringSeqToProcess(command: Seq[String]): ProcessBuilder = apply(command)
}

View File

@ -2,7 +2,7 @@ package sbt
object syntax extends syntax object syntax extends syntax
abstract class syntax extends IOSyntax0 with sbt.std.TaskExtra with sbt.internal.util.Types with sbt.ProcessExtra abstract class syntax extends IOSyntax0 with sbt.std.TaskExtra with sbt.internal.util.Types
with sbt.internal.librarymanagement.impl.DependencyBuilders with sbt.ProjectExtra with sbt.internal.librarymanagement.impl.DependencyBuilders with sbt.ProjectExtra
with sbt.internal.librarymanagement.DependencyFilterExtra with sbt.BuildExtra with sbt.TaskMacroExtra with sbt.internal.librarymanagement.DependencyFilterExtra with sbt.BuildExtra with sbt.TaskMacroExtra
with sbt.ScopeFilter.Make with sbt.ScopeFilter.Make

View File

@ -0,0 +1,23 @@
scalaOrganization := "org.other"
scalaArtifacts += "thing"
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
"org.other" % "thing" % "1.2.3",
"org.other" %% "wotsit" % "4.5.6"
)
lazy val check = taskKey[Unit]("Runs the check")
check := {
val lastLog = BuiltinCommands lastLogFile state.value
val last = IO read lastLog.get
def containsWarn1 = last contains "Binary version (1.2.3) for dependency org.other#thing;1.2.3"
def containsWarn2 = last contains "Binary version (4.5.6) for dependency org.other#wotsit_2.11;4.5.6"
def containsWarn3 = last contains "differs from Scala binary version in project (2.11)."
if (!containsWarn1) sys error "thing should not be exempted from the Scala binary version check"
if (containsWarn2) sys error "wotsit should be exempted from the Scala binary version check"
if (!containsWarn3) sys error "Binary version check failed"
}

View File

@ -0,0 +1,3 @@
> clean
> check