From 1f2c00cc567b03110369ba8c2ec3a16d09ff02f6 Mon Sep 17 00:00:00 2001 From: Kazuyoshi Kato Date: Wed, 26 Oct 2016 21:13:36 -0700 Subject: [PATCH 01/12] Remove ProcessExtra and the use of java.lang.ProcessBuilder Fixes #2736. --- MIGRATION.md | 1 + run/src/main/scala/sbt/Fork.scala | 24 +++++++++--------------- sbt/src/main/scala/ProcessExtra.scala | 15 --------------- sbt/src/main/scala/syntax.scala | 2 +- 4 files changed, 11 insertions(+), 31 deletions(-) delete mode 100644 sbt/src/main/scala/ProcessExtra.scala diff --git a/MIGRATION.md b/MIGRATION.md index 6f7d67952..e9e3e026b 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -12,6 +12,7 @@ Migration notes - Removes no-longer-documented old operators `<<=`, `<+=`, and `<++=`. - Renames early command feature from `--` to `early()`. - 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 diff --git a/run/src/main/scala/sbt/Fork.scala b/run/src/main/scala/sbt/Fork.scala index 917872424..2ebb56f28 100644 --- a/run/src/main/scala/sbt/Fork.scala +++ b/run/src/main/scala/sbt/Fork.scala @@ -46,8 +46,6 @@ case class LoggedOutput(logger: Logger) extends OutputStrategy */ case class CustomOutput(output: OutputStream) extends OutputStrategy -import java.lang.{ ProcessBuilder => JProcessBuilder } - /** * Represents a commad 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 preOptions = makeOptions(runJVMOptions, bootJars, arguments) val (classpathEnv, options) = Fork.fitClasspath(preOptions) - val command = (executable +: options).toArray - val builder = new JProcessBuilder(command: _*) - workingDirectory.foreach(wd => builder.directory(wd)) - val environment = builder.environment - 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) + val command = executable +: options + + val environment = env ++ classpathEnv.map(value => Fork.ClasspathEnvKey -> value) + val process = Process(command, workingDirectory, environment.toList: _*) + outputStrategy.getOrElse(StdoutOutput) match { - case StdoutOutput => Process(builder).run(connectInput) - case BufferedOutput(logger) => logger.buffer { Process(builder).run(logger, connectInput) } - case LoggedOutput(logger) => Process(builder).run(logger, connectInput) - case CustomOutput(output) => (Process(builder) #> output).run(connectInput) + case StdoutOutput => process.run(connectInput) + case BufferedOutput(logger) => logger.buffer { process.run(logger, connectInput) } + case LoggedOutput(logger) => process.run(logger, connectInput) + case CustomOutput(output) => (process #> output).run(connectInput) } } private[this] def makeOptions(jvmOptions: Seq[String], bootJars: Iterable[File], arguments: Seq[String]): Seq[String] = diff --git a/sbt/src/main/scala/ProcessExtra.scala b/sbt/src/main/scala/ProcessExtra.scala deleted file mode 100644 index 4625c6c90..000000000 --- a/sbt/src/main/scala/ProcessExtra.scala +++ /dev/null @@ -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) -} diff --git a/sbt/src/main/scala/syntax.scala b/sbt/src/main/scala/syntax.scala index 1472bec1f..b1400cbe7 100644 --- a/sbt/src/main/scala/syntax.scala +++ b/sbt/src/main/scala/syntax.scala @@ -5,7 +5,7 @@ import sbt.internal.util.Eval 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.DependencyFilterExtra with sbt.BuildExtra with sbt.TaskMacroExtra with sbt.ScopeFilter.Make { From b9c3a56454669a58bd1eaab78a6356ea0702cea2 Mon Sep 17 00:00:00 2001 From: David Perez Date: Tue, 1 Sep 2015 14:36:33 +0200 Subject: [PATCH 02/12] Changed logging from error to debug, because it is quite annoying the error message when autocompleting --- main/src/main/scala/sbt/Main.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 1aaa9333d..3499c9e28 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -221,7 +221,7 @@ object BuiltinCommands { Some(index.keyMap(key)) catch { case NonFatal(ex) => - s.log error ex.getMessage + s.log debug ex.getMessage None } }.collect { case Some(s) => s }.distinct From 70fa960f564c91fad09199a9cdf38108a0ac0a2c Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 16 Sep 2015 16:31:12 +0200 Subject: [PATCH 03/12] Improved time logging capabilities --- main/src/main/scala/sbt/EvaluateTask.scala | 9 ++- .../main/scala/sbt/internal/TaskTimings.scala | 56 +++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index b99fe54b8..b1d4facf6 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -150,8 +150,15 @@ object EvaluateTask { import std.Transform import Keys.state + lazy private val sharedProgress = new TaskTimings(shutdown = true) + 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.shutdown")) + sharedProgress + else + new TaskTimings(shutdown = false) + } else ExecuteProgress.empty[Task] val SystemProcessors = Runtime.getRuntime.availableProcessors diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index 5a9d8e46d..977e21f33 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -6,15 +6,43 @@ import sbt.internal.util.RMap import java.util.concurrent.ConcurrentHashMap 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.shutdown=true|false + * - -Dsbt.task.timings.decimals=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 anonOwners = new ConcurrentHashMap[Task[_], Task[_]] private[this] val timings = new ConcurrentHashMap[Task[_], Long] private[this] var start = 0L + private[this] val divider = java.lang.Integer.getInteger("sbt.task.timings.divider", 6).toInt + private[this] val threshold = java.lang.Long.getLong("sbt.task.timings.threshold", 0L) + private[this] val unit = divider match { + case 0 => "ns" + case 3 => "µs" + case 6 => "ms" + case 9 => "sec" + case _ => "" + } 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[_]]) = { pendingDeps foreach { t => if (transformNode(t).isEmpty) anonOwners.put(t, task) } } @@ -26,16 +54,24 @@ private[sbt] final class TaskTimings extends ExecuteProgress[Task] { } def completed[T](state: Unit, task: Task[T], result: Result[T]) = () def allCompleted(state: Unit, results: RMap[Task, Result]) = - { - val total = System.nanoTime - start - 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") + if (!shutdown) { + report() } + + 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) + for ( + (taskName, time) <- timingsByName.toSeq.sortBy(_._2).reverse + .map { case (name, time) => (name, divide(time)) } + .filter { _._2 > threshold } + ) println(s" $taskName: $time $unit") + } 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 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 } } From 4f5c5c92a200335031b3ced91f7fdc401f6d928b Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 16 Sep 2015 17:07:19 +0200 Subject: [PATCH 04/12] Alignment of reported time measuring data --- .../main/scala/sbt/internal/TaskTimings.scala | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index 977e21f33..1f23d82b0 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -64,11 +64,17 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ 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 - .map { case (name, time) => (name, divide(time)) } - .filter { _._2 > threshold } - ) println(s" $taskName: $time $unit") + val times = timingsByName.toSeq.sortBy(_._2).reverse + .map { case (name, time) => (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 nameDelegate(t: Task[_]): Option[Task[_]] = Option(anonOwners.get(t)) orElse Option(calledBy.get(t)) From 6ab0bc403abd130de1e70823208c85e6068e3826 Mon Sep 17 00:00:00 2001 From: David Perez Date: Thu, 17 Sep 2015 08:44:37 +0200 Subject: [PATCH 05/12] Renamed: sbt.task.timings.shutdown -> sbt.task.timings.on.shutdown sbt.task.timings.divider -> sbt.task.timings.unit --- main/src/main/scala/sbt/EvaluateTask.scala | 2 +- .../main/scala/sbt/internal/TaskTimings.scala | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index b1d4facf6..08d2571ea 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -154,7 +154,7 @@ object EvaluateTask { private[sbt] def defaultProgress: ExecuteProgress[Task] = if (java.lang.Boolean.getBoolean("sbt.task.timings")) { - if (java.lang.Boolean.getBoolean("sbt.task.timings.shutdown")) + if (java.lang.Boolean.getBoolean("sbt.task.timings.on.shutdown")) sharedProgress else new TaskTimings(shutdown = false) diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index 1f23d82b0..4767c1544 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -10,8 +10,8 @@ import TaskName._ * 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.shutdown=true|false - * - -Dsbt.task.timings.decimals=number + * - -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)? */ @@ -20,14 +20,15 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ private[this] val anonOwners = new ConcurrentHashMap[Task[_], Task[_]] private[this] val timings = new ConcurrentHashMap[Task[_], Long] private[this] var start = 0L - private[this] val divider = java.lang.Integer.getInteger("sbt.task.timings.divider", 6).toInt private[this] val threshold = java.lang.Long.getLong("sbt.task.timings.threshold", 0L) - private[this] val unit = divider match { - case 0 => "ns" - case 3 => "µs" - case 6 => "ms" - case 9 => "sec" - case _ => "" + 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 From 618487eb582882a0824ea2d78deec7512bdd625f Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 30 Sep 2015 08:52:59 +0200 Subject: [PATCH 06/12] New option sbt.task.timings.omit.paths, to produce even cleaner reports. --- main/src/main/scala/sbt/internal/TaskTimings.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index 4767c1544..d6acbeaaa 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -21,6 +21,7 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ private[this] val timings = new ConcurrentHashMap[Task[_], Long] 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) @@ -59,6 +60,8 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ report() } + private val reFilePath = raw"\{[^}]+\}".r + private[this] def report() = { val total = divide(System.nanoTime - start) println(s"Total time: $total $unit") @@ -66,8 +69,10 @@ private[sbt] final class TaskTimings(shutdown: Boolean) extends ExecuteProgress[ 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) => (name, divide(time)) } - .filter { _._2 > threshold } + .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 From 56e843960bb0c7ed8ecbf3f4eb599daca3950cb4 Mon Sep 17 00:00:00 2001 From: Miles Sabin Date: Mon, 22 Aug 2016 11:03:27 +0100 Subject: [PATCH 07/12] Configurable explicit list of artifacts for Scala binary version check --- main/src/main/scala/sbt/Defaults.scala | 5 +++- main/src/main/scala/sbt/Keys.scala | 1 + .../build.sbt | 23 +++++++++++++++++++ .../scala-organization-version-check/test | 3 +++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 sbt/src/sbt-test/dependency-management/scala-organization-version-check/build.sbt create mode 100644 sbt/src/sbt-test/dependency-management/scala-organization-version-check/test diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index c6b98d0d9..155ce1137 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -155,6 +155,7 @@ object Defaults extends BuildCommon { retrieveManagedSync :== false, configurationsToRetrieve :== None, scalaOrganization :== ScalaArtifacts.Organization, + scalaArtifacts :== ScalaArtifacts.Artifacts, sbtResolver := { if (sbtVersion.value endsWith "-SNAPSHOT") Classpaths.sbtIvySnapshots else Classpaths.typesafeReleases }, crossVersion :== Disabled(), buildDependencies := Classpaths.constructBuildDependencies.value, @@ -1431,7 +1432,9 @@ object Classpaths { (scalaVersion in update).value, (scalaBinaryVersion in update).value, Vector.empty, filterImplicit = false, checkExplicit = true, overrideScalaVersion = true - ).withScalaOrganization(scalaOrganization.value)) + ) + .withScalaOrganization(scalaOrganization.value) + .withScalaArtifacts(scalaArtifacts.value)) } )).value, artifactPath in makePom := artifactPathSetting(artifact in makePom).value, diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 5a5f10f5c..3d498e4f4 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -194,6 +194,7 @@ object Keys { val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask) val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting) val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting) + val scalaArtifacts = SettingKey[Vector[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 console = TaskKey[Unit]("console", "Starts the Scala interpreter with the project classes on the classpath.", APlusTask) diff --git a/sbt/src/sbt-test/dependency-management/scala-organization-version-check/build.sbt b/sbt/src/sbt-test/dependency-management/scala-organization-version-check/build.sbt new file mode 100644 index 000000000..efb198677 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/scala-organization-version-check/build.sbt @@ -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" +} diff --git a/sbt/src/sbt-test/dependency-management/scala-organization-version-check/test b/sbt/src/sbt-test/dependency-management/scala-organization-version-check/test new file mode 100644 index 000000000..760ba6309 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/scala-organization-version-check/test @@ -0,0 +1,3 @@ +> clean + +> check From cfecf1f6b9e39a04e5c3951f57efc3b3a1368997 Mon Sep 17 00:00:00 2001 From: Justin Kaeser Date: Fri, 18 Nov 2016 12:21:34 +0300 Subject: [PATCH 08/12] avoid IntelliJ marking valid code as erroneous relative imports and "println _" cause error highlighting in IntelliJ --- main/src/main/scala/sbt/Main.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 3499c9e28..dc6017da4 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -27,7 +27,7 @@ import sbt.internal.{ import sbt.internal.util.{ AttributeKey, AttributeMap, complete, ConsoleOut, GlobalLogging, LineRange, MainAppender, SimpleReader, Types } import sbt.util.{ Level, Logger } -import complete.{ DefaultParsers, Parser } +import sbt.internal.util.complete.{ DefaultParsers, Parser } import sbt.internal.inc.{ CompilerCache, ScalaInstance } import sbt.compiler.EvalImports import Types.{ const, idFun } @@ -356,7 +356,7 @@ object BuiltinCommands { val extracted = Project extract s import extracted.{ showKey, structure } 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 { lastOnly_keys <- keysParser kvs = Act.keyValues(structure)(lastOnly_keys._2) From 6c4cf28202cbecf9773cf01e0f3d4ffd270ff88d Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 22 Jan 2017 12:57:16 -0500 Subject: [PATCH 09/12] Fix dependency-management/scala-organization-version-check No implicit for Append.Value[Vector[String], String] found --- main/src/main/scala/sbt/Defaults.scala | 2 +- main/src/main/scala/sbt/Keys.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 155ce1137..205085662 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1434,7 +1434,7 @@ object Classpaths { Vector.empty, filterImplicit = false, checkExplicit = true, overrideScalaVersion = true ) .withScalaOrganization(scalaOrganization.value) - .withScalaArtifacts(scalaArtifacts.value)) + .withScalaArtifacts(scalaArtifacts.value.toVector)) } )).value, artifactPath in makePom := artifactPathSetting(artifact in makePom).value, diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 3d498e4f4..51550f6a0 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -194,7 +194,7 @@ object Keys { val printWarnings = TaskKey[Unit]("print-warnings", "Shows warnings from compilation, including ones that weren't printed initially.", BPlusTask) val fileInputOptions = SettingKey[Seq[String]]("file-input-options", "Options that take file input, which may invalidate the cache.", CSetting) val scalaCompilerBridgeSource = SettingKey[ModuleID]("scala-compiler-bridge-source", "Configures the module ID of the sources of the compiler bridge.", CSetting) - val scalaArtifacts = SettingKey[Vector[String]]("scala-artifacts", "Configures the list of artifacts which should match the Scala binary version", 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 console = TaskKey[Unit]("console", "Starts the Scala interpreter with the project classes on the classpath.", APlusTask) From 982a7c87241af974436e1ee60f6ade6c3bed0255 Mon Sep 17 00:00:00 2001 From: Roman Iakovlev Date: Mon, 30 May 2016 12:11:44 +0200 Subject: [PATCH 10/12] Add new SBT global setting asciiGraphWidth This setting 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. --- .gitignore | 1 + main/src/main/scala/sbt/Defaults.scala | 3 ++- main/src/main/scala/sbt/Keys.scala | 1 + main/src/main/scala/sbt/Project.scala | 4 ++-- main/src/main/scala/sbt/internal/Inspect.scala | 2 +- .../src/main/scala/sbt/internal/SettingGraph.scala | 14 ++++++++------ notes/1.0.0/ascii-graph-width.markdown | 9 +++++++++ 7 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 notes/1.0.0/ascii-graph-width.markdown diff --git a/.gitignore b/.gitignore index e762de7f9..03aec7c81 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target/ __pycache__ +.idea diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 382acbfbe..09f0cc749 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -362,7 +362,8 @@ object Defaults extends BuildCommon { private[this] lazy val configGlobal = globalDefaults(Seq( initialCommands :== "", - cleanupCommands :== "" + cleanupCommands :== "", + asciiGraphWidth :== 40 )) lazy val projectTasks: Seq[Setting[_]] = Seq( diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index fcf980d93..6fa80a7f8 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -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 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 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 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) diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index d1f54a525..76323ae27 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -534,8 +534,8 @@ object Project extends ProjectExtra { printScopes("Delegates", delegates(structure, scope, key)) + printScopes("Related", related, 10) } - def settingGraph(structure: BuildStructure, basedir: File, scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): SettingGraph = - SettingGraph(structure, basedir, scoped, 0) + def settingGraph(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], maxGraphWidth: Int)(implicit display: Show[ScopedKey[_]]): SettingGraph = + SettingGraph(structure, basedir, scoped, 0, maxGraphWidth) def graphSettings(structure: BuildStructure, basedir: File)(implicit display: Show[ScopedKey[_]]): Unit = { def graph(actual: Boolean, name: String) = graphSettings(structure, actual, name, new File(basedir, name + ".dot")) graph(true, "actual_dependencies") diff --git a/main/src/main/scala/sbt/internal/Inspect.scala b/main/src/main/scala/sbt/internal/Inspect.scala index 0d1e9ff6a..98d3759b3 100644 --- a/main/src/main/scala/sbt/internal/Inspect.scala +++ b/main/src/main/scala/sbt/internal/Inspect.scala @@ -47,7 +47,7 @@ object Inspect { Project.details(structure, actual, sk.scope, sk.key) case DependencyTreeMode => val basedir = new File(Project.session(s).current.build) - Project.settingGraph(structure, basedir, sk).dependsAscii + Project.settingGraph(structure, basedir, sk, get(sbt.Keys.asciiGraphWidth)).dependsAscii case UsesMode => Project.showUses(Project.usedBy(structure, true, sk.key)) case DefinitionsMode => diff --git a/main/src/main/scala/sbt/internal/SettingGraph.scala b/main/src/main/scala/sbt/internal/SettingGraph.scala index ec2b62df6..de12baea6 100644 --- a/main/src/main/scala/sbt/internal/SettingGraph.scala +++ b/main/src/main/scala/sbt/internal/SettingGraph.scala @@ -13,7 +13,7 @@ import Predef.{ any2stringadd => _, _ } import sbt.io.IO object SettingGraph { - def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int)(implicit display: Show[ScopedKey[_]]): SettingGraph = + def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int, graphMaxWidth: Int)(implicit display: Show[ScopedKey[_]]): SettingGraph = { val cMap = flattenLocals(compiled(structure.settings, false)(structure.delegates, structure.scopeLocal, display)) def loop(scoped: ScopedKey[_], generation: Int): SettingGraph = @@ -28,7 +28,8 @@ object SettingGraph { SettingGraph(display(scoped), definedIn, Project.scopedKeyData(structure, scope, key), key.description, basedir, - depends map { (x: ScopedKey[_]) => loop(x, generation + 1) }) + depends map { (x: ScopedKey[_]) => loop(x, generation + 1) }, + graphMaxWidth) } loop(scoped, generation) } @@ -40,7 +41,8 @@ case class SettingGraph( data: Option[ScopedKeyData[_]], description: Option[String], basedir: File, - depends: Set[SettingGraph] + depends: Set[SettingGraph], + graphMaxWidth: Int ) { def dataString: String = data map { d => @@ -53,7 +55,8 @@ case class SettingGraph( def dependsAscii: String = Graph.toAscii( this, (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), + graphMaxWidth ) } @@ -63,8 +66,7 @@ object Graph { // [info] | +-baz // [info] | // [info] +-quux - def toAscii[A](top: A, children: A => Seq[A], display: A => String): String = { - val defaultWidth = 40 + def toAscii[A](top: A, children: A => Seq[A], display: A => String, defaultWidth: Int): String = { // TODO: Fix JLine val maxColumn = math.max( /*JLine.usingTerminal(_.getWidth)*/ 0, defaultWidth) - 8 val twoSpaces = " " + " " // prevent accidentally being converted into a tab diff --git a/notes/1.0.0/ascii-graph-width.markdown b/notes/1.0.0/ascii-graph-width.markdown new file mode 100644 index 000000000..341577b3e --- /dev/null +++ b/notes/1.0.0/ascii-graph-width.markdown @@ -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 From e8b951c0d1fe2d0aef550173c1be4bd597636246 Mon Sep 17 00:00:00 2001 From: Roman Iakovlev Date: Mon, 30 May 2016 18:33:26 +0200 Subject: [PATCH 11/12] Review comments for https://github.com/sbt/sbt/pull/2633 --- .gitignore | 1 - main/src/main/scala/sbt/Project.scala | 4 ++-- main/src/main/scala/sbt/internal/Inspect.scala | 2 +- main/src/main/scala/sbt/internal/SettingGraph.scala | 12 +++++------- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 03aec7c81..e762de7f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ target/ __pycache__ -.idea diff --git a/main/src/main/scala/sbt/Project.scala b/main/src/main/scala/sbt/Project.scala index 76323ae27..d1f54a525 100755 --- a/main/src/main/scala/sbt/Project.scala +++ b/main/src/main/scala/sbt/Project.scala @@ -534,8 +534,8 @@ object Project extends ProjectExtra { printScopes("Delegates", delegates(structure, scope, key)) + printScopes("Related", related, 10) } - def settingGraph(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], maxGraphWidth: Int)(implicit display: Show[ScopedKey[_]]): SettingGraph = - SettingGraph(structure, basedir, scoped, 0, maxGraphWidth) + def settingGraph(structure: BuildStructure, basedir: File, scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): SettingGraph = + SettingGraph(structure, basedir, scoped, 0) def graphSettings(structure: BuildStructure, basedir: File)(implicit display: Show[ScopedKey[_]]): Unit = { def graph(actual: Boolean, name: String) = graphSettings(structure, actual, name, new File(basedir, name + ".dot")) graph(true, "actual_dependencies") diff --git a/main/src/main/scala/sbt/internal/Inspect.scala b/main/src/main/scala/sbt/internal/Inspect.scala index 98d3759b3..90cfa5348 100644 --- a/main/src/main/scala/sbt/internal/Inspect.scala +++ b/main/src/main/scala/sbt/internal/Inspect.scala @@ -47,7 +47,7 @@ object Inspect { Project.details(structure, actual, sk.scope, sk.key) case DependencyTreeMode => val basedir = new File(Project.session(s).current.build) - Project.settingGraph(structure, basedir, sk, get(sbt.Keys.asciiGraphWidth)).dependsAscii + Project.settingGraph(structure, basedir, sk).dependsAscii(get(sbt.Keys.asciiGraphWidth)) case UsesMode => Project.showUses(Project.usedBy(structure, true, sk.key)) case DefinitionsMode => diff --git a/main/src/main/scala/sbt/internal/SettingGraph.scala b/main/src/main/scala/sbt/internal/SettingGraph.scala index de12baea6..d181c01d5 100644 --- a/main/src/main/scala/sbt/internal/SettingGraph.scala +++ b/main/src/main/scala/sbt/internal/SettingGraph.scala @@ -13,7 +13,7 @@ import Predef.{ any2stringadd => _, _ } import sbt.io.IO object SettingGraph { - def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int, graphMaxWidth: Int)(implicit display: Show[ScopedKey[_]]): SettingGraph = + def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int)(implicit display: Show[ScopedKey[_]]): SettingGraph = { val cMap = flattenLocals(compiled(structure.settings, false)(structure.delegates, structure.scopeLocal, display)) def loop(scoped: ScopedKey[_], generation: Int): SettingGraph = @@ -28,8 +28,7 @@ object SettingGraph { SettingGraph(display(scoped), definedIn, Project.scopedKeyData(structure, scope, key), key.description, basedir, - depends map { (x: ScopedKey[_]) => loop(x, generation + 1) }, - graphMaxWidth) + depends map { (x: ScopedKey[_]) => loop(x, generation + 1) }) } loop(scoped, generation) } @@ -41,8 +40,7 @@ case class SettingGraph( data: Option[ScopedKeyData[_]], description: Option[String], basedir: File, - depends: Set[SettingGraph], - graphMaxWidth: Int + depends: Set[SettingGraph] ) { def dataString: String = data map { d => @@ -52,11 +50,11 @@ case class SettingGraph( } getOrElse { d.typeName } } getOrElse { "" } - def dependsAscii: String = Graph.toAscii( + def dependsAscii(defaultWidth: Int): String = Graph.toAscii( this, (x: SettingGraph) => x.depends.toSeq.sortBy(_.name), (x: SettingGraph) => "%s = %s" format (x.definedIn getOrElse { "" }, x.dataString), - graphMaxWidth + defaultWidth ) } From e2c7f58a140fba5f1e55190e10f648e762b70b42 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 22 Jan 2017 13:13:40 -0500 Subject: [PATCH 12/12] Uncomment JLine.usingTerminal --- main/src/main/scala/sbt/internal/SettingGraph.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main/src/main/scala/sbt/internal/SettingGraph.scala b/main/src/main/scala/sbt/internal/SettingGraph.scala index d181c01d5..dfd0e2ec3 100644 --- a/main/src/main/scala/sbt/internal/SettingGraph.scala +++ b/main/src/main/scala/sbt/internal/SettingGraph.scala @@ -4,7 +4,7 @@ package sbt package internal -import sbt.internal.util.Show +import sbt.internal.util.{ Show, JLine } import java.io.File import Def.{ compiled, flattenLocals, ScopedKey } @@ -65,8 +65,7 @@ object Graph { // [info] | // [info] +-quux def toAscii[A](top: A, children: A => Seq[A], display: A => String, defaultWidth: Int): String = { - // TODO: Fix JLine - val maxColumn = math.max( /*JLine.usingTerminal(_.getWidth)*/ 0, defaultWidth) - 8 + val maxColumn = math.max(JLine.usingTerminal(_.getWidth), defaultWidth) - 8 val twoSpaces = " " + " " // prevent accidentally being converted into a tab def limitLine(s: String): String = if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".."