diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index e6327c609..12d8cc4e1 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -164,7 +164,6 @@ object Defaults extends BuildCommon { private[sbt] lazy val globalJvmCore: Seq[Setting[_]] = Seq( compilerCache := state.value get Keys.stateCompilerCache getOrElse CompilerCache.fresh, - classLoaderLayeringStrategy :== ClassLoaderLayeringStrategy.AllLibraryJars, sourcesInBase :== true, autoAPIMappings := false, apiMappings := Map.empty, @@ -211,7 +210,7 @@ object Defaults extends BuildCommon { exportJars :== false, trackInternalDependencies :== TrackLevel.TrackAlways, exportToInternal :== TrackLevel.TrackAlways, - useCoursier :== LibraryManagement.defaultUseCoursier, + useCoursier :== SysProp.defaultUseCoursier, retrieveManaged :== false, retrieveManagedSync :== false, configurationsToRetrieve :== None, @@ -285,7 +284,8 @@ object Defaults extends BuildCommon { val tempDirectory = taskTemporaryDirectory.value () => Clean.deleteContents(tempDirectory, _ => false) }, - useSuperShell := { if (insideCI.value) false else sbt.internal.TaskProgress.isEnabled }, + turbo :== SysProp.turbo, + useSuperShell := { if (insideCI.value) false else SysProp.supershell }, progressReports := { val progress = useSuperShell.value val rs = EvaluateTask.taskTimingProgress.toVector ++ @@ -337,7 +337,7 @@ object Defaults extends BuildCommon { ++ Vector(ServerHandler.fallback)) }, insideCI :== sys.env.contains("BUILD_NUMBER") || - sys.env.contains("CI") || System.getProperty("sbt.ci", "false") == "true", + sys.env.contains("CI") || SysProp.ci, // watch related settings pollInterval :== Watch.defaultPollInterval, ) @@ -1049,7 +1049,7 @@ object Defaults extends BuildCommon { cp, forkedParallelExecution = false, javaOptions = Nil, - strategy = ClassLoaderLayeringStrategy.AllLibraryJars, + strategy = ClassLoaderLayeringStrategy.ScalaLibrary, projectId = "", ) } @@ -1072,7 +1072,7 @@ object Defaults extends BuildCommon { cp, forkedParallelExecution, javaOptions = Nil, - strategy = ClassLoaderLayeringStrategy.AllLibraryJars, + strategy = ClassLoaderLayeringStrategy.ScalaLibrary, projectId = "", ) } @@ -1886,7 +1886,11 @@ object Defaults extends BuildCommon { } val base = ModuleID(id.groupID, id.name, sv).withCrossVersion(cross) CrossVersion(scalaV, binVersion)(base).withCrossVersion(Disabled()) - } + }, + classLoaderLayeringStrategy := { + if (turbo.value) ClassLoaderLayeringStrategy.AllLibraryJars + else ClassLoaderLayeringStrategy.ScalaLibrary + }, ) // build.sbt is treated a Scala source of metabuild, so to enable deprecation flag on build.sbt we set the option here. lazy val deprecationSettings: Seq[Setting[_]] = @@ -2072,7 +2076,7 @@ object Classpaths { licenses :== Nil, developers :== Nil, scmInfo :== None, - offline :== java.lang.Boolean.getBoolean("sbt.offline"), + offline :== SysProp.offline, defaultConfiguration :== Some(Configurations.Compile), dependencyOverrides :== Vector.empty, libraryDependencies :== Nil, diff --git a/main/src/main/scala/sbt/EvaluateTask.scala b/main/src/main/scala/sbt/EvaluateTask.scala index d83ea65cd..784fd8197 100644 --- a/main/src/main/scala/sbt/EvaluateTask.scala +++ b/main/src/main/scala/sbt/EvaluateTask.scala @@ -156,8 +156,8 @@ object EvaluateTask { lazy private val sharedProgress = new TaskTimings(reportOnShutdown = true) def taskTimingProgress: Option[ExecuteProgress[Task]] = - if (java.lang.Boolean.getBoolean("sbt.task.timings")) { - if (java.lang.Boolean.getBoolean("sbt.task.timings.on.shutdown")) + if (SysProp.taskTimings) { + if (SysProp.taskTimingsOnShutdown) Some(sharedProgress) else Some(new TaskTimings(reportOnShutdown = false)) @@ -165,7 +165,7 @@ object EvaluateTask { lazy private val sharedTraceEvent = new TaskTraceEvent() def taskTraceEvent: Option[ExecuteProgress[Task]] = - if (java.lang.Boolean.getBoolean("sbt.traces")) { + if (SysProp.traces) { Some(sharedTraceEvent) } else None diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index a38f143c3..001db1bf8 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -474,6 +474,7 @@ object Keys { def apply(progress: ExecuteProgress[Task]): TaskProgress = new TaskProgress(progress) } val useSuperShell = settingKey[Boolean]("Enables (true) or disables the super shell.") + val turbo = settingKey[Boolean]("Enables (true) or disables optional performance features.") // This key can be used to add custom ExecuteProgress instances val progressReports = settingKey[Seq[TaskProgress]]("A function that returns a list of progress reporters.").withRank(DTask) private[sbt] val postProgressReports = settingKey[Unit]("Internally used to modify logger.").withRank(DTask) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 520c51a2d..3fb29afca 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -47,7 +47,7 @@ private[sbt] object xMainImpl { import sbt.internal.client.NetworkClient // if we detect -Dsbt.client=true or -client, run thin client. - val clientModByEnv = java.lang.Boolean.getBoolean("sbt.client") + val clientModByEnv = SysProp.client val userCommands = configuration.arguments.map(_.trim) if (clientModByEnv || (userCommands.exists { cmd => (cmd == DashClient) || (cmd == DashDashClient) @@ -845,18 +845,11 @@ object BuiltinCommands { def registerCompilerCache(s: State): State = { s.get(Keys.stateCompilerCache).foreach(_.clear()) - val maxCompilers = System.getProperty("sbt.resident.limit") + + val maxCompilers: Int = SysProp.residentLimit val cache = - if (maxCompilers == null) - CompilerCache.fresh - else { - val num = try maxCompilers.toInt - catch { - case e: NumberFormatException => - throw new RuntimeException("Resident compiler limit must be an integer.", e) - } - if (num <= 0) CompilerCache.fresh else CompilerCache.createCacheFor(num) - } + if (maxCompilers <= 0) CompilerCache.fresh + else CompilerCache.createCacheFor(maxCompilers) s.put(Keys.stateCompilerCache, cache) } @@ -925,7 +918,7 @@ object BuiltinCommands { state.remainingCommands exists (_.commandLine == TemplateCommand) private def writeSbtVersion(state: State) = - if (!java.lang.Boolean.getBoolean("sbt.skip.version.write") && !intendsToInvokeNew(state)) + if (SysProp.genBuildProps && !intendsToInvokeNew(state)) writeSbtVersionUnconditionally(state) private def WriteSbtVersion = "writeSbtVersion" diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index f212e5b64..890f82a80 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -324,7 +324,7 @@ private[sbt] object Continuous extends DeprecatedContinuous { isCommand: Boolean ): State = withCharBufferedStdIn { in => implicit val extracted: Extracted = Project.extract(state) - val repo = if ("polling" == System.getProperty("sbt.watch.mode")) { + val repo = if ("polling" == SysProp.watchMode) { val service = new PollingWatchService(extracted.getOpt(pollInterval).getOrElse(500.millis)) FileTreeRepository .legacy((_: Any) => {}, service) diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index 713e59402..5952da063 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -10,7 +10,6 @@ package internal import java.io.File import sbt.internal.librarymanagement._ -import sbt.internal.util.{ ConsoleAppender, LogOption } import sbt.librarymanagement._ import sbt.librarymanagement.syntax._ import sbt.util.{ CacheStore, CacheStoreFactory, Logger, Tracked } @@ -20,31 +19,6 @@ private[sbt] object LibraryManagement { private type UpdateInputs = (Long, ModuleSettings, UpdateConfiguration) - def defaultUseCoursier: Boolean = { - val coursierOpt = sys.props - .get("sbt.coursier") - .flatMap( - str => - ConsoleAppender.parseLogOption(str) match { - case LogOption.Always => Some(true) - case LogOption.Never => Some(false) - case _ => None - } - ) - val ivyOpt = sys.props - .get("sbt.ivy") - .flatMap( - str => - ConsoleAppender.parseLogOption(str) match { - case LogOption.Always => Some(true) - case LogOption.Never => Some(false) - case _ => None - } - ) - val notIvyOpt = ivyOpt map { !_ } - coursierOpt.orElse(notIvyOpt).getOrElse(true) - } - def cachedUpdate( lm: DependencyResolution, module: ModuleDescriptor, diff --git a/main/src/main/scala/sbt/internal/SysProp.scala b/main/src/main/scala/sbt/internal/SysProp.scala new file mode 100644 index 000000000..c5dd716f0 --- /dev/null +++ b/main/src/main/scala/sbt/internal/SysProp.scala @@ -0,0 +1,123 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package internal + +import java.util.Locale +import scala.util.control.NonFatal +import sbt.internal.util.ConsoleAppender + +// See also BuildPaths.scala +// See also LineReader.scala +object SysProp { + def booleanOpt(name: String): Option[Boolean] = + sys.props.get(name).flatMap { x => + x.toLowerCase(Locale.ENGLISH) match { + case "1" | "always" | "true" => Some(true) + case "0" | "never" | "false" => Some(false) + case "auto" => None + case _ => None + } + } + + def getOrFalse(name: String): Boolean = booleanOpt(name).getOrElse(false) + def getOrTrue(name: String): Boolean = booleanOpt(name).getOrElse(true) + + def long(name: String, default: Long): Long = + sys.props.get(name) match { + case Some(str) => + try { + str.toLong + } catch { + case NonFatal(_) => default + } + case _ => default + } + + def int(name: String, default: Int): Int = + sys.props.get(name) match { + case Some(str) => + try { + str.toInt + } catch { + case NonFatal(_) => default + } + case _ => default + } + + // System property style: + // 1. use sbt. prefix + // 2. prefer short nouns + // 3. use dot for namespacing, and avoid making dot-separated English phrase + // 4. make active/enable properties, instead of "sbt.disable." + // + // Good: sbt.offline + // + // Bad: + // sbt.disable.interface.classloader.cache + // sbt.task.timings.on.shutdown + // sbt.skip.version.write -> sbt.genbuildprops=false + + def offline: Boolean = getOrFalse("sbt.offline") + def traces: Boolean = getOrFalse("sbt.traces") + def client: Boolean = getOrFalse("sbt.client") + def ci: Boolean = getOrFalse("sbt.ci") + + def watchMode: String = + sys.props.get("sbt.watch.mode").getOrElse("auto") + + def residentLimit: Int = int("sbt.resident.limit", 0) + + /** + * Indicates whether formatting has been disabled in environment variables. + * 1. -Dsbt.log.noformat=true means no formatting. + * 2. -Dsbt.color=always/auto/never/true/false + * 3. -Dsbt.colour=always/auto/never/true/false + * 4. -Dsbt.log.format=always/auto/never/true/false + */ + lazy val color: Boolean = ConsoleAppender.formatEnabledInEnv + + def supershell: Boolean = color && getOrTrue("sbt.supershell") + + def supersheelSleep: Long = long("sbt.supershell.sleep", 100L) + + def defaultUseCoursier: Boolean = { + val coursierOpt = booleanOpt("sbt.coursier") + val ivyOpt = booleanOpt("sbt.ivy") + val notIvyOpt = ivyOpt map { !_ } + coursierOpt.orElse(notIvyOpt).getOrElse(true) + } + + def turbo: Boolean = getOrFalse("sbt.turbo") + + def taskTimings: Boolean = getOrFalse("sbt.task.timings") + def taskTimingsOnShutdown: Boolean = getOrFalse("sbt.task.timings.on.shutdown") + def taskTimingsThreshold: Long = long("sbt.task.timings.threshold", 0L) + def taskTimingsOmitPaths: Boolean = getOrFalse("sbt.task.timings.omit.paths") + def taskTimingsUnit: (String, Int) = + 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) + } + + /** Generate build.properties if missing. */ + def genBuildProps: Boolean = + booleanOpt("sbt.genbuildprops") match { + case Some(x) => x + case None => + booleanOpt("sbt.skip.version.write") match { + case Some(skip) => !skip + case None => true + } + } +} diff --git a/main/src/main/scala/sbt/internal/TaskProgress.scala b/main/src/main/scala/sbt/internal/TaskProgress.scala index 0c0c04677..dae694248 100644 --- a/main/src/main/scala/sbt/internal/TaskProgress.scala +++ b/main/src/main/scala/sbt/internal/TaskProgress.scala @@ -14,7 +14,6 @@ import sbt.internal.util._ import sbt.util.Level import scala.annotation.tailrec -import scala.util.control.NonFatal /** * implements task progress display on the shell. @@ -24,9 +23,7 @@ private[sbt] final class TaskProgress(log: ManagedLogger) with ExecuteProgress[Task] { private[this] val lastTaskCount = new AtomicInteger(0) private[this] val currentProgressThread = new AtomicReference[Option[ProgressThread]](None) - private[this] val sleepDuration = - try System.getProperty("sbt.supershell.sleep", "100").toLong - catch { case NonFatal(_) => 100L } + private[this] val sleepDuration = SysProp.supersheelSleep private[this] final class ProgressThread extends Thread("task-progress-report-thread") with AutoCloseable { @@ -105,18 +102,3 @@ private[sbt] final class TaskProgress(log: ManagedLogger) .map(t => taskName(t)) .exists(n => skipReportTasks.exists(m => n.endsWith("/ " + m))) } - -private[sbt] object TaskProgress { - def isEnabled: Boolean = - ConsoleAppender.formatEnabledInEnv && sys.props - .get("sbt.supershell") - .flatMap( - str => - ConsoleAppender.parseLogOption(str) match { - case LogOption.Always => Some(true) - case LogOption.Never => Some(false) - case _ => None - } - ) - .getOrElse(true) -} diff --git a/main/src/main/scala/sbt/internal/TaskTimings.scala b/main/src/main/scala/sbt/internal/TaskTimings.scala index a4b0b3184..08170e813 100644 --- a/main/src/main/scala/sbt/internal/TaskTimings.scala +++ b/main/src/main/scala/sbt/internal/TaskTimings.scala @@ -24,17 +24,9 @@ private[sbt] final class TaskTimings(reportOnShutdown: Boolean) with ExecuteProgress[Task] { import AbstractTaskExecuteProgress.Timer 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) - } + private[this] val threshold = SysProp.taskTimingsThreshold + private[this] val omitPaths = SysProp.taskTimingsOmitPaths + private[this] val (unit, divider) = SysProp.taskTimingsUnit if (reportOnShutdown) { start = System.nanoTime diff --git a/sbt/src/sbt-test/classloader-cache/akka-actor-system/build.sbt b/sbt/src/sbt-test/classloader-cache/akka-actor-system/build.sbt index 9be9015dc..7d5b0fbd5 100644 --- a/sbt/src/sbt-test/classloader-cache/akka-actor-system/build.sbt +++ b/sbt/src/sbt-test/classloader-cache/akka-actor-system/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / turbo := true + val akkaTest = (project in file(".")).settings( name := "akka-test", scalaVersion := "2.12.8", diff --git a/sbt/src/sbt-test/classloader-cache/jni/build.sbt b/sbt/src/sbt-test/classloader-cache/jni/build.sbt index e12fc74f2..63e0131ab 100644 --- a/sbt/src/sbt-test/classloader-cache/jni/build.sbt +++ b/sbt/src/sbt-test/classloader-cache/jni/build.sbt @@ -10,6 +10,8 @@ val wrappedTest = taskKey[Unit]("Test with modified java.library.path") def wrap(task: InputKey[Unit]): Def.Initialize[Task[Unit]] = Def.sequential(appendToLibraryPath, task.toTask(""), dropLibraryPath) +ThisBuild / turbo := true + val root = (project in file(".")).settings( scalaVersion := "2.12.8", javacOptions ++= Seq("-source", "1.8", "-target", "1.8", "-h", diff --git a/sbt/src/sbt-test/classloader-cache/library-mismatch/build.sbt b/sbt/src/sbt-test/classloader-cache/library-mismatch/build.sbt index fefcd86a2..460c9f175 100644 --- a/sbt/src/sbt-test/classloader-cache/library-mismatch/build.sbt +++ b/sbt/src/sbt-test/classloader-cache/library-mismatch/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / turbo := true + val snapshot = (project in file(".")).settings( name := "mismatched-libraries", scalaVersion := "2.12.8", diff --git a/sbt/src/sbt-test/classloader-cache/resources/build.sbt b/sbt/src/sbt-test/classloader-cache/resources/build.sbt index fbc057785..bf5ab6486 100644 --- a/sbt/src/sbt-test/classloader-cache/resources/build.sbt +++ b/sbt/src/sbt-test/classloader-cache/resources/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / turbo := true + resolvers += "Local Maven" at (baseDirectory.value / "libraries" / "foo" / "ivy").toURI.toURL.toString libraryDependencies += "sbt" %% "foo-lib" % "0.1.0" diff --git a/sbt/src/sbt-test/classloader-cache/snapshot/build.sbt b/sbt/src/sbt-test/classloader-cache/snapshot/build.sbt index a43dd3048..28eeb6222 100644 --- a/sbt/src/sbt-test/classloader-cache/snapshot/build.sbt +++ b/sbt/src/sbt-test/classloader-cache/snapshot/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / turbo := true + import java.nio.file.Files import java.nio.file.attribute.FileTime import scala.collection.JavaConverters._ diff --git a/sbt/src/sbt-test/classloader-cache/utest/build.sbt b/sbt/src/sbt-test/classloader-cache/utest/build.sbt index b0d82f379..c64105efb 100644 --- a/sbt/src/sbt-test/classloader-cache/utest/build.sbt +++ b/sbt/src/sbt-test/classloader-cache/utest/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / turbo := true + val utestTest = (project in file(".")).settings( name := "utest-test", scalaVersion := "2.12.8",