From 6c0f47ef48edf0168aa4a396be6cdb455e1fb9ec Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Wed, 8 May 2013 12:56:59 -0400 Subject: [PATCH] Default settings, which give internal sbt settings something like Plugin.globalSettings. --- main/src/main/scala/sbt/Defaults.scala | 44 +++++++++++-------- .../src/main/scala/sbt/Settings.scala | 30 +++++++++++-- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 0f694a30b..9259e5485 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -49,19 +49,20 @@ object Defaults extends BuildCommon val m = (for(a <- cp; an <- a.metadata get Keys.analysis) yield (a.data, an) ).toMap m.get _ } + private[this] def globalDefaults(ss: Seq[Setting[_]]): Seq[Setting[_]] = Def.defaultSettings(inScope(GlobalScope)(ss)) def buildCore: Seq[Setting[_]] = thisBuildCore ++ globalCore def thisBuildCore: Seq[Setting[_]] = inScope(GlobalScope.copy(project = Select(ThisBuild)))(Seq( managedDirectory := baseDirectory.value / "lib_managed" )) - def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq( + lazy val globalCore: Seq[Setting[_]] = globalDefaults(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq( compilerCache := state.value get Keys.stateCompilerCache getOrElse compiler.CompilerCache.fresh, crossVersion :== CrossVersion.Disabled, scalaOrganization :== ScalaArtifacts.Organization, - buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies, + buildDependencies <<= Classpaths.constructBuildDependencies, taskTemporaryDirectory := { val dir = IO.createTemporaryDirectory; dir.deleteOnExit(); dir }, onComplete := { val dir = taskTemporaryDirectory.value; () => IO.delete(dir); IO.createDirectory(dir) }, - concurrentRestrictions <<= concurrentRestrictions or defaultRestrictions, + concurrentRestrictions <<= defaultRestrictions, parallelExecution :== true, sbtVersion := appConfiguration.value.provider.id.version, sbtBinaryVersion := binarySbtVersion(sbtVersion.value), @@ -76,11 +77,11 @@ object Defaults extends BuildCommon apiMappings := Map.empty, autoScalaLibrary :== true, managedScalaInstance :== true, - onLoad <<= onLoad ?? idFun[State], - onUnload <<= (onUnload ?? idFun[State]), + onLoad := idFun[State], + onUnload := idFun[State], onUnload := { s => try onUnload.value(s) finally IO.delete(taskTemporaryDirectory.value) }, - watchingMessage <<= watchingMessage ?? Watched.defaultWatchingMessage, - triggeredMessage <<= triggeredMessage ?? Watched.defaultTriggeredMessage, + watchingMessage := Watched.defaultWatchingMessage, + triggeredMessage := Watched.defaultTriggeredMessage, definesClass :== FileValueCache(Locate.definesClass _ ).get, trapExit :== false, trapExit in run :== true, @@ -193,21 +194,24 @@ object Defaults extends BuildCommon } ) - def compileBase = inTask(console)(compilersSetting :: Nil) ++ Seq( - classpathOptions in GlobalScope :== ClasspathOptions.boot, - classpathOptions in GlobalScope in console :== ClasspathOptions.repl, - compileOrder in GlobalScope :== CompileOrder.Mixed, + def compileBase = inTask(console)(compilersSetting :: Nil) ++ compileBaseGlobal ++ Seq( compilersSetting, - javacOptions in GlobalScope :== Nil, - scalacOptions in GlobalScope :== Nil, incOptions in GlobalScope := sbt.inc.IncOptions.defaultTransactional(crossTarget.value.getParentFile / "classes.bak"), scalaInstance <<= scalaInstanceTask, - scalaVersion in GlobalScope := appConfiguration.value.provider.scalaProvider.version, - scalaBinaryVersion in GlobalScope := binaryScalaVersion(scalaVersion.value), crossVersion := (if(crossPaths.value) CrossVersion.binary else CrossVersion.Disabled), - crossScalaVersions in GlobalScope := Seq(scalaVersion.value), crossTarget := makeCrossTarget(target.value, scalaBinaryVersion.value, sbtBinaryVersion.value, sbtPlugin.value, crossPaths.value) ) + // must be a val: duplication detected by object identity + private[this] lazy val compileBaseGlobal: Seq[Setting[_]] = globalDefaults(Seq( + classpathOptions :== ClasspathOptions.boot, + classpathOptions in console :== ClasspathOptions.repl, + compileOrder :== CompileOrder.Mixed, + javacOptions :== Nil, + scalacOptions :== Nil, + scalaVersion := appConfiguration.value.provider.scalaProvider.version, + scalaBinaryVersion := binaryScalaVersion(scalaVersion.value), + crossScalaVersions := Seq(scalaVersion.value) + )) def makeCrossTarget(t: File, sv: String, sbtv: String, plugin: Boolean, cross: Boolean): File = { val scalaBase = if(cross) t / ("scala-" + sv) else t @@ -215,9 +219,7 @@ object Defaults extends BuildCommon } def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value)(appConfiguration.value, streams.value.log) - lazy val configTasks = docTaskSettings(doc) ++ compileTaskSettings ++ compileInputsSettings ++ Seq( - initialCommands in GlobalScope :== "", - cleanupCommands in GlobalScope :== "", + lazy val configTasks = docTaskSettings(doc) ++ compileTaskSettings ++ compileInputsSettings ++ configGlobal ++ Seq( compile <<= compileTask tag(Tags.Compile, Tags.CPU), printWarnings <<= printWarningsTask, compileIncSetup <<= compileIncSetupTask, @@ -233,6 +235,10 @@ object Defaults extends BuildCommon runMain <<= runMainTask(fullClasspath, runner in run), copyResources <<= copyResourcesTask ) + private[this] lazy val configGlobal = globalDefaults(Seq( + initialCommands :== "", + cleanupCommands :== "" + )) lazy val projectTasks: Seq[Setting[_]] = Seq( cleanFiles := Seq(managedDirectory.value, target.value), diff --git a/util/collection/src/main/scala/sbt/Settings.scala b/util/collection/src/main/scala/sbt/Settings.scala index 79cdaf751..6a16e1616 100644 --- a/util/collection/src/main/scala/sbt/Settings.scala +++ b/util/collection/src/main/scala/sbt/Settings.scala @@ -79,12 +79,21 @@ trait Init[Scope] * Only the static dependencies are tracked, however. */ final def derive[T](s: Setting[T], allowDynamic: Boolean = false, filter: Scope => Boolean = const(true)): Setting[T] = { deriveAllowed(s, allowDynamic) foreach error - new DerivedSetting[T](s.key, s.init, s.pos, filter) + new DerivedSetting[T](s.key, s.init, s.pos, filter, nextDefaultID()) } def deriveAllowed[T](s: Setting[T], allowDynamic: Boolean): Option[String] = s.init match { case _: Bind[_,_] if !allowDynamic => Some("Cannot derive from dynamic dependencies.") case _ => None } + // id is used for equality + private[sbt] final def defaultSetting[T](s: Setting[T]): Setting[T] = s match { + case _: DefaultSetting[_] | _: DerivedSetting[_] => s + case _ => new DefaultSetting[T](s.key, s.init, s.pos, nextDefaultID()) + } + private[sbt] def defaultSettings(ss: Seq[Setting[_]]): Seq[Setting[_]] = ss.map(s => defaultSetting(s)) + private[this] final val nextID = new java.util.concurrent.atomic.AtomicLong + private[this] final def nextDefaultID(): Long = nextID.incrementAndGet() + def empty(implicit delegates: Scope => Seq[Scope]): Settings[Scope] = new Settings0(Map.empty, delegates) def asTransform(s: Settings[Scope]): ScopedKey ~> Id = new (ScopedKey ~> Id) { @@ -123,11 +132,17 @@ trait Init[Scope] process(defs.toList) out.toList ++ defs } + private[this] def applyDefaults(ss: Seq[Setting[_]]): Seq[Setting[_]] = + { + val (defaults, others) = Util.separate[Setting[_], DefaultSetting[_], Setting[_]](ss) { case u: DefaultSetting[_] => Left(u); case s => Right(s) } + defaults.distinct ++ others + } def compiled(init: Seq[Setting[_]], actual: Boolean = true)(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopeLocal, display: Show[ScopedKey[_]]): CompiledMap = { + val initDefaults = applyDefaults(init) // inject derived settings into scopes where their dependencies are directly defined - val derived = derive(init) + val derived = derive(initDefaults) // prepend per-scope settings val withLocal = addLocal(derived)(scopeLocal) // group by Scope/Key, dropping dead initializations @@ -323,10 +338,17 @@ trait Init[Scope] protected[sbt] def isDerived: Boolean = false private[sbt] def setScope(s: Scope): Setting[T] = make(key.copy(scope = s), init.mapReferenced(mapScope(const(s))), pos) } - private[Init] final class DerivedSetting[T](sk: ScopedKey[T], i: Initialize[T], p: SourcePosition, val filter: Scope => Boolean) extends Setting[T](sk, i, p) { - override def make[T](key: ScopedKey[T], init: Initialize[T], pos: SourcePosition): Setting[T] = new DerivedSetting[T](key, init, pos, filter) + private[Init] final class DerivedSetting[T](sk: ScopedKey[T], i: Initialize[T], p: SourcePosition, val filter: Scope => Boolean, id: Long) extends DefaultSetting[T](sk, i, p, id) { + override def make[T](key: ScopedKey[T], init: Initialize[T], pos: SourcePosition): Setting[T] = new DerivedSetting[T](key, init, pos, filter, id) protected[sbt] override def isDerived: Boolean = true } + // Only keep the first occurence of this setting and move it to the front so that it has lower precedence than non-defaults. + // This is intended for internal sbt use only, where alternatives like Plugin.globalSettings are not available. + private[Init] sealed class DefaultSetting[T](sk: ScopedKey[T], i: Initialize[T], p: SourcePosition, val id: Long) extends Setting[T](sk, i, p) { + override def make[T](key: ScopedKey[T], init: Initialize[T], pos: SourcePosition): Setting[T] = new DefaultSetting[T](key, init, pos, id) + override final def hashCode = id.hashCode + override final def equals(o: Any): Boolean = o match { case d: DefaultSetting[_] => d.id == id; case _ => false } + } private[this] def handleUndefined[T](vr: ValidatedInit[T]): Initialize[T] = vr match {