reorganization of main/

* split several source files
* move base settings sources (Scope, Structure, ...) into main/settings/
* breaks cycles.  In particular, setting system moved from Project to Def
This commit is contained in:
Mark Harrah 2012-07-31 11:52:10 -04:00
parent 87e406fcbd
commit eecaeafbdf
42 changed files with 960 additions and 867 deletions

View File

@ -3,9 +3,9 @@
*/ */
package sbt package sbt
import Project.{ScopedKey, showContextKey} import Def.{showRelativeKey, ScopedKey}
import Project.showContextKey
import Keys.{sessionSettings, thisProject} import Keys.{sessionSettings, thisProject}
import Load.BuildStructure
import complete.{DefaultParsers, Parser} import complete.{DefaultParsers, Parser}
import Aggregation.{KeyValue,Values} import Aggregation.{KeyValue,Values}
import DefaultParsers._ import DefaultParsers._
@ -31,7 +31,7 @@ object Act
def scopedKeySelected(index: KeyIndex, current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String], def scopedKeySelected(index: KeyIndex, current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String],
keyMap: Map[String, AttributeKey[_]], data: Settings[Scope]): Parser[ParsedKey] = keyMap: Map[String, AttributeKey[_]], data: Settings[Scope]): Parser[ParsedKey] =
scopedKeyFull(index, current, defaultConfigs, keyMap) flatMap { choices => scopedKeyFull(index, current, defaultConfigs, keyMap) flatMap { choices =>
select(choices, data)( Project.showRelativeKey(current, index.buildURIs.size > 1) ) select(choices, data)( showRelativeKey(current, index.buildURIs.size > 1) )
} }
def scopedKeyFull(index: KeyIndex, current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String], keyMap: Map[String, AttributeKey[_]]): Parser[Seq[Parser[ParsedKey]]] = def scopedKeyFull(index: KeyIndex, current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String], keyMap: Map[String, AttributeKey[_]]): Parser[Seq[Parser[ParsedKey]]] =

View File

@ -3,8 +3,7 @@
*/ */
package sbt package sbt
import Project.ScopedKey import Def.ScopedKey
import Load.{BuildStructure,LoadedBuildUnit}
import Keys.{aggregate, showSuccess, showTiming, timingFormat} import Keys.{aggregate, showSuccess, showTiming, timingFormat}
import sbt.complete.Parser import sbt.complete.Parser
import java.net.URI import java.net.URI
@ -30,7 +29,7 @@ final object Aggregation
Command.applyEffect(seqParser(ps)) { ts => Command.applyEffect(seqParser(ps)) { ts =>
runTasks(s, structure, ts, Dummies(KNil, HNil), show) runTasks(s, structure, ts, Dummies(KNil, HNil), show)
} }
def runTasksWithResult[HL <: HList, T](s: State, structure: Load.BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean)(implicit display: Show[ScopedKey[_]]): (State, Result[Seq[KeyValue[T]]]) = def runTasksWithResult[HL <: HList, T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean)(implicit display: Show[ScopedKey[_]]): (State, Result[Seq[KeyValue[T]]]) =
{ {
import EvaluateTask._ import EvaluateTask._
import std.TaskExtra._ import std.TaskExtra._
@ -55,7 +54,7 @@ final object Aggregation
(newS, result) (newS, result)
} }
def runTasks[HL <: HList, T](s: State, structure: Load.BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean)(implicit display: Show[ScopedKey[_]]): State = { def runTasks[HL <: HList, T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean)(implicit display: Show[ScopedKey[_]]): State = {
runTasksWithResult(s, structure, ts, extra, show)._1 runTasksWithResult(s, structure, ts, extra, show)._1
} }
@ -157,16 +156,7 @@ final object Aggregation
def aggregationEnabled(key: ScopedKey[_], data: Settings[Scope]): Boolean = def aggregationEnabled(key: ScopedKey[_], data: Settings[Scope]): Boolean =
Keys.aggregate in Scope.fillTaskAxis(key.scope, key.key) get data getOrElse true Keys.aggregate in Scope.fillTaskAxis(key.scope, key.key) get data getOrElse true
@deprecated("Use BuildUtil.aggregationRelation", "0.13.0")
def relation(units: Map[URI, LoadedBuildUnit]): Relation[ProjectRef, ProjectRef] = def relation(units: Map[URI, LoadedBuildUnit]): Relation[ProjectRef, ProjectRef] =
{ BuildUtil.aggregationRelation(units)
val depPairs =
for {
(uri, unit) <- units.toIterable
project <- unit.defined.values
ref = ProjectRef(uri, project.id)
agg <- project.aggregate
} yield
(ref, agg)
Relation.empty ++ depPairs
}
} }

View File

@ -4,16 +4,8 @@
package sbt package sbt
import java.io.File import java.io.File
import java.net.URI
import BuildLoader.ResolveInfo
import compiler.{Eval, EvalImports}
import complete.DefaultParsers.validID
import Compiler.Compilers
import Keys.{globalBaseDirectory, globalPluginsDirectory, globalSettingsDirectory, stagingDirectory, Streams}
import Keys.{name, organization, thisProject} import Keys.{name, organization, thisProject}
import Project.{ScopedKey, Setting} import Def.{ScopedKey, Setting}
import Scope.GlobalScope
import scala.annotation.tailrec
// name is more like BuildDefinition, but that is too long // name is more like BuildDefinition, but that is too long
trait Build trait Build
@ -26,16 +18,16 @@ trait Build
trait Plugin trait Plugin
{ {
@deprecated("Override projectSettings or buildSettings instead.", "0.12.0") @deprecated("Override projectSettings or buildSettings instead.", "0.12.0")
def settings: Seq[Project.Setting[_]] = Nil def settings: Seq[Setting[_]] = Nil
/** Settings to be appended to all projects in a build. */ /** Settings to be appended to all projects in a build. */
def projectSettings: Seq[Project.Setting[_]] = Nil def projectSettings: Seq[Setting[_]] = Nil
/** Settings to be appended at the build scope. */ /** Settings to be appended at the build scope. */
def buildSettings: Seq[Project.Setting[_]] = Nil def buildSettings: Seq[Setting[_]] = Nil
/** Settings to be appended at the global scope. */ /** Settings to be appended at the global scope. */
def globalSettings: Seq[Project.Setting[_]] = Nil def globalSettings: Seq[Setting[_]] = Nil
} }
object Build object Build
@ -47,283 +39,7 @@ object Build
organization <<= (thisProject, organization, name) { (p, o, n) => if(p.id == n) "default" else o } organization <<= (thisProject, organization, name) { (p, o, n) => if(p.id == n) "default" else o }
) )
def data[T](in: Seq[Attributed[T]]): Seq[T] = in.map(_.data) @deprecated("Use Attributed.data", "0.13.0")
def data[T](in: Seq[Attributed[T]]): Seq[T] = Attributed.data(in)
def analyzed(in: Seq[Attributed[_]]): Seq[inc.Analysis] = in.flatMap{ _.metadata.get(Keys.analysis) } def analyzed(in: Seq[Attributed[_]]): Seq[inc.Analysis] = in.flatMap{ _.metadata.get(Keys.analysis) }
} }
object RetrieveUnit
{
def apply(info: ResolveInfo): Option[() => File] =
{
info.uri match {
case Scheme("svn") | Scheme("svn+ssh") => Resolvers.subversion(info)
case Scheme("hg") => Resolvers.mercurial(info)
case Scheme("git") => Resolvers.git(info)
case Path(path) if path.endsWith(".git") => Resolvers.git(info)
case Scheme("http") | Scheme("https") | Scheme("ftp") => Resolvers.remote(info)
case Scheme("file") => Resolvers.local(info)
case _ => None
}
}
object Scheme
{
def unapply(uri: URI) = Option(uri.getScheme)
}
object Path
{
import RichURI.fromURI
def unapply(uri: URI) = Option(uri.withoutMarkerScheme.getPath)
}
}
object EvaluateConfigurations
{
private[this] final class ParsedFile(val imports: Seq[(String,Int)], val definitions: Seq[(String,LineRange)], val settings: Seq[(String,LineRange)])
private[this] final class Definitions(val loader: ClassLoader => ClassLoader, val moduleNames: Seq[String])
private[this] val DefinitionKeywords = Seq("lazy val ", "def ", "val ")
def apply(eval: Eval, srcs: Seq[File], imports: Seq[String]): ClassLoader => Seq[Setting[_]] =
flatten(srcs.sortBy(_.getName) map { src => evaluateConfiguration(eval, src, imports) })
def evaluateConfiguration(eval: Eval, src: File, imports: Seq[String]): ClassLoader => Seq[Setting[_]] =
evaluateConfiguration(eval, src.getPath, IO.readLines(src), imports, 0)
private[this] def parseConfiguration(lines: Seq[String], builtinImports: Seq[String], offset: Int): ParsedFile =
{
val (importStatements, settingsAndDefinitions) = splitExpressions(lines)
val allImports = builtinImports.map(s => (s, -1)) ++ addOffset(offset, importStatements)
val (definitions, settings) = splitSettingsDefinitions(addOffsetToRange(offset, settingsAndDefinitions))
new ParsedFile(allImports, definitions, settings)
}
def evaluateConfiguration(eval: Eval, name: String, lines: Seq[String], imports: Seq[String], offset: Int): ClassLoader => Seq[Setting[_]] =
{
val parsed = parseConfiguration(lines, imports, offset)
val importDefs = if(parsed.definitions.isEmpty) Nil else {
val definitions = evaluateDefinitions(eval, name, parsed.imports, parsed.definitions)
Load.importAllRoot(definitions.moduleNames).map(s => (s, -1))
}
val allImports = importDefs ++ parsed.imports
val settings = parsed.settings map { case (settingExpression,range) =>
evaluateSetting(eval, name, allImports, settingExpression, range)
}
eval.unlinkDeferred()
flatten(settings)
}
def flatten(mksettings: Seq[ClassLoader => Seq[Setting[_]]]): ClassLoader => Seq[Setting[_]] =
loader => mksettings.flatMap(_ apply loader)
def addOffset(offset: Int, lines: Seq[(String,Int)]): Seq[(String,Int)] =
lines.map { case (s, i) => (s, i + offset) }
def addOffsetToRange(offset: Int, ranges: Seq[(String,LineRange)]): Seq[(String,LineRange)] =
ranges.map { case (s, r) => (s, r shift offset) }
def evaluateSetting(eval: Eval, name: String, imports: Seq[(String,Int)], expression: String, range: LineRange): ClassLoader => Seq[Setting[_]] =
{
val result = try {
eval.eval(expression, imports = new EvalImports(imports, name), srcName = name, tpeName = Some("sbt.Project.SettingsDefinition"), line = range.start)
} catch {
case e: sbt.compiler.EvalException => throw new MessageOnlyException(e.getMessage)
}
loader => {
val pos = RangePosition(name, range shift 1)
result.getValue(loader).asInstanceOf[Project.SettingsDefinition].settings map (_ withPos pos)
}
}
private[this] def isSpace = (c: Char) => Character isWhitespace c
private[this] def fstS(f: String => Boolean): ((String,Int)) => Boolean = { case (s,i) => f(s) }
private[this] def firstNonSpaceIs(lit: String) = (_: String).view.dropWhile(isSpace).startsWith(lit)
private[this] def or[A](a: A => Boolean, b: A => Boolean): A => Boolean = in => a(in) || b(in)
def splitExpressions(lines: Seq[String]): (Seq[(String,Int)], Seq[(String,LineRange)]) =
{
val blank = (_: String).forall(isSpace)
val isImport = firstNonSpaceIs("import ")
val comment = firstNonSpaceIs("//")
val blankOrComment = or(blank, comment)
val importOrBlank = fstS(or(blankOrComment, isImport))
val (imports, settings) = lines.zipWithIndex span importOrBlank
(imports filterNot fstS( blankOrComment ), groupedLines(settings, blank, blankOrComment))
}
def groupedLines(lines: Seq[(String,Int)], delimiter: String => Boolean, skipInitial: String => Boolean): Seq[(String,LineRange)] =
{
val fdelim = fstS(delimiter)
@tailrec def group0(lines: Seq[(String,Int)], accum: Seq[(String,LineRange)]): Seq[(String,LineRange)] =
if(lines.isEmpty) accum.reverse
else
{
val start = lines dropWhile fstS( skipInitial )
val (next, tail) = start.span { case (s,_) => !delimiter(s) }
val grouped = if(next.isEmpty) accum else (next.map(_._1).mkString("\n"), LineRange(next.head._2, next.last._2 + 1)) +: accum
group0(tail, grouped)
}
group0(lines, Nil)
}
private[this] def splitSettingsDefinitions(lines: Seq[(String,LineRange)]): (Seq[(String,LineRange)], Seq[(String,LineRange)]) =
lines partition { case (line, range) => isDefinition(line) }
private[this] def isDefinition(line: String): Boolean =
{
val trimmed = line.trim
DefinitionKeywords.exists(trimmed startsWith _)
}
private[this] def evaluateDefinitions(eval: Eval, name: String, imports: Seq[(String,Int)], definitions: Seq[(String,LineRange)]): Definitions =
{
val convertedRanges = definitions.map { case (s, r) => (s, r.start to r.end) }
val res = eval.evalDefinitions(convertedRanges, new EvalImports(imports, name), name)
new Definitions(loader => res.getValue(loader).getClass.getClassLoader, res.enclosingModule :: Nil)
}
}
object Index
{
def taskToKeyMap(data: Settings[Scope]): Map[Task[_], ScopedKey[Task[_]]] =
{
// AttributeEntry + the checked type test 'value: Task[_]' ensures that the cast is correct.
// (scalac couldn't determine that 'key' is of type AttributeKey[Task[_]] on its own and a type match still required the cast)
val pairs = for( scope <- data.scopes; AttributeEntry(key, value: Task[_]) <- data.data(scope).entries ) yield
(value, ScopedKey(scope, key.asInstanceOf[AttributeKey[Task[_]]])) // unclear why this cast is needed even with a type test in the above filter
pairs.toMap[Task[_], ScopedKey[Task[_]]]
}
def allKeys(settings: Seq[Setting[_]]): Set[ScopedKey[_]] =
settings.flatMap(s => if(s.key.key.isLocal) Nil else s.key +: s.dependencies).filter(!_.key.isLocal).toSet
def attributeKeys(settings: Settings[Scope]): Set[AttributeKey[_]] =
settings.data.values.flatMap(_.keys).toSet[AttributeKey[_]]
def stringToKeyMap(settings: Set[AttributeKey[_]]): Map[String, AttributeKey[_]] =
{
val multiMap = settings.groupBy(_.label)
val duplicates = multiMap collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) } collect { case (k, xs) if xs.size > 1 => (k, xs) }
if(duplicates.isEmpty)
multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap;
else
error(duplicates map { case (k, tps) => "'" + k + "' (" + tps.mkString(", ") + ")" } mkString("AttributeKey ID collisions detected for: ", ", ", ""))
}
private[this] type TriggerMap = collection.mutable.HashMap[Task[_], Seq[Task[_]]]
def triggers(ss: Settings[Scope]): Triggers[Task] =
{
val runBefore = new TriggerMap
val triggeredBy = new TriggerMap
for( (_, amap) <- ss.data; AttributeEntry(_, value: Task[_]) <- amap.entries)
{
val as = value.info.attributes
update(runBefore, value, as get Keys.runBefore)
update(triggeredBy, value, as get Keys.triggeredBy)
}
val onComplete = Keys.onComplete in GlobalScope get ss getOrElse { () => () }
new Triggers[Task](runBefore, triggeredBy, map => { onComplete(); map } )
}
private[this] def update(map: TriggerMap, base: Task[_], tasksOpt: Option[Seq[Task[_]]]): Unit =
for( tasks <- tasksOpt; task <- tasks )
map(task) = base +: map.getOrElse(task, Nil)
}
object BuildStreams
{
import Load.{BuildStructure, LoadedBuildUnit}
import Project.displayFull
import std.{TaskExtra,Transform}
import Path._
import BuildPaths.outputDirectory
final val GlobalPath = "$global"
final val BuildUnitPath = "$build"
final val StreamsDirectory = "streams"
def mkStreams(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope]): State => Streams = s =>
std.Streams( path(units, root, data), displayFull, LogManager.construct(data, s) )
def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope])(scoped: ScopedKey[_]): File =
resolvePath( projectPath(units, root, scoped, data), nonProjectPath(scoped) )
def resolvePath(base: File, components: Seq[String]): File =
(base /: components)( (b,p) => new File(b,p) )
def pathComponent[T](axis: ScopeAxis[T], scoped: ScopedKey[_], label: String)(show: T => String): String =
axis match
{
case Global => GlobalPath
case This => error("Unresolved This reference for " + label + " in " + Project.displayFull(scoped))
case Select(t) => show(t)
}
def nonProjectPath[T](scoped: ScopedKey[T]): Seq[String] =
{
val scope = scoped.scope
pathComponent(scope.config, scoped, "config")(_.name) ::
pathComponent(scope.task, scoped, "task")(_.label) ::
pathComponent(scope.extra, scoped, "extra")(showAMap) ::
Nil
}
def showAMap(a: AttributeMap): String =
a.entries.toSeq.sortBy(_.key.label).map { case AttributeEntry(key, value) => key.label + "=" + value.toString } mkString(" ")
def projectPath(units: Map[URI, LoadedBuildUnit], root: URI, scoped: ScopedKey[_], data: Settings[Scope]): File =
scoped.scope.project match
{
case Global => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath
case Select(br @ BuildRef(uri)) => refTarget(br, units(uri).localBase, data) / BuildUnitPath
case Select(pr @ ProjectRef(uri, id)) => refTarget(pr, units(uri).defined(id).base, data)
case Select(pr) => error("Unresolved project reference (" + pr + ") in " + displayFull(scoped))
case This => error("Unresolved project reference (This) in " + displayFull(scoped))
}
def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File =
refTarget(GlobalScope.copy(project = Select(ref)), fallbackBase, data)
def refTarget(scope: Scope, fallbackBase: File, data: Settings[Scope]): File =
(Keys.target in scope get data getOrElse outputDirectory(fallbackBase).asFile ) / StreamsDirectory
}
object BuildPaths
{
import Path._
def getGlobalBase(state: State): File =
getFileSetting(globalBaseDirectory, GlobalBaseProperty, defaultGlobalBase)(state)
def getStagingDirectory(state: State, globalBase: File): File =
getFileSetting(stagingDirectory, StagingProperty, defaultStaging(globalBase))(state)
def getGlobalPluginsDirectory(state: State, globalBase: File): File =
getFileSetting(globalPluginsDirectory, GlobalPluginsProperty, defaultGlobalPlugins(globalBase))(state)
def getGlobalSettingsDirectory(state: State, globalBase: File): File =
getFileSetting(globalSettingsDirectory, GlobalSettingsProperty, globalBase)(state)
def getFileSetting(stateKey: AttributeKey[File], property: String, default: File)(state: State): File =
state get stateKey orElse getFileProperty(property) getOrElse default
def getFileProperty(name: String): Option[File] = Option(System.getProperty(name)) flatMap { path =>
if(path.isEmpty) None else Some(new File(path))
}
def defaultGlobalBase = Path.userHome / ConfigDirectoryName
private[this] def defaultStaging(globalBase: File) = globalBase / "staging"
private[this] def defaultGlobalPlugins(globalBase: File) = globalBase / PluginsDirectoryName
def definitionSources(base: File): Seq[File] = (base * "*.scala").get
def configurationSources(base: File): Seq[File] = (base * (GlobFilter("*.sbt") - ".sbt")).get
def pluginDirectory(definitionBase: File) = definitionBase / PluginsDirectoryName
def evalOutputDirectory(base: File) = outputDirectory(base) / "config-classes"
def outputDirectory(base: File) = base / DefaultTargetName
def buildOutputDirectory(base: File, compilers: Compilers) = crossPath(outputDirectory(base), compilers.scalac.scalaInstance)
def projectStandard(base: File) = base / "project"
def projectHidden(base: File) = base / ConfigDirectoryName
def selectProjectDir(base: File, log: Logger) =
{
val a = projectHidden(base)
val b = projectStandard(base)
if(a.exists)
{
log.warn("Alternative project directory " + ConfigDirectoryName + " (" + a + ") has been deprecated since sbt 0.12.0.\n Please use the standard location: " + b)
a
}
else b
}
final val PluginsDirectoryName = "plugins"
final val DefaultTargetName = "target"
final val ConfigDirectoryName = ".sbt"
final val GlobalBaseProperty = "sbt.global.base"
final val StagingProperty = "sbt.global.staging"
final val GlobalPluginsProperty = "sbt.global.plugins"
final val GlobalSettingsProperty = "sbt.global.settings"
def crossPath(base: File, instance: xsbti.compile.ScalaInstance): File = base / ("scala_" + instance.version)
}

View File

@ -5,7 +5,6 @@ package sbt
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import Load.{BuildUnit, LoadBuildConfiguration, PartBuild}
import BuildLoader._ import BuildLoader._
import Alternatives._ import Alternatives._
import Types.{const,idFun} import Types.{const,idFun}

73
main/BuildPaths.scala Normal file
View File

@ -0,0 +1,73 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import java.io.File
import java.net.URI
import KeyRanks.DSetting
object BuildPaths
{
val globalBaseDirectory = AttributeKey[File]("global-base-directory", "The base directory for global sbt configuration and staging.", DSetting)
val globalPluginsDirectory = AttributeKey[File]("global-plugins-directory", "The base directory for global sbt plugins.", DSetting)
val globalSettingsDirectory = AttributeKey[File]("global-settings-directory", "The base directory for global sbt settings.", DSetting)
val stagingDirectory = AttributeKey[File]("staging-directory", "The directory for staging remote projects.", DSetting)
import Path._
def getGlobalBase(state: State): File =
getFileSetting(globalBaseDirectory, GlobalBaseProperty, defaultGlobalBase)(state)
def getStagingDirectory(state: State, globalBase: File): File =
getFileSetting(stagingDirectory, StagingProperty, defaultStaging(globalBase))(state)
def getGlobalPluginsDirectory(state: State, globalBase: File): File =
getFileSetting(globalPluginsDirectory, GlobalPluginsProperty, defaultGlobalPlugins(globalBase))(state)
def getGlobalSettingsDirectory(state: State, globalBase: File): File =
getFileSetting(globalSettingsDirectory, GlobalSettingsProperty, globalBase)(state)
def getFileSetting(stateKey: AttributeKey[File], property: String, default: File)(state: State): File =
state get stateKey orElse getFileProperty(property) getOrElse default
def getFileProperty(name: String): Option[File] = Option(System.getProperty(name)) flatMap { path =>
if(path.isEmpty) None else Some(new File(path))
}
def defaultGlobalBase = Path.userHome / ConfigDirectoryName
private[this] def defaultStaging(globalBase: File) = globalBase / "staging"
private[this] def defaultGlobalPlugins(globalBase: File) = globalBase / PluginsDirectoryName
def definitionSources(base: File): Seq[File] = (base * "*.scala").get
def configurationSources(base: File): Seq[File] = (base * (GlobFilter("*.sbt") - ".sbt")).get
def pluginDirectory(definitionBase: File) = definitionBase / PluginsDirectoryName
def evalOutputDirectory(base: File) = outputDirectory(base) / "config-classes"
def outputDirectory(base: File) = base / DefaultTargetName
def buildOutputDirectory(base: File, scalaInstance: xsbti.compile.ScalaInstance) = crossPath(outputDirectory(base), scalaInstance)
def projectStandard(base: File) = base / "project"
def projectHidden(base: File) = base / ConfigDirectoryName
def selectProjectDir(base: File, log: Logger) =
{
val a = projectHidden(base)
val b = projectStandard(base)
if(a.exists)
{
log.warn("Alternative project directory " + ConfigDirectoryName + " (" + a + ") has been deprecated since sbt 0.12.0.\n Please use the standard location: " + b)
a
}
else b
}
final val PluginsDirectoryName = "plugins"
final val DefaultTargetName = "target"
final val ConfigDirectoryName = ".sbt"
final val GlobalBaseProperty = "sbt.global.base"
final val StagingProperty = "sbt.global.staging"
final val GlobalPluginsProperty = "sbt.global.plugins"
final val GlobalSettingsProperty = "sbt.global.settings"
def crossPath(base: File, instance: xsbti.compile.ScalaInstance): File = base / ("scala_" + instance.version)
}

119
main/BuildStructure.scala Normal file
View File

@ -0,0 +1,119 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import java.io.File
import java.net.URI
import compiler.Eval
import inc.Locate
import Def.{displayFull, ScopedKey, ScopeLocal, Setting}
import Attributed.data
import BuildPaths.outputDirectory
import Scope.GlobalScope
import BuildStreams.Streams
import Path._
final class BuildStructure(val units: Map[URI, LoadedBuildUnit], val root: URI, val settings: Seq[Setting[_]], val data: Settings[Scope], val index: StructureIndex, val streams: State => Streams, val delegates: Scope => Seq[Scope], val scopeLocal: ScopeLocal)
{
val rootProject: URI => String = Load getRootProject units
def allProjects: Seq[ResolvedProject] = units.values.flatMap(_.defined.values).toSeq
def allProjects(build: URI): Seq[ResolvedProject] = units.get(build).toList.flatMap(_.defined.values)
def allProjectRefs: Seq[ProjectRef] = units.toSeq flatMap { case (build, unit) => refs(build, unit.defined.values.toSeq) }
def allProjectRefs(build: URI): Seq[ProjectRef] = refs(build, allProjects(build))
val extra: BuildUtil[ResolvedProject] = BuildUtil(root, units, index.keyIndex, data)
private[this] def refs(build: URI, projects: Seq[ResolvedProject]): Seq[ProjectRef] = projects.map { p => ProjectRef(build, p.id) }
}
// information that is not original, but can be reconstructed from the rest of BuildStructure
final class StructureIndex(
val keyMap: Map[String, AttributeKey[_]],
val taskToKey: Map[Task[_], ScopedKey[Task[_]]],
val triggers: Triggers[Task],
val keyIndex: KeyIndex,
val aggregateKeyIndex: KeyIndex
)
final class LoadedBuildUnit(val unit: BuildUnit, val defined: Map[String, ResolvedProject], val rootProjects: Seq[String], val buildSettings: Seq[Setting[_]]) extends BuildUnitBase
{
assert(!rootProjects.isEmpty, "No root projects defined for build unit " + unit)
val root = rootProjects.head
def localBase = unit.localBase
def classpath: Seq[File] = unit.definitions.target ++ unit.plugins.classpath
def loader = unit.definitions.loader
def imports = BuildUtil.getImports(unit)
override def toString = unit.toString
}
final class LoadedDefinitions(val base: File, val target: Seq[File], val loader: ClassLoader, val builds: Seq[Build], val buildNames: Seq[String])
final class LoadedPlugins(val base: File, val pluginData: PluginData, val loader: ClassLoader, val plugins: Seq[Plugin], val pluginNames: Seq[String])
{
def fullClasspath: Seq[Attributed[File]] = pluginData.classpath
def classpath = data(fullClasspath)
}
final class BuildUnit(val uri: URI, val localBase: File, val definitions: LoadedDefinitions, val plugins: LoadedPlugins)
{
override def toString = if(uri.getScheme == "file") localBase.toString else (uri + " (locally: " + localBase +")")
}
final class LoadedBuild(val root: URI, val units: Map[URI, LoadedBuildUnit])
{
BuildUtil.checkCycles(units)
def allProjectRefs: Seq[(ProjectRef, ResolvedProject)] = for( (uri, unit) <- units.toSeq; (id, proj) <- unit.defined ) yield ProjectRef(uri, id) -> proj
def extra(data: Settings[Scope])(keyIndex: KeyIndex): BuildUtil[ResolvedProject] = BuildUtil(root, units, keyIndex, data)
}
final class PartBuild(val root: URI, val units: Map[URI, PartBuildUnit])
sealed trait BuildUnitBase { def rootProjects: Seq[String]; def buildSettings: Seq[Setting[_]] }
final class PartBuildUnit(val unit: BuildUnit, val defined: Map[String, Project], val rootProjects: Seq[String], val buildSettings: Seq[Setting[_]]) extends BuildUnitBase
{
def resolve(f: Project => ResolvedProject): LoadedBuildUnit = new LoadedBuildUnit(unit, defined mapValues f toMap, rootProjects, buildSettings)
def resolveRefs(f: ProjectReference => ProjectRef): LoadedBuildUnit = resolve(_ resolve f)
}
object BuildStreams
{
type Streams = std.Streams[ScopedKey[_]]
final val GlobalPath = "$global"
final val BuildUnitPath = "$build"
final val StreamsDirectory = "streams"
def mkStreams(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope]): State => Streams = s =>
std.Streams( path(units, root, data), displayFull, LogManager.construct(data, s) )
def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope])(scoped: ScopedKey[_]): File =
resolvePath( projectPath(units, root, scoped, data), nonProjectPath(scoped) )
def resolvePath(base: File, components: Seq[String]): File =
(base /: components)( (b,p) => new File(b,p) )
def pathComponent[T](axis: ScopeAxis[T], scoped: ScopedKey[_], label: String)(show: T => String): String =
axis match
{
case Global => GlobalPath
case This => error("Unresolved This reference for " + label + " in " + displayFull(scoped))
case Select(t) => show(t)
}
def nonProjectPath[T](scoped: ScopedKey[T]): Seq[String] =
{
val scope = scoped.scope
pathComponent(scope.config, scoped, "config")(_.name) ::
pathComponent(scope.task, scoped, "task")(_.label) ::
pathComponent(scope.extra, scoped, "extra")(showAMap) ::
Nil
}
def showAMap(a: AttributeMap): String =
a.entries.toSeq.sortBy(_.key.label).map { case AttributeEntry(key, value) => key.label + "=" + value.toString } mkString(" ")
def projectPath(units: Map[URI, LoadedBuildUnit], root: URI, scoped: ScopedKey[_], data: Settings[Scope]): File =
scoped.scope.project match
{
case Global => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath
case Select(br @ BuildRef(uri)) => refTarget(br, units(uri).localBase, data) / BuildUnitPath
case Select(pr @ ProjectRef(uri, id)) => refTarget(pr, units(uri).defined(id).base, data)
case Select(pr) => error("Unresolved project reference (" + pr + ") in " + displayFull(scoped))
case This => error("Unresolved project reference (This) in " + displayFull(scoped))
}
def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File =
refTarget(GlobalScope.copy(project = Select(ref)), fallbackBase, data)
def refTarget(scope: Scope, fallbackBase: File, data: Settings[Scope]): File =
(Keys.target in scope get data getOrElse outputDirectory(fallbackBase).asFile ) / StreamsDirectory
}

View File

@ -1,6 +1,6 @@
package sbt package sbt
import java.net.URI import java.net.URI
final class BuildUtil[Proj]( final class BuildUtil[Proj](
val keyIndex: KeyIndex, val keyIndex: KeyIndex,
@ -37,4 +37,44 @@ final class BuildUtil[Proj](
val configurationsForAxis: Option[ResolvedReference] => Seq[String] = val configurationsForAxis: Option[ResolvedReference] => Seq[String] =
refOpt => configurations(projectForAxis(refOpt)).map(_.name) refOpt => configurations(projectForAxis(refOpt)).map(_.name)
}
object BuildUtil
{
def apply(root: URI, units: Map[URI, LoadedBuildUnit], keyIndex: KeyIndex, data: Settings[Scope]): BuildUtil[ResolvedProject] =
{
val getp = (build: URI, project: String) => Load.getProject(units, build, project)
val configs = (_: ResolvedProject).configurations.map(c => ConfigKey(c.name))
val aggregates = aggregationRelation(units)
new BuildUtil(keyIndex, data, root, Load getRootProject units, getp, configs, aggregates)
}
def checkCycles(units: Map[URI, LoadedBuildUnit])
{
def getRef(pref: ProjectRef) = units(pref.build).defined(pref.project)
def deps(proj: ResolvedProject)(base: ResolvedProject => Seq[ProjectRef]): Seq[ResolvedProject] = Dag.topologicalSort(proj)(p => base(p) map getRef)
// check for cycles
for( (_, lbu) <- units; proj <- lbu.defined.values) {
deps(proj)(_.dependencies.map(_.project))
deps(proj)(_.delegates)
deps(proj)(_.aggregate)
}
}
def baseImports = "import sbt._, Process._, Keys._" :: Nil
def getImports(unit: BuildUnit) = baseImports ++ importAllRoot(unit.plugins.pluginNames ++ unit.definitions.buildNames)
def importAll(values: Seq[String]) = if(values.isEmpty) Nil else values.map( _ + "._" ).mkString("import ", ", ", "") :: Nil
def importAllRoot(values: Seq[String]) = importAll(values map rootedName)
def rootedName(s: String) = if(s contains '.') "_root_." + s else s
def aggregationRelation(units: Map[URI, LoadedBuildUnit]): Relation[ProjectRef, ProjectRef] =
{
val depPairs =
for {
(uri, unit) <- units.toIterable
project <- unit.defined.values
ref = ProjectRef(uri, project.id)
agg <- project.aggregate
} yield
(ref, agg)
Relation.empty ++ depPairs
}
} }

View File

@ -6,7 +6,7 @@ package sbt
import Keys._ import Keys._
import complete.{DefaultParsers, Parser} import complete.{DefaultParsers, Parser}
import DefaultParsers._ import DefaultParsers._
import Project.{ScopedKey, Setting} import Def.{ScopedKey, Setting}
import Scope.GlobalScope import Scope.GlobalScope
object Cross object Cross

View File

@ -7,8 +7,8 @@ package sbt
import Scope.{fillTaskAxis, GlobalScope, ThisScope} import Scope.{fillTaskAxis, GlobalScope, ThisScope}
import xsbt.api.Discovery import xsbt.api.Discovery
import xsbti.compile.CompileOrder import xsbti.compile.CompileOrder
import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting, SettingsDefinition} import Project.{inConfig, inScope, inTask, richInitialize, richInitializeTask, richTaskSessionVar}
import Load.LoadedBuild import Def.{Initialize, ScopedKey, Setting, SettingsDefinition}
import Artifact.{DocClassifier, SourceClassifier} import Artifact.{DocClassifier, SourceClassifier}
import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test} import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
import CrossVersion.{binarySbtVersion, binaryScalaVersion} import CrossVersion.{binarySbtVersion, binaryScalaVersion}
@ -263,7 +263,7 @@ object Defaults extends BuildCommon
override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match { override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match {
case Some(Value(ps)) => ps case Some(Value(ps)) => ps
case Some(Inc(i)) => throw i case Some(Inc(i)) => throw i
case None => error("key not found: " + Project.displayFull(key)) case None => error("key not found: " + Def.displayFull(key))
} }
} }
} }
@ -657,7 +657,7 @@ object Defaults extends BuildCommon
forDependencies[T,T](ref => (key in ref) ?? default(ref), includeRoot, classpath, aggregate) forDependencies[T,T](ref => (key in ref) ?? default(ref), includeRoot, classpath, aggregate)
def forDependencies[T,V](init: ProjectRef => Initialize[V], includeRoot: Boolean = true, classpath: Boolean = true, aggregate: Boolean = false): Initialize[Seq[V]] = def forDependencies[T,V](init: ProjectRef => Initialize[V], includeRoot: Boolean = true, classpath: Boolean = true, aggregate: Boolean = false): Initialize[Seq[V]] =
Project.bind( (loadedBuild, thisProjectRef).identity ) { case (lb, base) => Def.bind( (loadedBuild, thisProjectRef).identity ) { case (lb, base) =>
transitiveDependencies(base, lb, includeRoot, classpath, aggregate) map init join ; transitiveDependencies(base, lb, includeRoot, classpath, aggregate) map init join ;
} }
@ -773,7 +773,7 @@ object Classpaths
) )
val baseSettings: Seq[Setting[_]] = sbtClassifiersTasks ++ Seq( val baseSettings: Seq[Setting[_]] = sbtClassifiersTasks ++ Seq(
conflictWarning in GlobalScope :== ConflictWarning.default("global"), conflictWarning in GlobalScope :== ConflictWarning.default("global"),
conflictWarning <<= (thisProjectRef, conflictWarning) { (ref, cw) => cw.copy(label = Project.display(ref)) }, conflictWarning <<= (thisProjectRef, conflictWarning) { (ref, cw) => cw.copy(label = Reference.display(ref)) },
unmanagedBase <<= baseDirectory / "lib", unmanagedBase <<= baseDirectory / "lib",
normalizedName <<= name(StringUtilities.normalize), normalizedName <<= name(StringUtilities.normalize),
isSnapshot <<= isSnapshot or version(_ endsWith "-SNAPSHOT"), isSnapshot <<= isSnapshot or version(_ endsWith "-SNAPSHOT"),
@ -859,7 +859,7 @@ object Classpaths
(module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) => (module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) =>
val depsUpdated = reports.exists(!_.stats.cached) val depsUpdated = reports.exists(!_.stats.cached)
val isRoot = roots contains resolved val isRoot = roots contains resolved
cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log) cachedUpdate(cacheDirectory / "update", Reference.display(ref), module, config, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log)
} tag(Tags.Update, Tags.Network), } tag(Tags.Update, Tags.Network),
update <<= (conflictWarning, update, streams) map { (config, report, s) => ConflictWarning(config, report, s.log); report }, update <<= (conflictWarning, update, streams) map { (config, report, s) => ConflictWarning(config, report, s.log); report },
transitiveClassifiers in GlobalScope :== Seq(SourceClassifier, DocClassifier), transitiveClassifiers in GlobalScope :== Seq(SourceClassifier, DocClassifier),
@ -1277,12 +1277,12 @@ trait BuildExtra extends BuildCommon
seq( artLocal <<= artifact, taskLocal <<= taskDef, art, pkgd ) seq( artLocal <<= artifact, taskLocal <<= taskDef, art, pkgd )
} }
def seq(settings: Setting[_]*): SettingsDefinition = new Project.SettingList(settings) def seq(settings: Setting[_]*): SettingsDefinition = new Def.SettingList(settings)
def externalIvySettings(file: Initialize[File] = baseDirectory / "ivysettings.xml", addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] = def externalIvySettings(file: Initialize[File] = baseDirectory / "ivysettings.xml", addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
externalIvySettingsURI(file(_.toURI), addMultiResolver) externalIvySettingsURI(file(_.toURI), addMultiResolver)
def externalIvySettingsURL(url: URL, addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] = def externalIvySettingsURL(url: URL, addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
externalIvySettingsURI(Project.value(url.toURI), addMultiResolver) externalIvySettingsURI(Def.value(url.toURI), addMultiResolver)
def externalIvySettingsURI(uri: Initialize[URI], addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] = def externalIvySettingsURI(uri: Initialize[URI], addMultiResolver: Boolean = true): Setting[Task[IvyConfiguration]] =
{ {
val other = (baseDirectory, appConfiguration, projectResolver, streams).identityMap val other = (baseDirectory, appConfiguration, projectResolver, streams).identityMap
@ -1375,12 +1375,12 @@ trait BuildCommon
// intended for use in constructing InputTasks // intended for use in constructing InputTasks
def loadForParser[P,T](task: TaskKey[T])(f: (State, Option[T]) => Parser[P])(implicit format: sbinary.Format[T]): Initialize[State => Parser[P]] = def loadForParser[P,T](task: TaskKey[T])(f: (State, Option[T]) => Parser[P])(implicit format: sbinary.Format[T]): Initialize[State => Parser[P]] =
loadForParserI(task)(Project value f)(format) loadForParserI(task)(Def value f)(format)
def loadForParserI[P,T](task: TaskKey[T])(init: Initialize[(State, Option[T]) => Parser[P]])(implicit format: sbinary.Format[T]): Initialize[State => Parser[P]] = def loadForParserI[P,T](task: TaskKey[T])(init: Initialize[(State, Option[T]) => Parser[P]])(implicit format: sbinary.Format[T]): Initialize[State => Parser[P]] =
(resolvedScoped, init)( (ctx, f) => (s: State) => f( s, loadFromContext(task, ctx, s)(format)) ) (resolvedScoped, init)( (ctx, f) => (s: State) => f( s, loadFromContext(task, ctx, s)(format)) )
def getForParser[P,T](task: TaskKey[T])(init: (State, Option[T]) => Parser[P]): Initialize[State => Parser[P]] = def getForParser[P,T](task: TaskKey[T])(init: (State, Option[T]) => Parser[P]): Initialize[State => Parser[P]] =
getForParserI(task)(Project value init) getForParserI(task)(Def value init)
def getForParserI[P,T](task: TaskKey[T])(init: Initialize[(State, Option[T]) => Parser[P]]): Initialize[State => Parser[P]] = def getForParserI[P,T](task: TaskKey[T])(init: Initialize[(State, Option[T]) => Parser[P]]): Initialize[State => Parser[P]] =
(resolvedScoped, init)( (ctx, f) => (s: State) => f(s, getFromContext(task, ctx, s)) ) (resolvedScoped, init)( (ctx, f) => (s: State) => f(s, getFromContext(task, ctx, s)) )

View File

@ -0,0 +1,151 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import java.io.File
import java.net.URI
import compiler.{Eval, EvalImports}
import complete.DefaultParsers.validID
import Def.{ScopedKey, Setting, SettingsDefinition}
import Scope.GlobalScope
import scala.annotation.tailrec
object EvaluateConfigurations
{
private[this] final class ParsedFile(val imports: Seq[(String,Int)], val definitions: Seq[(String,LineRange)], val settings: Seq[(String,LineRange)])
private[this] final class Definitions(val loader: ClassLoader => ClassLoader, val moduleNames: Seq[String])
private[this] val DefinitionKeywords = Seq("lazy val ", "def ", "val ")
def apply(eval: Eval, srcs: Seq[File], imports: Seq[String]): ClassLoader => Seq[Setting[_]] =
flatten(srcs.sortBy(_.getName) map { src => evaluateConfiguration(eval, src, imports) })
def evaluateConfiguration(eval: Eval, src: File, imports: Seq[String]): ClassLoader => Seq[Setting[_]] =
evaluateConfiguration(eval, src.getPath, IO.readLines(src), imports, 0)
private[this] def parseConfiguration(lines: Seq[String], builtinImports: Seq[String], offset: Int): ParsedFile =
{
val (importStatements, settingsAndDefinitions) = splitExpressions(lines)
val allImports = builtinImports.map(s => (s, -1)) ++ addOffset(offset, importStatements)
val (definitions, settings) = splitSettingsDefinitions(addOffsetToRange(offset, settingsAndDefinitions))
new ParsedFile(allImports, definitions, settings)
}
def evaluateConfiguration(eval: Eval, name: String, lines: Seq[String], imports: Seq[String], offset: Int): ClassLoader => Seq[Setting[_]] =
{
val parsed = parseConfiguration(lines, imports, offset)
val importDefs = if(parsed.definitions.isEmpty) Nil else {
val definitions = evaluateDefinitions(eval, name, parsed.imports, parsed.definitions)
Load.importAllRoot(definitions.moduleNames).map(s => (s, -1))
}
val allImports = importDefs ++ parsed.imports
val settings = parsed.settings map { case (settingExpression,range) =>
evaluateSetting(eval, name, allImports, settingExpression, range)
}
eval.unlinkDeferred()
flatten(settings)
}
def flatten(mksettings: Seq[ClassLoader => Seq[Setting[_]]]): ClassLoader => Seq[Setting[_]] =
loader => mksettings.flatMap(_ apply loader)
def addOffset(offset: Int, lines: Seq[(String,Int)]): Seq[(String,Int)] =
lines.map { case (s, i) => (s, i + offset) }
def addOffsetToRange(offset: Int, ranges: Seq[(String,LineRange)]): Seq[(String,LineRange)] =
ranges.map { case (s, r) => (s, r shift offset) }
val SettingsDefinitionName = classOf[SettingsDefinition].getName
def evaluateSetting(eval: Eval, name: String, imports: Seq[(String,Int)], expression: String, range: LineRange): ClassLoader => Seq[Setting[_]] =
{
val result = try {
eval.eval(expression, imports = new EvalImports(imports, name), srcName = name, tpeName = Some(SettingsDefinitionName), line = range.start)
} catch {
case e: sbt.compiler.EvalException => throw new MessageOnlyException(e.getMessage)
}
loader => {
val pos = RangePosition(name, range shift 1)
result.getValue(loader).asInstanceOf[SettingsDefinition].settings map (_ withPos pos)
}
}
private[this] def isSpace = (c: Char) => Character isWhitespace c
private[this] def fstS(f: String => Boolean): ((String,Int)) => Boolean = { case (s,i) => f(s) }
private[this] def firstNonSpaceIs(lit: String) = (_: String).view.dropWhile(isSpace).startsWith(lit)
private[this] def or[A](a: A => Boolean, b: A => Boolean): A => Boolean = in => a(in) || b(in)
def splitExpressions(lines: Seq[String]): (Seq[(String,Int)], Seq[(String,LineRange)]) =
{
val blank = (_: String).forall(isSpace)
val isImport = firstNonSpaceIs("import ")
val comment = firstNonSpaceIs("//")
val blankOrComment = or(blank, comment)
val importOrBlank = fstS(or(blankOrComment, isImport))
val (imports, settings) = lines.zipWithIndex span importOrBlank
(imports filterNot fstS( blankOrComment ), groupedLines(settings, blank, blankOrComment))
}
def groupedLines(lines: Seq[(String,Int)], delimiter: String => Boolean, skipInitial: String => Boolean): Seq[(String,LineRange)] =
{
val fdelim = fstS(delimiter)
@tailrec def group0(lines: Seq[(String,Int)], accum: Seq[(String,LineRange)]): Seq[(String,LineRange)] =
if(lines.isEmpty) accum.reverse
else
{
val start = lines dropWhile fstS( skipInitial )
val (next, tail) = start.span { case (s,_) => !delimiter(s) }
val grouped = if(next.isEmpty) accum else (next.map(_._1).mkString("\n"), LineRange(next.head._2, next.last._2 + 1)) +: accum
group0(tail, grouped)
}
group0(lines, Nil)
}
private[this] def splitSettingsDefinitions(lines: Seq[(String,LineRange)]): (Seq[(String,LineRange)], Seq[(String,LineRange)]) =
lines partition { case (line, range) => isDefinition(line) }
private[this] def isDefinition(line: String): Boolean =
{
val trimmed = line.trim
DefinitionKeywords.exists(trimmed startsWith _)
}
private[this] def evaluateDefinitions(eval: Eval, name: String, imports: Seq[(String,Int)], definitions: Seq[(String,LineRange)]): Definitions =
{
val convertedRanges = definitions.map { case (s, r) => (s, r.start to r.end) }
val res = eval.evalDefinitions(convertedRanges, new EvalImports(imports, name), name)
new Definitions(loader => res.getValue(loader).getClass.getClassLoader, res.enclosingModule :: Nil)
}
}
object Index
{
def taskToKeyMap(data: Settings[Scope]): Map[Task[_], ScopedKey[Task[_]]] =
{
// AttributeEntry + the checked type test 'value: Task[_]' ensures that the cast is correct.
// (scalac couldn't determine that 'key' is of type AttributeKey[Task[_]] on its own and a type match still required the cast)
val pairs = for( scope <- data.scopes; AttributeEntry(key, value: Task[_]) <- data.data(scope).entries ) yield
(value, ScopedKey(scope, key.asInstanceOf[AttributeKey[Task[_]]])) // unclear why this cast is needed even with a type test in the above filter
pairs.toMap[Task[_], ScopedKey[Task[_]]]
}
def allKeys(settings: Seq[Setting[_]]): Set[ScopedKey[_]] =
settings.flatMap(s => if(s.key.key.isLocal) Nil else s.key +: s.dependencies).filter(!_.key.isLocal).toSet
def attributeKeys(settings: Settings[Scope]): Set[AttributeKey[_]] =
settings.data.values.flatMap(_.keys).toSet[AttributeKey[_]]
def stringToKeyMap(settings: Set[AttributeKey[_]]): Map[String, AttributeKey[_]] =
{
val multiMap = settings.groupBy(_.label)
val duplicates = multiMap collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) } collect { case (k, xs) if xs.size > 1 => (k, xs) }
if(duplicates.isEmpty)
multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap;
else
error(duplicates map { case (k, tps) => "'" + k + "' (" + tps.mkString(", ") + ")" } mkString("AttributeKey ID collisions detected for: ", ", ", ""))
}
private[this] type TriggerMap = collection.mutable.HashMap[Task[_], Seq[Task[_]]]
def triggers(ss: Settings[Scope]): Triggers[Task] =
{
val runBefore = new TriggerMap
val triggeredBy = new TriggerMap
for( (_, amap) <- ss.data; AttributeEntry(_, value: Task[_]) <- amap.entries)
{
val as = value.info.attributes
update(runBefore, value, as get Keys.runBefore)
update(triggeredBy, value, as get Keys.triggeredBy)
}
val onComplete = Keys.onComplete in GlobalScope get ss getOrElse { () => () }
new Triggers[Task](runBefore, triggeredBy, map => { onComplete(); map } )
}
private[this] def update(map: TriggerMap, base: Task[_], tasksOpt: Option[Seq[Task[_]]]): Unit =
for( tasks <- tasksOpt; task <- tasks )
map(task) = base +: map.getOrElse(task, Nil)
}

View File

@ -4,9 +4,10 @@
package sbt package sbt
import java.io.File import java.io.File
import Project.{ScopedKey, Setting} import Def.{displayFull, ScopedKey, Setting}
import Keys.{streams, Streams, TaskStreams} import Keys.{streams, Streams, TaskStreams}
import Keys.{dummyRoots, dummyState, dummyStreamsManager, executionRoots, pluginData, streamsManager, taskDefinitionKey, transformState} import Keys.{dummyRoots, dummyState, dummyStreamsManager, executionRoots, pluginData, streamsManager, taskDefinitionKey, transformState}
import Project.richInitializeTask
import Scope.{GlobalScope, ThisScope} import Scope.{GlobalScope, ThisScope}
import Types.const import Types.const
import scala.Console.RED import scala.Console.RED
@ -25,8 +26,6 @@ object PluginData
object EvaluateTask object EvaluateTask
{ {
import Load.BuildStructure
import Project.display
import std.{TaskExtra,Transform} import std.{TaskExtra,Transform}
import TaskExtra._ import TaskExtra._
import Keys.state import Keys.state
@ -34,7 +33,7 @@ object EvaluateTask
val SystemProcessors = Runtime.getRuntime.availableProcessors val SystemProcessors = Runtime.getRuntime.availableProcessors
def defaultConfig(state: State): EvaluateConfig = def defaultConfig(state: State): EvaluateConfig =
EvaluateConfig(false, restrictions(state)) EvaluateConfig(false, restrictions(state))
def defaultConfig(extracted: Extracted, structure: Load.BuildStructure) = def defaultConfig(extracted: Extracted, structure: BuildStructure) =
EvaluateConfig(false, restrictions(extracted, structure)) EvaluateConfig(false, restrictions(extracted, structure))
def extractedConfig(extracted: Extracted, structure: BuildStructure): EvaluateConfig = def extractedConfig(extracted: Extracted, structure: BuildStructure): EvaluateConfig =
@ -45,7 +44,7 @@ object EvaluateTask
} }
def defaultRestrictions(maxWorkers: Int) = Tags.limitAll(maxWorkers) :: Nil def defaultRestrictions(maxWorkers: Int) = Tags.limitAll(maxWorkers) :: Nil
def defaultRestrictions(extracted: Extracted, structure: Load.BuildStructure): Seq[Tags.Rule] = def defaultRestrictions(extracted: Extracted, structure: BuildStructure): Seq[Tags.Rule] =
Tags.limitAll(maxWorkers(extracted, structure)) :: Nil Tags.limitAll(maxWorkers(extracted, structure)) :: Nil
def restrictions(state: State): Seq[Tags.Rule] = def restrictions(state: State): Seq[Tags.Rule] =
@ -53,16 +52,16 @@ object EvaluateTask
val extracted = Project.extract(state) val extracted = Project.extract(state)
restrictions(extracted, extracted.structure) restrictions(extracted, extracted.structure)
} }
def restrictions(extracted: Extracted, structure: Load.BuildStructure): Seq[Tags.Rule] = def restrictions(extracted: Extracted, structure: BuildStructure): Seq[Tags.Rule] =
getSetting(Keys.concurrentRestrictions, defaultRestrictions(extracted, structure), extracted, structure) getSetting(Keys.concurrentRestrictions, defaultRestrictions(extracted, structure), extracted, structure)
def maxWorkers(extracted: Extracted, structure: Load.BuildStructure): Int = def maxWorkers(extracted: Extracted, structure: BuildStructure): Int =
if(getSetting(Keys.parallelExecution, true, extracted, structure)) if(getSetting(Keys.parallelExecution, true, extracted, structure))
SystemProcessors SystemProcessors
else else
1 1
def cancelable(extracted: Extracted, structure: Load.BuildStructure): Boolean = def cancelable(extracted: Extracted, structure: BuildStructure): Boolean =
getSetting(Keys.cancelable, false, extracted, structure) getSetting(Keys.cancelable, false, extracted, structure)
def getSetting[T](key: SettingKey[T], default: T, extracted: Extracted, structure: Load.BuildStructure): T = def getSetting[T](key: SettingKey[T], default: T, extracted: Extracted, structure: BuildStructure): T =
key in extracted.currentRef get structure.data getOrElse default key in extracted.currentRef get structure.data getOrElse default
def injectSettings: Seq[Setting[_]] = Seq( def injectSettings: Seq[Setting[_]] = Seq(
@ -97,7 +96,7 @@ object EvaluateTask
def logIncomplete(result: Incomplete, state: State, streams: Streams) def logIncomplete(result: Incomplete, state: State, streams: Streams)
{ {
val all = Incomplete linearize result val all = Incomplete linearize result
val keyed = for(Incomplete(Some(key: Project.ScopedKey[_]), _, msg, _, ex) <- all) yield (key, msg, ex) val keyed = for(Incomplete(Some(key: ScopedKey[_]), _, msg, _, ex) <- all) yield (key, msg, ex)
val un = all.filter { i => i.node.isEmpty || i.message.isEmpty } val un = all.filter { i => i.node.isEmpty || i.message.isEmpty }
import ExceptionCategory._ import ExceptionCategory._
@ -199,7 +198,7 @@ object EvaluateTask
case _ => c.toString case _ => c.toString
} }
def name(node: Task[_]): String = def name(node: Task[_]): String =
node.info.name orElse transformNode(node).map(Project.displayFull) getOrElse ("<anon-" + System.identityHashCode(node).toHexString + ">") node.info.name orElse transformNode(node).map(displayFull) getOrElse ("<anon-" + System.identityHashCode(node).toHexString + ">")
def liftAnonymous: Incomplete => Incomplete = { def liftAnonymous: Incomplete => Incomplete = {
case i @ Incomplete(node, tpe, None, causes, None) => case i @ Incomplete(node, tpe, None, causes, None) =>
causes.find( inc => !inc.node.isDefined && (inc.message.isDefined || inc.directCause.isDefined)) match { causes.find( inc => !inc.node.isDefined && (inc.message.isDefined || inc.directCause.isDefined)) match {

48
main/Extracted.scala Normal file
View File

@ -0,0 +1,48 @@
package sbt
import Project._
import Scope.GlobalScope
import Def.{ScopedKey, Setting}
final case class Extracted(structure: BuildStructure, session: SessionSettings, currentRef: ProjectRef)(implicit val showKey: Show[ScopedKey[_]])
{
def rootProject = structure.rootProject
lazy val currentUnit = structure units currentRef.build
lazy val currentProject = currentUnit defined currentRef.project
lazy val currentLoader: ClassLoader = currentUnit.loader
def get[T](key: TaskKey[T]): Task[T] = get(key.task)
def get[T](key: SettingKey[T]) = getOrError(inCurrent(key), key.key)
def getOpt[T](key: SettingKey[T]): Option[T] = structure.data.get(inCurrent(key), key.key)
private[this] def inCurrent[T](key: SettingKey[T]): Scope = if(key.scope.project == This) key.scope.copy(project = Select(currentRef)) else key.scope
@deprecated("This method does not apply state changes requested during task execution. Use 'runTask' instead, which does.", "0.11.1")
def evalTask[T](key: TaskKey[T], state: State): T = runTask(key, state)._2
def runTask[T](key: TaskKey[T], state: State): (State, T) =
{
import EvaluateTask._
val rkey = resolve(key.scopedKey)
val config = extractedConfig(this, structure)
val value: Option[(State, Result[T])] = apply(structure, key.task.scopedKey, state, currentRef, config)
val (newS, result) = getOrError(rkey.scope, rkey.key, value)
(newS, processResult(result, newS.log))
}
def runAggregated[T](key: TaskKey[T], state: State): State =
{
val rkey = resolve(key.scopedKey)
val keys = Aggregation.aggregate(rkey, ScopeMask(), structure.extra)
val tasks = Act.keyValues(structure)(keys)
Aggregation.runTasks(state, structure, tasks, Aggregation.Dummies(KNil, HNil), show = false )(showKey)
}
private[this] def resolve[T](key: ScopedKey[T]): ScopedKey[T] =
Project.mapScope(Scope.resolveScope(GlobalScope, currentRef.build, rootProject) )( key.scopedKey )
private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T])(implicit display: Show[ScopedKey[_]]): T =
value getOrElse error(display(ScopedKey(scope, key)) + " is undefined.")
private def getOrError[T](scope: Scope, key: AttributeKey[T])(implicit display: Show[ScopedKey[_]]): T =
structure.data.get(scope, key) getOrElse error(display(ScopedKey(scope, key)) + " is undefined.")
def append(settings: Seq[Setting[_]], state: State): State =
{
val appendSettings = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
val newStructure = Load.reapply(session.original ++ appendSettings, structure)
Project.setProject(session, newStructure, state)
}
}

View File

@ -1,7 +1,7 @@
package sbt package sbt
import Load._ import Load._
import Project._ import Def.{ScopedKey,Setting}
import Scoped._ import Scoped._
import Keys._ import Keys._
import Configurations.{Compile,Runtime} import Configurations.{Compile,Runtime}
@ -64,7 +64,7 @@ object GlobalPlugin
(newS, processResult(result, newS.log)) (newS, processResult(result, newS.log))
} }
} }
val globalPluginSettings = inScope(Scope.GlobalScope in LocalRootProject)(Seq( val globalPluginSettings = Project.inScope(Scope.GlobalScope in LocalRootProject)(Seq(
organization := SbtArtifacts.Organization, organization := SbtArtifacts.Organization,
onLoadMessage <<= Keys.baseDirectory("Loading global plugins from " + _), onLoadMessage <<= Keys.baseDirectory("Loading global plugins from " + _),
name := "global-plugin", name := "global-plugin",

View File

@ -6,6 +6,7 @@ package sbt
import java.io.File import java.io.File
import Attributed.blankSeq import Attributed.blankSeq
import Configurations.Compile import Configurations.Compile
import Def.Setting
import Keys._ import Keys._
object IvyConsole object IvyConsole
@ -22,7 +23,7 @@ object IvyConsole
val extracted = Project.extract(session, structure) val extracted = Project.extract(session, structure)
import extracted._ import extracted._
val depSettings: Seq[Project.Setting[_]] = Seq( val depSettings: Seq[Setting[_]] = Seq(
libraryDependencies ++= managed.reverse, libraryDependencies ++= managed.reverse,
resolvers ++= repos.reverse, resolvers ++= repos.reverse,
unmanagedJars in Compile ++= Attributed blankSeq unmanaged.reverse, unmanagedJars in Compile ++= Attributed blankSeq unmanaged.reverse,

View File

@ -4,8 +4,7 @@
package sbt package sbt
import java.net.URI import java.net.URI
import Project.ScopedKey import Def.ScopedKey
import Load.BuildStructure
import complete.DefaultParsers.validID import complete.DefaultParsers.validID
import Types.{idFun, some} import Types.{idFun, some}

View File

@ -5,7 +5,7 @@ package sbt
import java.io.File import java.io.File
import java.net.URL import java.net.URL
import Project.ScopedKey import Def.ScopedKey
import complete._ import complete._
import inc.Analysis import inc.Analysis
import inc.Locate.DefinesClass import inc.Locate.DefinesClass
@ -38,9 +38,9 @@ object Keys
// Project keys // Project keys
val projectCommand = AttributeKey[Boolean]("project-command", "Marks Commands that were registered for the current Project.", Invisible) val projectCommand = AttributeKey[Boolean]("project-command", "Marks Commands that were registered for the current Project.", Invisible)
val sessionSettings = AttributeKey[SessionSettings]("session-settings", "Tracks current build, project, and setting modifications.", DSetting) val sessionSettings = AttributeKey[SessionSettings]("session-settings", "Tracks current build, project, and setting modifications.", DSetting)
val stateBuildStructure = AttributeKey[Load.BuildStructure]("build-structure", "Data structure containing all information about the build definition.", BSetting) val stateBuildStructure = AttributeKey[BuildStructure]("build-structure", "Data structure containing all information about the build definition.", BSetting)
val buildStructure = TaskKey[Load.BuildStructure]("build-structure", "Provides access to the build structure, settings, and streams manager.", DTask) val buildStructure = TaskKey[BuildStructure]("build-structure", "Provides access to the build structure, settings, and streams manager.", DTask)
val loadedBuild = SettingKey[Load.LoadedBuild]("loaded-build", "Provides access to the loaded project structure. This is the information available before settings are evaluated.", DSetting) val loadedBuild = SettingKey[LoadedBuild]("loaded-build", "Provides access to the loaded project structure. This is the information available before settings are evaluated.", DSetting)
val buildDependencies = SettingKey[BuildDependencies]("build-dependencies", "Definitive source of inter-project dependencies for compilation and dependency management.\n\tThis is populated by default by the dependencies declared on Project instances, but may be modified.\n\tThe main restriction is that new builds may not be introduced.", DSetting) val buildDependencies = SettingKey[BuildDependencies]("build-dependencies", "Definitive source of inter-project dependencies for compilation and dependency management.\n\tThis is populated by default by the dependencies declared on Project instances, but may be modified.\n\tThe main restriction is that new builds may not be introduced.", DSetting)
val appConfiguration = SettingKey[xsbti.AppConfiguration]("app-configuration", "Provides access to the launched sbt configuration, including the ScalaProvider, Launcher, and GlobalLock.", DSetting) val appConfiguration = SettingKey[xsbti.AppConfiguration]("app-configuration", "Provides access to the launched sbt configuration, including the ScalaProvider, Launcher, and GlobalLock.", DSetting)
val thisProject = SettingKey[ResolvedProject]("this-project", "Provides the current project for the referencing scope.", CSetting) val thisProject = SettingKey[ResolvedProject]("this-project", "Provides the current project for the referencing scope.", CSetting)
@ -70,10 +70,6 @@ object Keys
// Path Keys // Path Keys
val baseDirectory = SettingKey[File]("base-directory", "The base directory. Depending on the scope, this is the base directory for the build, project, configuration, or task.", AMinusSetting) val baseDirectory = SettingKey[File]("base-directory", "The base directory. Depending on the scope, this is the base directory for the build, project, configuration, or task.", AMinusSetting)
val globalBaseDirectory = AttributeKey[File]("global-base-directory", "The base directory for global sbt configuration and staging.", DSetting)
val globalPluginsDirectory = AttributeKey[File]("global-plugins-directory", "The base directory for global sbt plugins.", DSetting)
val globalSettingsDirectory = AttributeKey[File]("global-settings-directory", "The base directory for global sbt settings.", DSetting)
val stagingDirectory = AttributeKey[File]("staging-directory", "The directory for staging remote projects.", DSetting)
val target = SettingKey[File]("target", "Main directory for files generated by the build.", AMinusSetting) val target = SettingKey[File]("target", "Main directory for files generated by the build.", AMinusSetting)
val crossTarget = SettingKey[File]("cross-target", "Main directory for files generated by the build that are cross-built.", BSetting) val crossTarget = SettingKey[File]("cross-target", "Main directory for files generated by the build that are cross-built.", BSetting)
@ -210,7 +206,7 @@ object Keys
val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.", DSetting) val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.", DSetting)
// Classpath/Dependency Management Keys // Classpath/Dependency Management Keys
type Classpath = Seq[Attributed[File]] type Classpath = Def.Classpath
val name = SettingKey[String]("name", "Project name.", APlusSetting) val name = SettingKey[String]("name", "Project name.", APlusSetting)
val normalizedName = SettingKey[String]("normalized-name", "Project name transformed from mixed case and spaces to lowercase and dash-separated.", BSetting) val normalizedName = SettingKey[String]("normalized-name", "Project name transformed from mixed case and spaces to lowercase and dash-separated.", BSetting)
@ -333,12 +329,11 @@ object Keys
val (executionRoots, dummyRoots)= dummy[Seq[ScopedKey[_]]]("execution-roots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.") val (executionRoots, dummyRoots)= dummy[Seq[ScopedKey[_]]]("execution-roots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.")
val (state, dummyState) = dummy[State]("state", "Current build state.") val (state, dummyState) = dummy[State]("state", "Current build state.")
val (streamsManager, dummyStreamsManager) = dummy[Streams]("streams-manager", "Streams manager, which provides streams for different contexts.") val (streamsManager, dummyStreamsManager) = dummy[Streams]("streams-manager", "Streams manager, which provides streams for different contexts.")
val resolvedScoped = SettingKey[ScopedKey[_]]("resolved-scoped", "The ScopedKey for the referencing setting or task.", DSetting) val resolvedScoped = Def.resolvedScoped
val pluginData = TaskKey[PluginData]("plugin-data", "Information from the plugin build needed in the main build definition.", DTask) val pluginData = TaskKey[PluginData]("plugin-data", "Information from the plugin build needed in the main build definition.", DTask)
private[sbt] val parseResult: TaskKey[Any] = TaskKey("$parse-result", "Internal: used to implement input tasks.", Invisible)
val triggeredBy = AttributeKey[Seq[Task[_]]]("triggered-by") val triggeredBy = Def.triggeredBy
val runBefore = AttributeKey[Seq[Task[_]]]("run-before") val runBefore = Def.runBefore
type Streams = std.Streams[ScopedKey[_]] type Streams = std.Streams[ScopedKey[_]]
type TaskStreams = std.TaskStreams[ScopedKey[_]] type TaskStreams = std.TaskStreams[ScopedKey[_]]
@ -351,47 +346,3 @@ object Keys
} }
def isDummy(t: Task[_]): Boolean = t.info.attributes.get(isDummyTask) getOrElse false def isDummy(t: Task[_]): Boolean = t.info.attributes.get(isDummyTask) getOrElse false
} }
object KeyRanks
{
// task and setting ranks, used to prioritize displaying information
// main tasks
final val APlusTask = 4
final val ATask = 5
final val AMinusTask = 6
// main settings
final val APlusSetting = 9
final val ASetting = 10
final val AMinusSetting = 11
// less major tasks or tasks that print useful information
final val BPlusTask = 29
final val BTask = 30
final val BMinusTask = 31
// secondary settings
final val BPlusSetting = 39
final val BSetting = 40
final val BMinusSetting = 41
// advanced settings
final val CSetting = 100
// advanced tasks
final val CTask = 200
// explicit settings
final val DSetting = 10000
// explicit tasks
final val DTask = 20000
final val MainTaskCutoff = AMinusTask
final val MainSettingCutoff = AMinusSetting
final val MainCutoff = math.max(AMinusTask, AMinusSetting)
final val DefaultTaskRank = (ATask + BTask)/2
final val DefaultInputRank = ATask // input tasks are likely a main task
final val DefaultSettingRank = (ASetting + BSetting) / 2
// implementation details
val Invisible = Int.MaxValue
}

View File

@ -13,20 +13,20 @@ package sbt
import collection.mutable import collection.mutable
import Compiler.{Compilers,Inputs} import Compiler.{Compilers,Inputs}
import inc.{FileValueCache, Locate} import inc.{FileValueCache, Locate}
import Project.{inScope, ScopedKey, ScopeLocal, Setting} import Project.{inScope,makeSettings}
import Keys.{appConfiguration, baseDirectory, configuration, fullResolvers, fullClasspath, pluginData, streams, Streams, thisProject, thisProjectRef, update} import Def.{parseResult, ScopedKey, ScopeLocal, Setting}
import Keys.{exportedProducts, isDummy, loadedBuild, parseResult, resolvedScoped, taskDefinitionKey} import Keys.{appConfiguration, baseDirectory, configuration, fullResolvers, fullClasspath, pluginData, streams, thisProject, thisProjectRef, update}
import Keys.{exportedProducts, isDummy, loadedBuild, resolvedScoped, taskDefinitionKey}
import tools.nsc.reporters.ConsoleReporter import tools.nsc.reporters.ConsoleReporter
import Build.{analyzed, data} import Build.{analyzed, data}
import Scope.{GlobalScope, ThisScope} import Scope.{GlobalScope, ThisScope}
import Types.const import Types.const
object Load
{
import BuildPaths._ import BuildPaths._
import BuildStreams._ import BuildStreams._
import Locate.DefinesClass import Locate.DefinesClass
object Load
{
// note that there is State passed in but not pulled out // note that there is State passed in but not pulled out
def defaultLoad(state: State, baseDirectory: File, log: Logger, isPlugin: Boolean = false, topLevelExtras: List[URI] = Nil): (() => Eval, BuildStructure) = def defaultLoad(state: State, baseDirectory: File, log: Logger, isPlugin: Boolean = false, topLevelExtras: List[URI] = Nil): (() => Eval, BuildStructure) =
{ {
@ -55,7 +55,7 @@ object Load
new LoadBuildConfiguration(stagingDirectory, classpath, loader, compilers, evalPluginDef, definesClass, delegates, new LoadBuildConfiguration(stagingDirectory, classpath, loader, compilers, evalPluginDef, definesClass, delegates,
EvaluateTask.injectStreams, pluginMgmt, inject, None, Nil, log) EvaluateTask.injectStreams, pluginMgmt, inject, None, Nil, log)
} }
def injectGlobal(state: State): Seq[Project.Setting[_]] = def injectGlobal(state: State): Seq[Setting[_]] =
(appConfiguration in GlobalScope :== state.configuration) +: (appConfiguration in GlobalScope :== state.configuration) +:
EvaluateTask.injectSettings EvaluateTask.injectSettings
def defaultWithGlobal(state: State, base: File, rawConfig: LoadBuildConfiguration, globalBase: File, log: Logger): LoadBuildConfiguration = def defaultWithGlobal(state: State, base: File, rawConfig: LoadBuildConfiguration, globalBase: File, log: Logger): LoadBuildConfiguration =
@ -126,7 +126,7 @@ object Load
lazy val rootEval = lazyEval(loaded.units(loaded.root).unit) lazy val rootEval = lazyEval(loaded.units(loaded.root).unit)
val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings)) val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings))
val delegates = config.delegates(loaded) val delegates = config.delegates(loaded)
val data = Project.makeSettings(settings, delegates, config.scopeLocal)( Project.showLoadingKey( loaded ) ) val data = makeSettings(settings, delegates, config.scopeLocal)( Project.showLoadingKey( loaded ) )
val index = structureIndex(data, settings, loaded.extra(data)) val index = structureIndex(data, settings, loaded.extra(data))
val streams = mkStreams(projects, loaded.root, data) val streams = mkStreams(projects, loaded.root, data)
(rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal)) (rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal))
@ -156,7 +156,7 @@ object Load
case resolvedScoped.key => Some(defining.asInstanceOf[T]) case resolvedScoped.key => Some(defining.asInstanceOf[T])
case parseResult.key => case parseResult.key =>
import std.TaskExtra._ import std.TaskExtra._
val getResult = InputTask.inputMap map { m => m get defining getOrElse error("No parsed value for " + Project.displayFull(defining) + "\n" + m) } val getResult = InputTask.inputMap map { m => m get defining getOrElse error("No parsed value for " + Def.displayFull(defining) + "\n" + m) }
Some(getResult.asInstanceOf[T]) Some(getResult.asInstanceOf[T])
case _ => None case _ => None
} }
@ -180,7 +180,7 @@ object Load
def reapply(newSettings: Seq[Setting[_]], structure: BuildStructure)(implicit display: Show[ScopedKey[_]]): BuildStructure = def reapply(newSettings: Seq[Setting[_]], structure: BuildStructure)(implicit display: Show[ScopedKey[_]]): BuildStructure =
{ {
val transformed = finalTransforms(newSettings) val transformed = finalTransforms(newSettings)
val newData = Project.makeSettings(transformed, structure.delegates, structure.scopeLocal) val newData = makeSettings(transformed, structure.delegates, structure.scopeLocal)
val newIndex = structureIndex(newData, transformed, index => buildUtil(structure.root, structure.units, index, newData)) val newIndex = structureIndex(newData, transformed, index => buildUtil(structure.root, structure.units, index, newData))
val newStreams = mkStreams(structure.units, structure.root, newData) val newStreams = mkStreams(structure.units, structure.root, newData)
new BuildStructure(units = structure.units, root = structure.root, settings = transformed, data = newData, index = newIndex, streams = newStreams, delegates = structure.delegates, scopeLocal = structure.scopeLocal) new BuildStructure(units = structure.units, root = structure.root, settings = transformed, data = newData, index = newIndex, streams = newStreams, delegates = structure.delegates, scopeLocal = structure.scopeLocal)
@ -439,7 +439,7 @@ object Load
"Put .sbt plugin definitions directly in project/,\n .scala plugin definitions in project/project/,\n and remove the project/plugins/ directory.") "Put .sbt plugin definitions directly in project/,\n .scala plugin definitions in project/project/,\n and remove the project/plugins/ directory.")
val plugs = plugins(pluginDir, s, config) val plugs = plugins(pluginDir, s, config)
val defs = definitionSources(defDir) val defs = definitionSources(defDir)
val target = buildOutputDirectory(defDir, config.compilers) val target = buildOutputDirectory(defDir, config.compilers.scalac.scalaInstance)
IO.createDirectory(target) IO.createDirectory(target)
val loadedDefs = val loadedDefs =
if(defs.isEmpty) if(defs.isEmpty)
@ -594,10 +594,6 @@ object Load
def loadPlugin(pluginName: String, loader: ClassLoader): Plugin = def loadPlugin(pluginName: String, loader: ClassLoader): Plugin =
ModuleUtilities.getObject(pluginName, loader).asInstanceOf[Plugin] ModuleUtilities.getObject(pluginName, loader).asInstanceOf[Plugin]
def importAll(values: Seq[String]) = if(values.isEmpty) Nil else values.map( _ + "._" ).mkString("import ", ", ", "") :: Nil
def importAllRoot(values: Seq[String]) = importAll(values map rootedName)
def rootedName(s: String) = if(s contains '.') "_root_." + s else s
def findPlugins(analysis: inc.Analysis): Seq[String] = discover(analysis, "sbt.Plugin") def findPlugins(analysis: inc.Analysis): Seq[String] = discover(analysis, "sbt.Plugin")
def findDefinitions(analysis: inc.Analysis): Seq[String] = discover(analysis, "sbt.Build") def findDefinitions(analysis: inc.Analysis): Seq[String] = discover(analysis, "sbt.Build")
def discover(analysis: inc.Analysis, subclasses: String*): Seq[String] = def discover(analysis: inc.Analysis, subclasses: String*): Seq[String] =
@ -634,93 +630,65 @@ object Load
} }
def defaultEvalOptions: Seq[String] = Nil def defaultEvalOptions: Seq[String] = Nil
def baseImports = "import sbt._, Process._, Keys._" :: Nil
final class EvaluatedConfigurations(val eval: Eval, val settings: Seq[Setting[_]]) @deprecated("Use BuildUtil.baseImports", "0.13.0")
final class LoadedDefinitions(val base: File, val target: Seq[File], val loader: ClassLoader, val builds: Seq[Build], val buildNames: Seq[String]) def baseImports = BuildUtil.baseImports
final class LoadedPlugins(val base: File, val pluginData: PluginData, val loader: ClassLoader, val plugins: Seq[Plugin], val pluginNames: Seq[String]) @deprecated("Use BuildUtil.checkCycles", "0.13.0")
{ def checkCycles(units: Map[URI, LoadedBuildUnit]): Unit = BuildUtil.checkCycles(units)
def fullClasspath: Seq[Attributed[File]] = pluginData.classpath @deprecated("Use BuildUtil.importAll", "0.13.0")
def classpath: Seq[File] = data(fullClasspath) def importAll(values: Seq[String]): Seq[String] = BuildUtil.importAll(values)
} @deprecated("Use BuildUtil.importAllRoot", "0.13.0")
final class BuildUnit(val uri: URI, val localBase: File, val definitions: LoadedDefinitions, val plugins: LoadedPlugins) def importAllRoot(values: Seq[String]): Seq[String] = BuildUtil.importAllRoot(values)
{ @deprecated("Use BuildUtil.rootedNames", "0.13.0")
override def toString = if(uri.getScheme == "file") localBase.toString else (uri + " (locally: " + localBase +")") def rootedName(s: String): String = BuildUtil.rootedName(s)
} @deprecated("Use BuildUtil.getImports", "0.13.0")
def getImports(unit: BuildUnit): Seq[String] = BuildUtil.getImports(unit)
final class LoadedBuild(val root: URI, val units: Map[URI, LoadedBuildUnit])
{
checkCycles(units)
def allProjectRefs: Seq[(ProjectRef, ResolvedProject)] = for( (uri, unit) <- units.toSeq; (id, proj) <- unit.defined ) yield ProjectRef(uri, id) -> proj
def extra(data: Settings[Scope])(keyIndex: KeyIndex): BuildUtil[ResolvedProject] = buildUtil(root, units, keyIndex, data)
}
def checkCycles(units: Map[URI, LoadedBuildUnit])
{
def getRef(pref: ProjectRef) = units(pref.build).defined(pref.project)
def deps(proj: ResolvedProject)(base: ResolvedProject => Seq[ProjectRef]): Seq[ResolvedProject] = Dag.topologicalSort(proj)(p => base(p) map getRef)
// check for cycles
for( (_, lbu) <- units; proj <- lbu.defined.values) {
deps(proj)(_.dependencies.map(_.project))
deps(proj)(_.delegates)
deps(proj)(_.aggregate)
}
}
final class PartBuild(val root: URI, val units: Map[URI, PartBuildUnit])
sealed trait BuildUnitBase { def rootProjects: Seq[String]; def buildSettings: Seq[Setting[_]] }
final class PartBuildUnit(val unit: BuildUnit, val defined: Map[String, Project], val rootProjects: Seq[String], val buildSettings: Seq[Setting[_]]) extends BuildUnitBase
{
def resolve(f: Project => ResolvedProject): LoadedBuildUnit = new LoadedBuildUnit(unit, defined mapValues f toMap, rootProjects, buildSettings)
def resolveRefs(f: ProjectReference => ProjectRef): LoadedBuildUnit = resolve(_ resolve f)
}
final class LoadedBuildUnit(val unit: BuildUnit, val defined: Map[String, ResolvedProject], val rootProjects: Seq[String], val buildSettings: Seq[Setting[_]]) extends BuildUnitBase
{
assert(!rootProjects.isEmpty, "No root projects defined for build unit " + unit)
val root = rootProjects.head
def localBase = unit.localBase
def classpath: Seq[File] = unit.definitions.target ++ unit.plugins.classpath
def loader = unit.definitions.loader
def imports = getImports(unit)
override def toString = unit.toString
}
def getImports(unit: BuildUnit) = baseImports ++ importAllRoot(unit.plugins.pluginNames ++ unit.definitions.buildNames)
def referenced[PR <: ProjectReference](definitions: Seq[ProjectDefinition[PR]]): Seq[PR] = definitions flatMap { _.referenced } def referenced[PR <: ProjectReference](definitions: Seq[ProjectDefinition[PR]]): Seq[PR] = definitions flatMap { _.referenced }
final class BuildStructure(val units: Map[URI, LoadedBuildUnit], val root: URI, val settings: Seq[Setting[_]], val data: Settings[Scope], val index: StructureIndex, val streams: State => Streams, val delegates: Scope => Seq[Scope], val scopeLocal: ScopeLocal) @deprecated("LoadedBuildUnit is now top-level", "0.13.0")
{ type LoadedBuildUnit = sbt.LoadedBuildUnit
val rootProject: URI => String = Load getRootProject units
def allProjects: Seq[ResolvedProject] = units.values.flatMap(_.defined.values).toSeq @deprecated("BuildStructure is now top-level", "0.13.0")
def allProjects(build: URI): Seq[ResolvedProject] = units.get(build).toList.flatMap(_.defined.values) type BuildStructure = sbt.BuildStructure
def allProjectRefs: Seq[ProjectRef] = units.toSeq flatMap { case (build, unit) => refs(build, unit.defined.values.toSeq) }
def allProjectRefs(build: URI): Seq[ProjectRef] = refs(build, allProjects(build)) @deprecated("StructureIndex is now top-level", "0.13.0")
val extra: BuildUtil[ResolvedProject] = buildUtil(root, units, index.keyIndex, data) type StructureIndex = sbt.StructureIndex
private[this] def refs(build: URI, projects: Seq[ResolvedProject]): Seq[ProjectRef] = projects.map { p => ProjectRef(build, p.id) }
} @deprecated("LoadBuildConfiguration is now top-level", "0.13.0")
def buildUtil(root: URI, units: Map[URI, LoadedBuildUnit], keyIndex: KeyIndex, data: Settings[Scope]): BuildUtil[ResolvedProject] = type LoadBuildConfiguration = sbt.LoadBuildConfiguration
{ @deprecated("LoadBuildConfiguration is now top-level", "0.13.0")
val getp = (build: URI, project: String) => Load.getProject(units, build, project) val LoadBuildConfiguration = sbt.LoadBuildConfiguration
val configs = (_: ResolvedProject).configurations.map(c => ConfigKey(c.name))
val aggregates = Aggregation.relation(units) final class EvaluatedConfigurations(val eval: Eval, val settings: Seq[Setting[_]])
new BuildUtil(keyIndex, data, root, Load getRootProject units, getp, configs, aggregates)
}
final case class LoadBuildConfiguration(stagingDirectory: File, classpath: Seq[Attributed[File]], loader: ClassLoader,
compilers: Compilers, evalPluginDef: (BuildStructure, State) => PluginData, definesClass: DefinesClass,
delegates: LoadedBuild => Scope => Seq[Scope], scopeLocal: ScopeLocal,
pluginManagement: PluginManagement, injectSettings: InjectSettings, globalPlugin: Option[GlobalPlugin], extraBuilds: Seq[URI],
log: Logger)
{
lazy val (globalPluginClasspath, globalPluginLoader) = pluginDefinitionLoader(this, Load.globalPluginClasspath(globalPlugin))
lazy val globalPluginNames = if(globalPluginClasspath.isEmpty) Nil else getPluginNames(globalPluginClasspath, globalPluginLoader)
}
final case class InjectSettings(global: Seq[Setting[_]], project: Seq[Setting[_]], projectLoaded: ClassLoader => Seq[Setting[_]]) final case class InjectSettings(global: Seq[Setting[_]], project: Seq[Setting[_]], projectLoaded: ClassLoader => Seq[Setting[_]])
// information that is not original, but can be reconstructed from the rest of BuildStructure @deprecated("LoadedDefinitions is now top-level", "0.13.0")
final class StructureIndex( type LoadedDefinitions = sbt.LoadedDefinitions
val keyMap: Map[String, AttributeKey[_]], @deprecated("LoadedPlugins is now top-level", "0.13.0")
val taskToKey: Map[Task[_], ScopedKey[Task[_]]], type LoadedPlugins = sbt.LoadedPlugins
val triggers: Triggers[Task], @deprecated("BuildUnit is now top-level", "0.13.0")
val keyIndex: KeyIndex, type BuildUnit = sbt.BuildUnit
val aggregateKeyIndex: KeyIndex @deprecated("LoadedBuild is now top-level", "0.13.0")
) type LoadedBuild = sbt.LoadedBuild
@deprecated("PartBuild is now top-level", "0.13.0")
type PartBuild = sbt.PartBuild
@deprecated("BuildUnitBase is now top-level", "0.13.0")
type BuildUnitBase = sbt.BuildUnitBase
@deprecated("PartBuildUnit is now top-level", "0.13.0")
type PartBuildUnit = sbt.PartBuildUnit
@deprecated("Use BuildUtil.apply", "0.13.0")
def buildUtil(root: URI, units: Map[URI, LoadedBuildUnit], keyIndex: KeyIndex, data: Settings[Scope]): BuildUtil[ResolvedProject] = BuildUtil(root, units, keyIndex, data)
} }
final case class LoadBuildConfiguration(stagingDirectory: File, classpath: Seq[Attributed[File]], loader: ClassLoader,
compilers: Compilers, evalPluginDef: (BuildStructure, State) => PluginData, definesClass: DefinesClass,
delegates: LoadedBuild => Scope => Seq[Scope], scopeLocal: ScopeLocal,
pluginManagement: PluginManagement, injectSettings: Load.InjectSettings, globalPlugin: Option[GlobalPlugin], extraBuilds: Seq[URI],
log: Logger)
{
lazy val (globalPluginClasspath, globalPluginLoader) = Load.pluginDefinitionLoader(this, Load.globalPluginClasspath(globalPlugin))
lazy val globalPluginNames = if(globalPluginClasspath.isEmpty) Nil else Load.getPluginNames(globalPluginClasspath, globalPluginLoader)
}
final class IncompatiblePluginsException(msg: String, cause: Throwable) extends Exception(msg, cause) final class IncompatiblePluginsException(msg: String, cause: Throwable) extends Exception(msg, cause)

View File

@ -7,7 +7,7 @@ package sbt
import java.io.File import java.io.File
import LogManager._ import LogManager._
import std.Transform import std.Transform
import Project.ScopedKey import Def.ScopedKey
import Scope.GlobalScope import Scope.GlobalScope
import MainLogging._ import MainLogging._
import Keys.{logLevel, logManager, persistLogLevel, persistTraceLevel, state, traceLevel} import Keys.{logLevel, logManager, persistLogLevel, persistTraceLevel, state, traceLevel}

View File

@ -94,7 +94,7 @@ object BuiltinCommands
if(Project.isProjectLoaded(s)) if(Project.isProjectLoaded(s))
{ {
val e = Project.extract(s) val e = Project.extract(s)
val current = "The current project is " + Project.display(e.currentRef) + "\n" val current = "The current project is " + Reference.display(e.currentRef) + "\n"
val sc = aboutScala(s, e) val sc = aboutScala(s, e)
val built = if(sc.isEmpty) "" else "The current project is built against " + sc + "\n" val built = if(sc.isEmpty) "" else "The current project is built against " + sc + "\n"
current + built + aboutPlugins(e) current + built + aboutPlugins(e)
@ -199,7 +199,7 @@ object BuiltinCommands
s s
} }
def sessionCommand = Command.make(SessionCommand, sessionBrief, SessionSettings.Help)(SessionSettings.command) def sessionCommand = Command.make(SessionCommand, sessionBrief, SessionSettings.Help)(SessionSettings.command)
def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State = def reapply(newSession: SessionSettings, structure: BuildStructure, s: State): State =
{ {
s.log.info("Reapplying settings...") s.log.info("Reapplying settings...")
val newStructure = Load.reapply(newSession.mergeSettings, structure)( Project.showContextKey(newSession, structure) ) val newStructure = Load.reapply(newSession.mergeSettings, structure)( Project.showContextKey(newSession, structure) )
@ -215,13 +215,13 @@ object BuiltinCommands
reapply(setResult.session, structure, s) reapply(setResult.session, structure, s)
} }
// @deprecated("Use SettingCompletions.setThis", "0.13.0") // @deprecated("Use SettingCompletions.setThis", "0.13.0")
def setThis(s: State, extracted: Extracted, settings: Seq[Project.Setting[_]], arg: String) = def setThis(s: State, extracted: Extracted, settings: Seq[Def.Setting[_]], arg: String) =
SettingCompletions.setThis(s, extracted, settings, arg) SettingCompletions.setThis(s, extracted, settings, arg)
def inspect = Command(InspectCommand, inspectBrief, inspectDetailed)(inspectParser) { case (s, (option, sk)) => def inspect = Command(InspectCommand, inspectBrief, inspectDetailed)(inspectParser) { case (s, (option, sk)) =>
s.log.info(inspectOutput(s, option, sk)) s.log.info(inspectOutput(s, option, sk))
s s
} }
def inspectOutput(s: State, option: InspectOption, sk: Project.ScopedKey[_]): String = def inspectOutput(s: State, option: InspectOption, sk: Def.ScopedKey[_]): String =
{ {
val extracted = Project.extract(s) val extracted = Project.extract(s)
import extracted._ import extracted._
@ -262,7 +262,7 @@ object BuiltinCommands
import InspectOption._ import InspectOption._
def inspectParser = (s: State) => spacedInspectOptionParser(s) flatMap { def inspectParser = (s: State) => spacedInspectOptionParser(s) flatMap {
case opt @ (Uses | Definitions) => allKeyParser(s).map(key => (opt, Project.ScopedKey(Global, key))) case opt @ (Uses | Definitions) => allKeyParser(s).map(key => (opt, Def.ScopedKey(Global, key)))
case opt @ (DependencyTree | Details(_)) => spacedKeyParser(s).map(key => (opt, key)) case opt @ (DependencyTree | Details(_)) => spacedKeyParser(s).map(key => (opt, key))
} }
val spacedInspectOptionParser: (State => Parser[InspectOption]) = (s: State) => { val spacedInspectOptionParser: (State => Parser[InspectOption]) = (s: State) => {
@ -322,7 +322,7 @@ object BuiltinCommands
extracted.structure.units(curi).imports.map(s => (s, -1)) extracted.structure.units(curi).imports.map(s => (s, -1))
} }
def listBuild(uri: URI, build: Load.LoadedBuildUnit, current: Boolean, currentID: String, log: Logger) = def listBuild(uri: URI, build: LoadedBuildUnit, current: Boolean, currentID: String, log: Logger) =
{ {
log.info("In " + uri) log.info("In " + uri)
def prefix(id: String) = if(currentID != id) " " else if(current) " * " else "(*)" def prefix(id: String) = if(currentID != id) " " else if(current) " * " else "(*)"

View File

@ -33,7 +33,8 @@ object DefaultOptions {
import Opts._ import Opts._
import Path._ import Path._
import BuildPaths.{getGlobalBase, getGlobalSettingsDirectory} import BuildPaths.{getGlobalBase, getGlobalSettingsDirectory}
import Project.{Setting, extract} import Project.{extract, richInitializeTask}
import Def.Setting
def javac: Seq[String] = compile.encoding("UTF-8") def javac: Seq[String] = compile.encoding("UTF-8")
def scalac: Seq[String] = compile.encoding("UTF-8") def scalac: Seq[String] = compile.encoding("UTF-8")

View File

@ -6,7 +6,7 @@ package sbt
import java.util.regex.Pattern import java.util.regex.Pattern
import java.io.File import java.io.File
import Keys.{Streams, TaskStreams} import Keys.{Streams, TaskStreams}
import Project.ScopedKey import Def.ScopedKey
import Aggregation.{KeyValue, Values} import Aggregation.{KeyValue, Values}
import Types.idFun import Types.idFun
import Highlight.{bold, showMatches} import Highlight.{bold, showMatches}

View File

@ -1,7 +1,7 @@
package sbt package sbt
import Keys.Classpath import Keys.Classpath
import Project.Setting import Def.Setting
import PluginManagement._ import PluginManagement._
import java.net.{URL,URLClassLoader} import java.net.{URL,URLClassLoader}

View File

@ -6,10 +6,10 @@ package sbt
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import Project._ import Project._
import Keys.{appConfiguration, stateBuildStructure, commands, configuration, historyPath, projectCommand, sessionSettings, sessionVars, shellPrompt, thisProject, thisProjectRef, watch} import Keys.{appConfiguration, stateBuildStructure, commands, configuration, historyPath, projectCommand, sessionSettings, shellPrompt, thisProject, thisProjectRef, watch}
import Scope.{GlobalScope,ThisScope} import Scope.{GlobalScope,ThisScope}
import Load.BuildStructure import Def.{Flattened, Initialize, ScopedKey, Setting}
import Types.{idFun, Id} import Types.idFun
import complete.DefaultParsers import complete.DefaultParsers
sealed trait ProjectDefinition[PR <: ProjectReference] sealed trait ProjectDefinition[PR <: ProjectReference]
@ -17,7 +17,7 @@ sealed trait ProjectDefinition[PR <: ProjectReference]
def id: String def id: String
def base: File def base: File
def configurations: Seq[Configuration] def configurations: Seq[Configuration]
def settings: Seq[Project.Setting[_]] def settings: Seq[Setting[_]]
def aggregate: Seq[PR] def aggregate: Seq[PR]
@deprecated("Delegation between projects should be replaced by directly sharing settings.", "0.13.0") @deprecated("Delegation between projects should be replaced by directly sharing settings.", "0.13.0")
def delegates: Seq[PR] def delegates: Seq[PR]
@ -36,7 +36,7 @@ sealed trait ProjectDefinition[PR <: ProjectReference]
sealed trait Project extends ProjectDefinition[ProjectReference] sealed trait Project extends ProjectDefinition[ProjectReference]
{ {
def copy(id: String = id, base: File = base, aggregate: => Seq[ProjectReference] = aggregate, dependencies: => Seq[ClasspathDep[ProjectReference]] = dependencies, def copy(id: String = id, base: File = base, aggregate: => Seq[ProjectReference] = aggregate, dependencies: => Seq[ClasspathDep[ProjectReference]] = dependencies,
delegates: => Seq[ProjectReference] = delegates, settings: => Seq[Project.Setting[_]] = settings, configurations: Seq[Configuration] = configurations, delegates: => Seq[ProjectReference] = delegates, settings: => Seq[Setting[_]] = settings, configurations: Seq[Configuration] = configurations,
auto: AddSettings = auto): Project = auto: AddSettings = auto): Project =
Project(id, base, aggregate = aggregate, dependencies = dependencies, delegates = delegates, settings, configurations, auto) Project(id, base, aggregate = aggregate, dependencies = dependencies, delegates = delegates, settings, configurations, auto)
@ -61,85 +61,28 @@ sealed trait Project extends ProjectDefinition[ProjectReference]
def delegateTo(from: ProjectReference*): Project = copy(delegates = delegates ++ from) def delegateTo(from: ProjectReference*): Project = copy(delegates = delegates ++ from)
def aggregate(refs: ProjectReference*): Project = copy(aggregate = (aggregate: Seq[ProjectReference]) ++ refs) def aggregate(refs: ProjectReference*): Project = copy(aggregate = (aggregate: Seq[ProjectReference]) ++ refs)
def configs(cs: Configuration*): Project = copy(configurations = configurations ++ cs) def configs(cs: Configuration*): Project = copy(configurations = configurations ++ cs)
def settings(ss: Project.Setting[_]*): Project = copy(settings = (settings: Seq[Project.Setting[_]]) ++ ss) def settings(ss: Setting[_]*): Project = copy(settings = (settings: Seq[Setting[_]]) ++ ss)
def autoSettings(select: AddSettings*): Project = copy(auto = AddSettings.seq(select : _*)) def autoSettings(select: AddSettings*): Project = copy(auto = AddSettings.seq(select : _*))
} }
sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] sealed trait ResolvedProject extends ProjectDefinition[ProjectRef]
final case class Extracted(structure: BuildStructure, session: SessionSettings, currentRef: ProjectRef)(implicit val showKey: Show[ScopedKey[_]])
{
def rootProject = structure.rootProject
lazy val currentUnit = structure units currentRef.build
lazy val currentProject = currentUnit defined currentRef.project
lazy val currentLoader: ClassLoader = currentUnit.loader
def get[T](key: TaskKey[T]): Task[T] = get(key.task)
def get[T](key: SettingKey[T]) = getOrError(inCurrent(key), key.key)
def getOpt[T](key: SettingKey[T]): Option[T] = structure.data.get(inCurrent(key), key.key)
private[this] def inCurrent[T](key: SettingKey[T]): Scope = if(key.scope.project == This) key.scope.copy(project = Select(currentRef)) else key.scope
@deprecated("This method does not apply state changes requested during task execution. Use 'runTask' instead, which does.", "0.11.1")
def evalTask[T](key: TaskKey[T], state: State): T = runTask(key, state)._2
def runTask[T](key: TaskKey[T], state: State): (State, T) =
{
import EvaluateTask._
val rkey = resolve(key.scopedKey)
val config = extractedConfig(this, structure)
val value: Option[(State, Result[T])] = apply(structure, key.task.scopedKey, state, currentRef, config)
val (newS, result) = getOrError(rkey.scope, rkey.key, value)
(newS, processResult(result, newS.log))
}
def runAggregated[T](key: TaskKey[T], state: State): State =
{
val rkey = resolve(key.scopedKey)
val keys = Aggregation.aggregate(rkey, ScopeMask(), structure.extra)
val tasks = Act.keyValues(structure)(keys)
Aggregation.runTasks(state, structure, tasks, Aggregation.Dummies(KNil, HNil), show = false )(showKey)
}
private[this] def resolve[T](key: ScopedKey[T]): ScopedKey[T] =
Project.mapScope(Scope.resolveScope(GlobalScope, currentRef.build, rootProject) )( key.scopedKey )
private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T])(implicit display: Show[ScopedKey[_]]): T =
value getOrElse error(display(ScopedKey(scope, key)) + " is undefined.")
private def getOrError[T](scope: Scope, key: AttributeKey[T])(implicit display: Show[ScopedKey[_]]): T =
structure.data.get(scope, key) getOrElse error(display(ScopedKey(scope, key)) + " is undefined.")
def append(settings: Seq[Setting[_]], state: State): State =
{
val appendSettings = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)
val newStructure = Load.reapply(session.original ++ appendSettings, structure)
Project.setProject(session, newStructure, state)
}
}
sealed trait ClasspathDep[PR <: ProjectReference] { def project: PR; def configuration: Option[String] } sealed trait ClasspathDep[PR <: ProjectReference] { def project: PR; def configuration: Option[String] }
final case class ResolvedClasspathDependency(project: ProjectRef, configuration: Option[String]) extends ClasspathDep[ProjectRef] final case class ResolvedClasspathDependency(project: ProjectRef, configuration: Option[String]) extends ClasspathDep[ProjectRef]
final case class ClasspathDependency(project: ProjectReference, configuration: Option[String]) extends ClasspathDep[ProjectReference] final case class ClasspathDependency(project: ProjectReference, configuration: Option[String]) extends ClasspathDep[ProjectReference]
object Project extends Init[Scope] with ProjectExtra object Project extends ProjectExtra
{ {
lazy val showFullKey: Show[ScopedKey[_]] = showFullKey(None)
def showFullKey(keyNameColor: Option[String]): Show[ScopedKey[_]] =
new Show[ScopedKey[_]] { def apply(key: ScopedKey[_]) = displayFull(key, keyNameColor) }
def showContextKey(state: State): Show[ScopedKey[_]] = def showContextKey(state: State): Show[ScopedKey[_]] =
showContextKey(state, None) showContextKey(state, None)
def showContextKey(state: State, keyNameColor: Option[String]): Show[ScopedKey[_]] = def showContextKey(state: State, keyNameColor: Option[String]): Show[ScopedKey[_]] =
if(isProjectLoaded(state)) showContextKey( session(state), structure(state), keyNameColor ) else showFullKey if(isProjectLoaded(state)) showContextKey( session(state), structure(state), keyNameColor ) else Def.showFullKey
def showContextKey(session: SessionSettings, structure: BuildStructure, keyNameColor: Option[String] = None): Show[ScopedKey[_]] = def showContextKey(session: SessionSettings, structure: BuildStructure, keyNameColor: Option[String] = None): Show[ScopedKey[_]] =
showRelativeKey(session.current, structure.allProjects.size > 1, keyNameColor) Def.showRelativeKey(session.current, structure.allProjects.size > 1, keyNameColor)
def showLoadingKey(loaded: Load.LoadedBuild, keyNameColor: Option[String] = None): Show[ScopedKey[_]] = def showLoadingKey(loaded: LoadedBuild, keyNameColor: Option[String] = None): Show[ScopedKey[_]] =
showRelativeKey( ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head), loaded.allProjectRefs.size > 1, keyNameColor) Def.showRelativeKey( ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head), loaded.allProjectRefs.size > 1, keyNameColor)
def showRelativeKey(current: ProjectRef, multi: Boolean, keyNameColor: Option[String] = None): Show[ScopedKey[_]] = new Show[ScopedKey[_]] {
def apply(key: ScopedKey[_]) =
Scope.display(key.scope, colored(key.key.label, keyNameColor), ref => displayRelative(current, multi, ref))
}
def displayRelative(current: ProjectRef, multi: Boolean, project: Reference): String = project match {
case BuildRef(current.build) => "{.}/"
case `current` => if(multi) current.project + "/" else ""
case ProjectRef(current.build, x) => x + "/"
case _ => display(project) + "/"
}
private abstract class ProjectDef[PR <: ProjectReference](val id: String, val base: File, aggregate0: => Seq[PR], dependencies0: => Seq[ClasspathDep[PR]], private abstract class ProjectDef[PR <: ProjectReference](val id: String, val base: File, aggregate0: => Seq[PR], dependencies0: => Seq[ClasspathDep[PR]],
delegates0: => Seq[PR], settings0: => Seq[Setting[_]], val configurations: Seq[Configuration], val auto: AddSettings) extends ProjectDefinition[PR] delegates0: => Seq[PR], settings0: => Seq[Setting[_]], val configurations: Seq[Configuration], val auto: AddSettings) extends ProjectDefinition[PR]
@ -183,8 +126,8 @@ object Project extends Init[Scope] with ProjectExtra
def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] = def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] =
ref match { case pr: ProjectRef => getProject(pr, structure); case _ => None } ref match { case pr: ProjectRef => getProject(pr, structure); case _ => None }
def getProject(ref: ProjectRef, structure: BuildStructure): Option[ResolvedProject] = getProject(ref, structure.units) def getProject(ref: ProjectRef, structure: BuildStructure): Option[ResolvedProject] = getProject(ref, structure.units)
def getProject(ref: ProjectRef, structure: Load.LoadedBuild): Option[ResolvedProject] = getProject(ref, structure.units) def getProject(ref: ProjectRef, structure: LoadedBuild): Option[ResolvedProject] = getProject(ref, structure.units)
def getProject(ref: ProjectRef, units: Map[URI, Load.LoadedBuildUnit]): Option[ResolvedProject] = def getProject(ref: ProjectRef, units: Map[URI, LoadedBuildUnit]): Option[ResolvedProject] =
(units get ref.build).flatMap(_.defined get ref.project) (units get ref.build).flatMap(_.defined get ref.project)
def runUnloadHooks(s: State): State = def runUnloadHooks(s: State): State =
@ -227,40 +170,11 @@ object Project extends Init[Scope] with ProjectExtra
def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap = def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap =
vopt match { case Some(v) => attributes.put(key, v); case None => attributes.remove(key) } vopt match { case Some(v) => attributes.put(key, v); case None => attributes.remove(key) }
def makeSettings(settings: Seq[Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]])(implicit display: Show[ScopedKey[_]]) = def makeSettings(settings: Seq[Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]])(implicit display: Show[ScopedKey[_]]) =
make(settings)(delegates, scopeLocal, display) Def.make(settings)(delegates, scopeLocal, display)
def equal(a: ScopedKey[_], b: ScopedKey[_], mask: ScopeMask): Boolean = def equal(a: ScopedKey[_], b: ScopedKey[_], mask: ScopeMask): Boolean =
a.key == b.key && Scope.equal(a.scope, b.scope, mask) a.key == b.key && Scope.equal(a.scope, b.scope, mask)
def colored(s: String, color: Option[String]): String = color match {
case Some(c) => c + s + scala.Console.RESET
case None => s
}
def displayFull(scoped: ScopedKey[_]): String = displayFull(scoped, None)
def displayFull(scoped: ScopedKey[_], keyNameColor: Option[String]): String = Scope.display(scoped.scope, colored(scoped.key.label, keyNameColor))
def displayMasked(scoped: ScopedKey[_], mask: ScopeMask): String = Scope.displayMasked(scoped.scope, scoped.key.label, mask)
def display(ref: Reference): String =
ref match
{
case pr: ProjectReference => display(pr)
case br: BuildReference => display(br)
}
def display(ref: BuildReference) =
ref match
{
case ThisBuild => "{<this>}"
case BuildRef(uri) => "{" + uri + "}"
}
def display(ref: ProjectReference) =
ref match
{
case ThisProject => "{<this>}<this>"
case LocalRootProject => "{<this>}<root>"
case LocalProject(id) => "{<this>}" + id
case RootProject(uri) => "{" + uri + " }<root>"
case ProjectRef(uri, id) => "{" + uri + "}" + id
}
def fillTaskAxis(scoped: ScopedKey[_]): ScopedKey[_] = def fillTaskAxis(scoped: ScopedKey[_]): ScopedKey[_] =
ScopedKey(Scope.fillTaskAxis(scoped.scope, scoped.key), scoped.key) ScopedKey(Scope.fillTaskAxis(scoped.scope, scoped.key), scoped.key)
@ -294,7 +208,7 @@ object Project extends Init[Scope] with ProjectExtra
case Some(sc) => "Provided by:\n\t" + Scope.display(sc, key.label) + "\n" case Some(sc) => "Provided by:\n\t" + Scope.display(sc, key.label) + "\n"
case None => "" case None => ""
} }
val comp = compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display) val comp = Def.compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display)
val definedAt = comp get scoped map { c => val definedAt = comp get scoped map { c =>
def fmt(s: Setting[_]) = s.pos match { def fmt(s: Setting[_]) = s.pos match {
case pos: FilePosition => Some(pos.path + ":" + pos.startLine) case pos: FilePosition => Some(pos.path + ":" + pos.startLine)
@ -309,7 +223,7 @@ object Project extends Init[Scope] with ProjectExtra
} getOrElse "" } getOrElse ""
val cMap = flattenLocals(comp) val cMap = Def.flattenLocals(comp)
val related = cMap.keys.filter(k => k.key == key && k.scope != scope) val related = cMap.keys.filter(k => k.key == key && k.scope != scope)
val depends = cMap.get(scoped) match { case Some(c) => c.dependencies.toSet; case None => Set.empty } val depends = cMap.get(scoped) match { case Some(c) => c.dependencies.toSet; case None => Set.empty }
@ -343,7 +257,7 @@ object Project extends Init[Scope] with ProjectExtra
def relation(structure: BuildStructure, actual: Boolean)(implicit display: Show[ScopedKey[_]]) = def relation(structure: BuildStructure, actual: Boolean)(implicit display: Show[ScopedKey[_]]) =
{ {
type Rel = Relation[ScopedKey[_], ScopedKey[_]] type Rel = Relation[ScopedKey[_], ScopedKey[_]]
val cMap = flattenLocals(compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display)) val cMap = Def.flattenLocals(Def.compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display))
((Relation.empty: Rel) /: cMap) { case (r, (key, value)) => ((Relation.empty: Rel) /: cMap) { case (r, (key, value)) =>
r + (key, value.dependencies) r + (key, value.dependencies)
} }
@ -412,26 +326,25 @@ object Project extends Init[Scope] with ProjectExtra
val extracted = Project.extract(state) val extracted = Project.extract(state)
EvaluateTask(extracted.structure, taskKey, state, extracted.currentRef, config) EvaluateTask(extracted.structure, taskKey, state, extracted.currentRef, config)
} }
// this is here instead of Scoped so that it is considered without need for import (because of Project.Initialize)
implicit def richInitializeTask[T](init: Initialize[Task[T]]): Scoped.RichInitializeTask[T] = new Scoped.RichInitializeTask(init)
implicit def richInitializeInputTask[T](init: Initialize[InputTask[T]]): Scoped.RichInitializeInputTask[T] = new Scoped.RichInitializeInputTask(init)
implicit def richInitialize[T](i: Initialize[T]): Scoped.RichInitialize[T] = new Scoped.RichInitialize[T](i)
}
final case class ScopedKeyData[A](scoped: ScopedKey[A], value: Any) /** Many methods were moved to Def in 0.13. This implicit makes those methods still available on Project for the transition. */
{ @inline
import Types.const @deprecated("Use Def directly", "0.13.0")
val key = scoped.key implicit def projectToDef(p: Project.type): Def.type = Def
val scope = scoped.scope
def typeName: String = fold(fmtMf("Task[%s]"), fmtMf("InputTask[%s]"), key.manifest.toString) implicit def projectToRef(p: Project): ProjectReference = LocalProject(p.id)
def settingValue: Option[Any] = fold(const(None), const(None), Some(value))
def description: String = fold(fmtMf("Task: %s"), fmtMf("Input task: %s"), final class RichTaskSessionVar[S](i: Initialize[Task[S]])
"Setting: %s = %s" format (key.manifest.toString, value.toString)) {
def fold[A](targ: OptManifest[_] => A, itarg: OptManifest[_] => A, s: => A): A = import SessionVar.{persistAndSet, resolveContext, set, transform => tx}
if (key.manifest.erasure == classOf[Task[_]]) targ(key.manifest.typeArguments.head)
else if (key.manifest.erasure == classOf[InputTask[_]]) itarg(key.manifest.typeArguments.head) def updateState(f: (State, S) => State): Initialize[Task[S]] = i(t => tx(t, f))
else s def storeAs(key: TaskKey[S])(implicit f: sbinary.Format[S]): Initialize[Task[S]] = (Keys.resolvedScoped, i) { (scoped, task) =>
def fmtMf(s: String): OptManifest[_] => String = s format _ tx(task, (state, value) => persistAndSet( resolveContext(key, scoped.scope, state), state, value)(f))
}
def keepAs(key: TaskKey[S]): Initialize[Task[S]] =
(i, Keys.resolvedScoped)( (t,scoped) => tx(t, (state,value) => set(resolveContext(key, scoped.scope, state), state, value) ) )
}
} }
trait ProjectExtra trait ProjectExtra
@ -439,6 +352,14 @@ trait ProjectExtra
implicit def configDependencyConstructor[T <% ProjectReference](p: T): Constructor = new Constructor(p) implicit def configDependencyConstructor[T <% ProjectReference](p: T): Constructor = new Constructor(p)
implicit def classpathDependency[T <% ProjectReference](p: T): ClasspathDependency = new ClasspathDependency(p, None) implicit def classpathDependency[T <% ProjectReference](p: T): ClasspathDependency = new ClasspathDependency(p, None)
// These used to be in Project so that they didn't need to get imported (due to Initialize being nested in Project).
// Moving Initialize and other settings types to Def and decoupling Project, Def, and Structure means these go here for now
implicit def richInitializeTask[T](init: Initialize[Task[T]]): Scoped.RichInitializeTask[T] = new Scoped.RichInitializeTask(init)
implicit def richInitializeInputTask[T](init: Initialize[InputTask[T]]): Scoped.RichInitializeInputTask[T] = new Scoped.RichInitializeInputTask(init)
implicit def richInitialize[T](i: Initialize[T]): Scoped.RichInitialize[T] = new Scoped.RichInitialize[T](i)
implicit def richTaskSessionVar[T](init: Initialize[Task[T]]): Project.RichTaskSessionVar[T] = new Project.RichTaskSessionVar(init)
def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] = def inConfig(conf: Configuration)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
inScope(ThisScope.copy(config = Select(conf)) )( (configuration :== conf) +: ss) inScope(ThisScope.copy(config = Select(conf)) )( (configuration :== conf) +: ss)
def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] = def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
@ -446,69 +367,3 @@ trait ProjectExtra
def inScope(scope: Scope)(ss: Seq[Setting[_]]): Seq[Setting[_]] = def inScope(scope: Scope)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
Project.transform(Scope.replaceThis(scope), ss) Project.transform(Scope.replaceThis(scope), ss)
} }
import sbinary.{Format, Operations}
object SessionVar
{
val DefaultDataID = "data"
// these are required because of inference+manifest limitations
final case class Key[T](key: ScopedKey[Task[T]])
final case class Map(map: IMap[Key, Id]) {
def get[T](k: ScopedKey[Task[T]]): Option[T] = map get Key(k)
def put[T](k: ScopedKey[Task[T]], v: T): Map = Map(map put (Key(k), v))
}
def emptyMap = Map(IMap.empty)
def persistAndSet[T](key: ScopedKey[Task[T]], state: State, value: T)(implicit f: sbinary.Format[T]): State =
{
persist(key, state, value)(f)
set(key, state, value)
}
def persist[T](key: ScopedKey[Task[T]], state: State, value: T)(implicit f: sbinary.Format[T]): Unit =
Project.structure(state).streams(state).use(key)( s =>
Operations.write(s.binary(DefaultDataID), value)(f)
)
def clear(s: State): State = s.put(sessionVars, SessionVar.emptyMap)
def get[T](key: ScopedKey[Task[T]], state: State): Option[T] = orEmpty(state get sessionVars) get key
def set[T](key: ScopedKey[Task[T]], state: State, value: T): State = state.update(sessionVars)(om => orEmpty(om) put (key, value))
def orEmpty(opt: Option[Map]) = opt getOrElse emptyMap
def transform[S](task: Task[S], f: (State, S) => State): Task[S] =
{
val g = (s: S, map: AttributeMap) => map.put(Keys.transformState, (state: State) => f(state, s))
task.copy(info = task.info.postTransform(g))
}
def resolveContext[T](key: ScopedKey[Task[T]], context: Scope, state: State): ScopedKey[Task[T]] =
{
val subScope = Scope.replaceThis(context)(key.scope)
val scope = Project.structure(state).data.definingScope(subScope, key.key) getOrElse subScope
ScopedKey(scope, key.key)
}
def read[T](key: ScopedKey[Task[T]], state: State)(implicit f: Format[T]): Option[T] =
Project.structure(state).streams(state).use(key) { s =>
try { Some(Operations.read(s.readBinary(key, DefaultDataID))) }
catch { case e: Exception => None }
}
def load[T](key: ScopedKey[Task[T]], state: State)(implicit f: Format[T]): Option[T] =
get(key, state) orElse read(key, state)(f)
def loadAndSet[T](key: ScopedKey[Task[T]], state: State, setIfUnset: Boolean = true)(implicit f: Format[T]): (State, Option[T]) =
get(key, state) match {
case s: Some[T] => (state, s)
case None => read(key, state)(f) match {
case s @ Some(t) =>
val newState = if(setIfUnset && get(key, state).isDefined) state else set(key, state, t)
(newState, s)
case None => (state, None)
}
}
}

37
main/RetrieveUnit.scala Normal file
View File

@ -0,0 +1,37 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import java.io.File
import java.net.URI
import BuildLoader.ResolveInfo
import Def.{ScopedKey, Setting}
object RetrieveUnit
{
def apply(info: ResolveInfo): Option[() => File] =
{
info.uri match {
case Scheme("svn") | Scheme("svn+ssh") => Resolvers.subversion(info)
case Scheme("hg") => Resolvers.mercurial(info)
case Scheme("git") => Resolvers.git(info)
case Path(path) if path.endsWith(".git") => Resolvers.git(info)
case Scheme("http") | Scheme("https") | Scheme("ftp") => Resolvers.remote(info)
case Scheme("file") => Resolvers.local(info)
case _ => None
}
}
object Scheme
{
def unapply(uri: URI) = Option(uri.getScheme)
}
object Path
{
import RichURI.fromURI
def unapply(uri: URI) = Option(uri.withoutMarkerScheme.getPath)
}
}

19
main/ScopedKeyData.scala Normal file
View File

@ -0,0 +1,19 @@
package sbt
import Def.ScopedKey
final case class ScopedKeyData[A](scoped: ScopedKey[A], value: Any)
{
import Types.const
val key = scoped.key
val scope = scoped.scope
def typeName: String = fold(fmtMf("Task[%s]"), fmtMf("InputTask[%s]"), key.manifest.toString)
def settingValue: Option[Any] = fold(const(None), const(None), Some(value))
def description: String = fold(fmtMf("Task: %s"), fmtMf("Input task: %s"),
"Setting: %s = %s" format (key.manifest.toString, value.toString))
def fold[A](targ: OptManifest[_] => A, itarg: OptManifest[_] => A, s: => A): A =
if (key.manifest.erasure == classOf[Task[_]]) targ(key.manifest.typeArguments.head)
else if (key.manifest.erasure == classOf[InputTask[_]]) itarg(key.manifest.typeArguments.head)
else s
def fmtMf(s: String): OptManifest[_] => String = s format _
}

View File

@ -5,6 +5,7 @@ package sbt
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import Def.{ScopedKey,Setting}
import Project._ import Project._
import Types.Endo import Types.Endo
import compiler.Eval import compiler.Eval
@ -89,7 +90,7 @@ object SessionSettings
val newSession = session.copy(append = newAppend.toMap, original = newOriginal.flatten.toSeq) val newSession = session.copy(append = newAppend.toMap, original = newOriginal.flatten.toSeq)
reapply(newSession.copy(original = newSession.mergeSettings, append = Map.empty), s) reapply(newSession.copy(original = newSession.mergeSettings, append = Map.empty), s)
} }
def writeSettings(pref: ProjectRef, settings: List[SessionSetting], original: Seq[Setting[_]], structure: Load.BuildStructure): (Seq[SessionSetting], Seq[Setting[_]]) = def writeSettings(pref: ProjectRef, settings: List[SessionSetting], original: Seq[Setting[_]], structure: BuildStructure): (Seq[SessionSetting], Seq[Setting[_]]) =
{ {
val project = Project.getProject(pref, structure).getOrElse(error("Invalid project reference " + pref)) val project = Project.getProject(pref, structure).getOrElse(error("Invalid project reference " + pref))
val writeTo: File = BuildPaths.configurationSources(project.base).headOption.getOrElse(new File(project.base, "build.sbt")) val writeTo: File = BuildPaths.configurationSources(project.base).headOption.getOrElse(new File(project.base, "build.sbt"))
@ -140,7 +141,7 @@ object SessionSettings
def printAllSettings(s: State): State = def printAllSettings(s: State): State =
withSettings(s){ session => withSettings(s){ session =>
for( (ref, settings) <- session.append if !settings.isEmpty) { for( (ref, settings) <- session.append if !settings.isEmpty) {
println("In " + Project.display(ref)) println("In " + Reference.display(ref))
printSettings(settings) printSettings(settings)
} }
s s

71
main/SessionVar.scala Normal file
View File

@ -0,0 +1,71 @@
package sbt
import Def.ScopedKey
import Types.Id
import Keys.sessionVars
import sbinary.{Format, Operations}
object SessionVar
{
val DefaultDataID = "data"
// these are required because of inference+manifest limitations
final case class Key[T](key: ScopedKey[Task[T]])
final case class Map(map: IMap[Key, Id]) {
def get[T](k: ScopedKey[Task[T]]): Option[T] = map get Key(k)
def put[T](k: ScopedKey[Task[T]], v: T): Map = Map(map put (Key(k), v))
}
def emptyMap = Map(IMap.empty)
def persistAndSet[T](key: ScopedKey[Task[T]], state: State, value: T)(implicit f: sbinary.Format[T]): State =
{
persist(key, state, value)(f)
set(key, state, value)
}
def persist[T](key: ScopedKey[Task[T]], state: State, value: T)(implicit f: sbinary.Format[T]): Unit =
Project.structure(state).streams(state).use(key)( s =>
Operations.write(s.binary(DefaultDataID), value)(f)
)
def clear(s: State): State = s.put(sessionVars, SessionVar.emptyMap)
def get[T](key: ScopedKey[Task[T]], state: State): Option[T] = orEmpty(state get sessionVars) get key
def set[T](key: ScopedKey[Task[T]], state: State, value: T): State = state.update(sessionVars)(om => orEmpty(om) put (key, value))
def orEmpty(opt: Option[Map]) = opt getOrElse emptyMap
def transform[S](task: Task[S], f: (State, S) => State): Task[S] =
{
val g = (s: S, map: AttributeMap) => map.put(Keys.transformState, (state: State) => f(state, s))
task.copy(info = task.info.postTransform(g))
}
def resolveContext[T](key: ScopedKey[Task[T]], context: Scope, state: State): ScopedKey[Task[T]] =
{
val subScope = Scope.replaceThis(context)(key.scope)
val scope = Project.structure(state).data.definingScope(subScope, key.key) getOrElse subScope
ScopedKey(scope, key.key)
}
def read[T](key: ScopedKey[Task[T]], state: State)(implicit f: Format[T]): Option[T] =
Project.structure(state).streams(state).use(key) { s =>
try { Some(Operations.read(s.readBinary(key, DefaultDataID))) }
catch { case e: Exception => None }
}
def load[T](key: ScopedKey[Task[T]], state: State)(implicit f: Format[T]): Option[T] =
get(key, state) orElse read(key, state)(f)
def loadAndSet[T](key: ScopedKey[Task[T]], state: State, setIfUnset: Boolean = true)(implicit f: Format[T]): (State, Option[T]) =
get(key, state) match {
case s: Some[T] => (state, s)
case None => read(key, state)(f) match {
case s @ Some(t) =>
val newState = if(setIfUnset && get(key, state).isDefined) state else set(key, state, t)
(newState, s)
case None => (state, None)
}
}
}

View File

@ -3,8 +3,8 @@ package sbt
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import Project._ import Project._
import Def.{ScopedKey, Setting}
import Scope.{GlobalScope,ThisScope} import Scope.{GlobalScope,ThisScope}
import Load.BuildStructure
import Types.{const, idFun, Id} import Types.{const, idFun, Id}
import complete._ import complete._
import DefaultParsers._ import DefaultParsers._
@ -31,7 +31,7 @@ private[sbt] object SettingCompletions
{ {
val akey = setting.key.key val akey = setting.key.key
val global = ScopedKey(Global, akey) val global = ScopedKey(Global, akey)
val globalSetting = resolve( Project.setting(global, setting.init, setting.pos) ) val globalSetting = resolve( Def.setting(global, setting.init, setting.pos) )
globalSetting ++ allDefs.flatMap { d => globalSetting ++ allDefs.flatMap { d =>
if(d.key == akey) if(d.key == akey)
Seq( SettingKey(akey) in d.scope <<= global) Seq( SettingKey(akey) in d.scope <<= global)
@ -45,7 +45,7 @@ private[sbt] object SettingCompletions
} }
/** Implementation of the `set` command that will reload the current project with `settings` appended to the current settings. */ /** Implementation of the `set` command that will reload the current project with `settings` appended to the current settings. */
def setThis(s: State, extracted: Extracted, settings: Seq[Project.Setting[_]], arg: String): SetResult = def setThis(s: State, extracted: Extracted, settings: Seq[Def.Setting[_]], arg: String): SetResult =
{ {
import extracted._ import extracted._
val append = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings) val append = Load.transformSettings(Load.projectScope(currentRef), currentRef.build, rootProject, settings)

View File

@ -5,8 +5,7 @@ package sbt
import java.net.URI import java.net.URI
import java.io.File import java.io.File
import Project.{ScopedKey, flattenLocals, compiled} import Def.{compiled,flattenLocals,ScopedKey}
import Load.BuildStructure
import Predef.{any2stringadd => _, _} import Predef.{any2stringadd => _, _}
object SettingGraph object SettingGraph

View File

@ -1,52 +0,0 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import Load.BuildStructure
import Project.{Initialize, ScopedKey}
import Keys.{resolvedScoped, streams, TaskStreams}
import std.TaskExtra._
import Types.{:+:, idFun}
import sbinary.{Format, Operations}
@deprecated("Superseded by task state system.", "0.11.1")
object TaskData
{
val DefaultDataID = "data"
def apply[I,O](readFrom: Scoped, id: String = DefaultDataID)(f: (State, I) => O)(default: => I)(implicit fmt: Format[I]): Initialize[State => O] =
resolvedScoped { resolved =>
s => f(s, readData(Project structure s, resolved, readFrom.key, id) getOrElse default)
}
def readData[T](structure: BuildStructure, reader: ScopedKey[_], readFrom: AttributeKey[_], id: String)(implicit f: Format[T]): Option[T] =
try {
dataStreams(structure, reader, readFrom) { (ts,key) =>
Operations.read( ts.readBinary(key, id) )(f)
}
} catch { case e: Exception => None }
def dataStreams[T](structure: BuildStructure, reader: ScopedKey[_], readFrom: AttributeKey[_])(f: (TaskStreams, ScopedKey[_]) => T): Option[T] =
structure.data.definingScope(reader.scope, readFrom) map { defined =>
val key = ScopedKey(Scope.fillTaskAxis(defined, readFrom), readFrom)
structure.streams(fakeState(structure)).use(reader)(ts => f(ts, key))
}
def write[T](i: Initialize[Task[T]], id: String = DefaultDataID)(implicit f: Format[T]): Initialize[Task[T]] = writeRelated(i, id)(idFun[T])(f)
def writeRelated[T, S](i: Initialize[Task[T]], id: String = DefaultDataID)(convert: T => S)(implicit f: Format[S]): Initialize[Task[T]] =
(streams zipWith i) { (sTask, iTask) =>
(sTask,iTask) map { case s :+: value :+: HNil =>
Operations.write( s.binary(id), convert(value) )(f)
value
}
}
// exists to keep the method signatures the same (since this object is potentially used but deprecated),
// but allow the BuildStructure Streams to be constructed from State, which isn't actually needed here
private[this] def fakeState(structure: BuildStructure): State =
{
val config = Keys.appConfiguration in Scope.GlobalScope get structure.data
State(config.get, Nil, Set.empty, None, Nil, State.newHistory, AttributeMap.empty, StandardMain.initialGlobalLogging, State.Continue)
}
}

View File

@ -1,11 +1,11 @@
package sbt package sbt
import java.io.File import java.io.File
import Keys.Classpath import Def.Classpath
import scala.annotation.implicitNotFound import scala.annotation.implicitNotFound
object Append object Append
{ {
@implicitNotFound(msg = "No implicit for Append.Value[${A}, ${B}] found,\n so ${B} cannot be appended to ${A}") @implicitNotFound(msg = "No implicit for Append.Value[${A}, ${B}] found,\n so ${B} cannot be appended to ${A}")
sealed trait Value[A,B] sealed trait Value[A,B]
{ {

View File

@ -0,0 +1,7 @@
package sbt
final case class ConfigKey(name: String)
object ConfigKey
{
implicit def configurationToKey(c: Configuration): ConfigKey = ConfigKey(c.name)
}

37
main/settings/Def.scala Normal file
View File

@ -0,0 +1,37 @@
package sbt
import java.io.File
object Def extends Init[Scope]
{
type Classpath = Seq[Attributed[File]]
val triggeredBy = AttributeKey[Seq[Task[_]]]("triggered-by")
val runBefore = AttributeKey[Seq[Task[_]]]("run-before")
private[sbt] val parseResult: TaskKey[Any] = TaskKey("$parse-result", "Internal: used to implement input tasks.", KeyRanks.Invisible)
// TODO: move back to Keys
val resolvedScoped = SettingKey[ScopedKey[_]]("resolved-scoped", "The ScopedKey for the referencing setting or task.", KeyRanks.DSetting)
lazy val showFullKey: Show[ScopedKey[_]] = showFullKey(None)
def showFullKey(keyNameColor: Option[String]): Show[ScopedKey[_]] =
new Show[ScopedKey[_]] { def apply(key: ScopedKey[_]) = displayFull(key, keyNameColor) }
def showRelativeKey(current: ProjectRef, multi: Boolean, keyNameColor: Option[String] = None): Show[ScopedKey[_]] = new Show[ScopedKey[_]] {
def apply(key: ScopedKey[_]) =
Scope.display(key.scope, colored(key.key.label, keyNameColor), ref => displayRelative(current, multi, ref))
}
def displayRelative(current: ProjectRef, multi: Boolean, project: Reference): String = project match {
case BuildRef(current.build) => "{.}/"
case `current` => if(multi) current.project + "/" else ""
case ProjectRef(current.build, 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, colored(scoped.key.label, keyNameColor))
def displayMasked(scoped: ScopedKey[_], mask: ScopeMask): String = Scope.displayMasked(scoped.scope, scoped.key.label, mask)
def colored(s: String, color: Option[String]): String = color match {
case Some(c) => c + s + scala.Console.RESET
case None => s
}
}

View File

@ -0,0 +1,19 @@
package sbt
sealed trait DelegateIndex
{
def project(ref: ProjectRef): Seq[ScopeAxis[ResolvedReference]]
def config(ref: ProjectRef, conf: ConfigKey): Seq[ScopeAxis[ConfigKey]]
// def task(ref: ProjectRef, task: ScopedKey[_]): Seq[ScopeAxis[ScopedKey[_]]]
// def extra(ref: ProjectRef, e: AttributeMap): Seq[ScopeAxis[AttributeMap]]
}
private final class DelegateIndex0(refs: Map[ProjectRef, ProjectDelegates]) extends DelegateIndex
{
def project(ref: ProjectRef): Seq[ScopeAxis[ResolvedReference]] = refs.get(ref) match { case Some(pd) => pd.refs; case None => Nil }
def config(ref: ProjectRef, conf: ConfigKey): Seq[ScopeAxis[ConfigKey]] =
refs.get(ref) match {
case Some(pd) => pd.confs.get(conf) match { case Some(cs) => cs; case None => Select(conf) :: Global :: Nil }
case None => Select(conf) :: Global :: Nil
}
}
private final class ProjectDelegates(val ref: ProjectRef, val refs: Seq[ScopeAxis[ResolvedReference]], val confs: Map[ConfigKey, Seq[ScopeAxis[ConfigKey]]])

View File

@ -0,0 +1,45 @@
package sbt
object KeyRanks
{
// task and setting ranks, used to prioritize displaying information
// main tasks
final val APlusTask = 4
final val ATask = 5
final val AMinusTask = 6
// main settings
final val APlusSetting = 9
final val ASetting = 10
final val AMinusSetting = 11
// less major tasks or tasks that print useful information
final val BPlusTask = 29
final val BTask = 30
final val BMinusTask = 31
// secondary settings
final val BPlusSetting = 39
final val BSetting = 40
final val BMinusSetting = 41
// advanced settings
final val CSetting = 100
// advanced tasks
final val CTask = 200
// explicit settings
final val DSetting = 10000
// explicit tasks
final val DTask = 20000
final val MainTaskCutoff = AMinusTask
final val MainSettingCutoff = AMinusSetting
final val MainCutoff = math.max(AMinusTask, AMinusSetting)
final val DefaultTaskRank = (ATask + BTask)/2
final val DefaultInputRank = ATask // input tasks are likely a main task
final val DefaultSettingRank = (ASetting + BSetting) / 2
// implementation details
val Invisible = Int.MaxValue
}

View File

@ -64,6 +64,29 @@ object Reference
} }
} }
def display(ref: Reference): String =
ref match
{
case pr: ProjectReference => display(pr)
case br: BuildReference => display(br)
}
def display(ref: BuildReference): String =
ref match
{
case ThisBuild => "{<this>}"
case BuildRef(uri) => "{" + uri + "}"
}
def display(ref: ProjectReference): String =
ref match
{
case ThisProject => "{<this>}<this>"
case LocalRootProject => "{<this>}<root>"
case LocalProject(id) => "{<this>}" + id
case RootProject(uri) => "{" + uri + " }<root>"
case ProjectRef(uri, id) => "{" + uri + "}" + id
}
def buildURI(ref: ResolvedReference): URI = ref match { def buildURI(ref: ResolvedReference): URI = ref match {
case BuildRef(b) => b case BuildRef(b) => b
case ProjectRef(b, _) => b case ProjectRef(b, _) => b
@ -78,5 +101,4 @@ object Reference
implicit def uriToRef(u: URI): ProjectReference = RootProject(u) implicit def uriToRef(u: URI): ProjectReference = RootProject(u)
implicit def fileToRef(f: File): ProjectReference = RootProject(f) implicit def fileToRef(f: File): ProjectReference = RootProject(f)
implicit def stringToReference(s: String): ProjectReference = LocalProject(s) implicit def stringToReference(s: String): ProjectReference = LocalProject(s)
implicit def projectToRef(p: Project): ProjectReference = LocalProject(p.id)
} }

View File

@ -5,7 +5,6 @@ package sbt
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import Types.some
final case class Scope(project: ScopeAxis[Reference], config: ScopeAxis[ConfigKey], task: ScopeAxis[AttributeKey[_]], extra: ScopeAxis[AttributeMap]) final case class Scope(project: ScopeAxis[Reference], config: ScopeAxis[ConfigKey], task: ScopeAxis[AttributeKey[_]], extra: ScopeAxis[AttributeMap])
{ {
@ -121,7 +120,7 @@ object Scope
(!mask.extra || a.extra == b.extra) (!mask.extra || a.extra == b.extra)
def projectPrefix(project: ScopeAxis[Reference], show: Reference => String = showProject): String = project.foldStrict(show, "*/", "./") def projectPrefix(project: ScopeAxis[Reference], show: Reference => String = showProject): String = project.foldStrict(show, "*/", "./")
def showProject = (ref: Reference) => Project.display(ref) + "/" def showProject = (ref: Reference) => Reference.display(ref) + "/"
def parseScopedKey(command: String): (Scope, String) = def parseScopedKey(command: String): (Scope, String) =
{ {
@ -231,68 +230,3 @@ object Scope
else else
for( c <- withGlobalAxis(scope.config); t <- withGlobalAxis(scope.task); e <- withGlobalAxis(scope.extra) ) yield Scope(Global, c, t, e) for( c <- withGlobalAxis(scope.config); t <- withGlobalAxis(scope.task); e <- withGlobalAxis(scope.extra) ) yield Scope(Global, c, t, e)
} }
sealed trait ScopeAxis[+S] {
def foldStrict[T](f: S => T, ifGlobal: T, ifThis: T): T = fold(f, ifGlobal, ifThis)
def fold[T](f: S => T, ifGlobal: => T, ifThis: => T): T = this match {
case This => ifThis
case Global => ifGlobal
case Select(s) => f(s)
}
def toOption: Option[S] = foldStrict(some.fn, None, None)
def map[T](f: S => T): ScopeAxis[T] = foldStrict(s => Select(f(s)), Global, This)
def isSelect: Boolean = false
}
case object This extends ScopeAxis[Nothing]
case object Global extends ScopeAxis[Nothing]
final case class Select[S](s: S) extends ScopeAxis[S] {
override def isSelect = true
}
object ScopeAxis
{
implicit def scopeAxisToScope(axis: ScopeAxis[Nothing]): Scope =
Scope(axis, axis, axis, axis)
def fromOption[T](o: Option[T]): ScopeAxis[T] = o match {
case Some(v) => Select(v)
case None => Global
}
}
/** 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)
{
def concatShow(p: String, c: String, t: String, sep: String, x: String): String =
{
val sb = new StringBuilder
if(project) sb.append(p)
if(config) sb.append(c)
if(task) sb.append(t)
sb.append(sep)
if(extra) sb.append(x)
sb.toString
}
}
final case class ConfigKey(name: String)
object ConfigKey
{
implicit def configurationToKey(c: Configuration): ConfigKey = ConfigKey(c.name)
}
sealed trait DelegateIndex
{
def project(ref: ProjectRef): Seq[ScopeAxis[ResolvedReference]]
def config(ref: ProjectRef, conf: ConfigKey): Seq[ScopeAxis[ConfigKey]]
// def task(ref: ProjectRef, task: ScopedKey[_]): Seq[ScopeAxis[ScopedKey[_]]]
// def extra(ref: ProjectRef, e: AttributeMap): Seq[ScopeAxis[AttributeMap]]
}
private final class DelegateIndex0(refs: Map[ProjectRef, ProjectDelegates]) extends DelegateIndex
{
def project(ref: ProjectRef): Seq[ScopeAxis[ResolvedReference]] = refs.get(ref) match { case Some(pd) => pd.refs; case None => Nil }
def config(ref: ProjectRef, conf: ConfigKey): Seq[ScopeAxis[ConfigKey]] =
refs.get(ref) match {
case Some(pd) => pd.confs.get(conf) match { case Some(cs) => cs; case None => Select(conf) :: Global :: Nil }
case None => Select(conf) :: Global :: Nil
}
}
private final class ProjectDelegates(val ref: ProjectRef, val refs: Seq[ScopeAxis[ResolvedReference]], val confs: Map[ConfigKey, Seq[ScopeAxis[ConfigKey]]])

View File

@ -0,0 +1,29 @@
package sbt
import Types.some
sealed trait ScopeAxis[+S] {
def foldStrict[T](f: S => T, ifGlobal: T, ifThis: T): T = fold(f, ifGlobal, ifThis)
def fold[T](f: S => T, ifGlobal: => T, ifThis: => T): T = this match {
case This => ifThis
case Global => ifGlobal
case Select(s) => f(s)
}
def toOption: Option[S] = foldStrict(some.fn, None, None)
def map[T](f: S => T): ScopeAxis[T] = foldStrict(s => Select(f(s)), Global, This)
def isSelect: Boolean = false
}
case object This extends ScopeAxis[Nothing]
case object Global extends ScopeAxis[Nothing]
final case class Select[S](s: S) extends ScopeAxis[S] {
override def isSelect = true
}
object ScopeAxis
{
implicit def scopeAxisToScope(axis: ScopeAxis[Nothing]): Scope =
Scope(axis, axis, axis, axis)
def fromOption[T](o: Option[T]): ScopeAxis[T] = o match {
case Some(v) => Select(v)
case None => Global
}
}

View File

@ -0,0 +1,16 @@
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)
{
def concatShow(p: String, c: String, t: String, sep: String, x: String): String =
{
val sb = new StringBuilder
if(project) sb.append(p)
if(config) sb.append(c)
if(task) sb.append(t)
sb.append(sep)
if(extra) sb.append(x)
sb.toString
}
}

View File

@ -5,14 +5,16 @@ package sbt
/** An abstraction on top of Settings for build configuration and task definition. */ /** An abstraction on top of Settings for build configuration and task definition. */
import Types._
import std.TaskExtra.{task => mktask, _}
import Task._
import Project.{Initialize, KeyedInitialize, ScopedKey, Setting, setting}
import complete.Parser
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import complete.Parser
import ConcurrentRestrictions.Tag
import Def.{Initialize, KeyedInitialize, ScopedKey, Setting, setting}
import Path._ import Path._
import std.TaskExtra.{task => mktask, _}
import Task._
import Types._
/** Parses input and produces a task to run. Constructed using the companion object. */ /** Parses input and produces a task to run. Constructed using the companion object. */
sealed trait InputTask[T] { sealed trait InputTask[T] {
@ -43,7 +45,7 @@ object InputTask
def free[I,T](p: State => Parser[I])(c: I => Task[T]): InputTask[T] = free(s => p(s) map c) def free[I,T](p: State => Parser[I])(c: I => Task[T]): InputTask[T] = free(s => p(s) map c)
def separate[I,T](p: State => Parser[I])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] = def separate[I,T](p: State => Parser[I])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] =
separate(Project value p)(action) separate(Def value p)(action)
def separate[I,T](p: Initialize[State => Parser[I]])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] = def separate[I,T](p: Initialize[State => Parser[I]])(action: Initialize[I => Task[T]]): Initialize[InputTask[T]] =
p.zipWith(action)((parser, act) => free(parser)(act)) p.zipWith(action)((parser, act) => free(parser)(act))
@ -56,8 +58,8 @@ object InputTask
// However, this results in a minimal interface to the full capabilities of an InputTask for users // However, this results in a minimal interface to the full capabilities of an InputTask for users
def apply[I,T](p: Initialize[State => Parser[I]])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = def apply[I,T](p: Initialize[State => Parser[I]])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] =
{ {
val key: TaskKey[I] = Keys.parseResult.asInstanceOf[TaskKey[I]] val key: TaskKey[I] = Def.parseResult.asInstanceOf[TaskKey[I]]
(p zip Keys.resolvedScoped zipWith action(key)) { case ((parserF, scoped), act) => (p zip Def.resolvedScoped zipWith action(key)) { case ((parserF, scoped), act) =>
new InputDynamic[T] new InputDynamic[T]
{ {
type Result = I type Result = I
@ -68,7 +70,7 @@ object InputTask
} }
} }
def apply[I,T](p: State => Parser[I])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] = def apply[I,T](p: State => Parser[I])(action: TaskKey[I] => Initialize[Task[T]]): Initialize[InputTask[T]] =
apply(Project.value(p))(action) apply(Def.value(p))(action)
} }
sealed trait Scoped { def scope: Scope; val key: AttributeKey[_] } sealed trait Scoped { def scope: Scope; val key: AttributeKey[_] }
@ -153,13 +155,13 @@ object Scoped
def scopedKey: ScopedKey[S] def scopedKey: ScopedKey[S]
private[sbt] final def :==(value: S): Setting[S] = :=(value) private[sbt] final def :==(value: S): Setting[S] = :=(value)
final def := (value: => S): Setting[S] = setting(scopedKey, Project.value(value)) final def := (value: => S): Setting[S] = setting(scopedKey, Def.value(value))
final def ~= (f: S => S): Setting[S] = Project.update(scopedKey)(f) final def ~= (f: S => S): Setting[S] = Def.update(scopedKey)(f)
final def <<= (app: Initialize[S]): Setting[S] = setting(scopedKey, app) final def <<= (app: Initialize[S]): Setting[S] = setting(scopedKey, app)
final def get(settings: Settings[Scope]): Option[S] = settings.get(scopedKey.scope, scopedKey.key) final def get(settings: Settings[Scope]): Option[S] = settings.get(scopedKey.scope, scopedKey.key)
final def ? : Initialize[Option[S]] = Project.optional(scopedKey)(idFun) final def ? : Initialize[Option[S]] = Def.optional(scopedKey)(idFun)
final def or[T >: S](i: Initialize[T]): Initialize[T] = (this.?, i)(_ getOrElse _ ) final def or[T >: S](i: Initialize[T]): Initialize[T] = (this.?, i)(_ getOrElse _ )
final def ??[T >: S](or: => T): Initialize[T] = Project.optional(scopedKey)(_ getOrElse or ) final def ??[T >: S](or: => T): Initialize[T] = Def.optional(scopedKey)(_ getOrElse or )
} }
final class RichInitialize[S](init: Initialize[S]) final class RichInitialize[S](init: Initialize[S])
{ {
@ -172,12 +174,12 @@ object Scoped
{ self: TaskKey[S] => { self: TaskKey[S] =>
private[sbt] def :==(value: S): Setting[Task[S]] = :=(value) private[sbt] def :==(value: S): Setting[Task[S]] = :=(value)
private[sbt] def ::=(value: Task[S]): Setting[Task[S]] = Project.setting(scopedKey, Project.value( value )) private[sbt] def ::=(value: Task[S]): Setting[Task[S]] = Def.setting(scopedKey, Def.value( value ))
def := (value: => S): Setting[Task[S]] = ::=(mktask(value)) def := (value: => S): Setting[Task[S]] = ::=(mktask(value))
private[sbt] def :== (v: SettingKey[S]): Setting[Task[S]] = <<=( v(constant)) private[sbt] def :== (v: SettingKey[S]): Setting[Task[S]] = <<=( v(constant))
def ~= (f: S => S): Setting[Task[S]] = Project.update(scopedKey)( _ map f ) def ~= (f: S => S): Setting[Task[S]] = Def.update(scopedKey)( _ map f )
def <<= (app: Initialize[Task[S]]): Setting[Task[S]] = Project.setting(scopedKey, app) def <<= (app: Initialize[Task[S]]): Setting[Task[S]] = Def.setting(scopedKey, app)
def task: SettingKey[Task[S]] = scopedSetting(scope, key) def task: SettingKey[Task[S]] = scopedSetting(scope, key)
def get(settings: Settings[Scope]): Option[Task[S]] = settings.get(scope, key) def get(settings: Settings[Scope]): Option[Task[S]] = settings.get(scope, key)
@ -185,8 +187,8 @@ object Scoped
@deprecated("A call to 'identity' is no longer necessary and can be removed.", "0.11.0") @deprecated("A call to 'identity' is no longer necessary and can be removed.", "0.11.0")
def identity: Initialize[Task[S]] = this def identity: Initialize[Task[S]] = this
def ? : Initialize[Task[Option[S]]] = Project.optional(scopedKey) { case None => mktask { None }; case Some(t) => t map some.fn } def ? : Initialize[Task[Option[S]]] = Def.optional(scopedKey) { case None => mktask { None }; case Some(t) => t map some.fn }
def ??[T >: S](or: => T): Initialize[Task[T]] = Project.optional(scopedKey)( _ getOrElse mktask(or) ) def ??[T >: S](or: => T): Initialize[Task[T]] = Def.optional(scopedKey)( _ getOrElse mktask(or) )
def or[T >: S](i: Initialize[Task[T]]): Initialize[Task[T]] = (this.? zipWith i)( (x,y) => (x :^: y :^: KNil) map hf2( _ getOrElse _ )) def or[T >: S](i: Initialize[Task[T]]): Initialize[Task[T]] = (this.? zipWith i)( (x,y) => (x :^: y :^: KNil) map hf2( _ getOrElse _ ))
} }
final class RichInitializeTask[S](i: Initialize[Task[S]]) extends RichInitTaskBase[S, Task] final class RichInitializeTask[S](i: Initialize[Task[S]]) extends RichInitTaskBase[S, Task]
@ -195,17 +197,8 @@ object Scoped
def dependsOn(tasks: AnyInitTask*): Initialize[Task[S]] = (i, Initialize.joinAny(tasks)) { (thisTask, deps) => thisTask.dependsOn(deps : _*) } def dependsOn(tasks: AnyInitTask*): Initialize[Task[S]] = (i, Initialize.joinAny(tasks)) { (thisTask, deps) => thisTask.dependsOn(deps : _*) }
import SessionVar.{persistAndSet, resolveContext, set, transform} def triggeredBy(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Def.triggeredBy)
def runBefore(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Def.runBefore)
def updateState(f: (State, S) => State): Initialize[Task[S]] = onTask(t => transform(t, f))
def storeAs(key: TaskKey[S])(implicit f: sbinary.Format[S]): Initialize[Task[S]] = (Keys.resolvedScoped, i) { (scoped, task) =>
transform(task, (state, value) => persistAndSet( resolveContext(key, scoped.scope, state), state, value)(f))
}
def keepAs(key: TaskKey[S]): Initialize[Task[S]] =
(i, Keys.resolvedScoped)( (t,scoped) => transform(t, (state,value) => set(resolveContext(key, scoped.scope, state), state, value) ) )
def triggeredBy(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Keys.triggeredBy)
def runBefore(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Keys.runBefore)
private[this] def nonLocal(tasks: Seq[AnyInitTask], key: AttributeKey[Seq[Task[_]]]): Initialize[Task[S]] = private[this] def nonLocal(tasks: Seq[AnyInitTask], key: AttributeKey[Seq[Task[_]]]): Initialize[Task[S]] =
(Initialize.joinAny(tasks), i) { (ts, i) => i.copy(info = i.info.set(key, ts)) } (Initialize.joinAny(tasks), i) { (ts, i) => i.copy(info = i.info.set(key, ts)) }
} }
@ -231,8 +224,8 @@ object Scoped
def || [T >: S](alt: Task[T]): Initialize[R[T]] = onTask(_ || alt) def || [T >: S](alt: Task[T]): Initialize[R[T]] = onTask(_ || alt)
def && [T](alt: Task[T]): Initialize[R[T]] = onTask(_ && alt) def && [T](alt: Task[T]): Initialize[R[T]] = onTask(_ && alt)
def tag(tags: Tags.Tag*): Initialize[R[S]] = onTask(_.tag(tags: _*)) def tag(tags: Tag*): Initialize[R[S]] = onTask(_.tag(tags: _*))
def tagw(tags: (Tags.Tag, Int)*): Initialize[R[S]] = onTask(_.tagw(tags : _*)) def tagw(tags: (Tag, Int)*): Initialize[R[S]] = onTask(_.tagw(tags : _*))
} }
type AnyInitTask = Initialize[Task[T]] forSome { type T } type AnyInitTask = Initialize[Task[T]] forSome { type T }
@ -308,7 +301,7 @@ object Scoped
} }
def combine[D[_],S](c: Combine[D], f: Results[HLv] => D[S]): Initialize[Task[S]] = def combine[D[_],S](c: Combine[D], f: Results[HLv] => D[S]): Initialize[Task[S]] =
Project.app(settings)(hls => c(tasks(hls))(hlt => f(expand(hls, hlt))) ) Def.app(settings)(hls => c(tasks(hls))(hlt => f(expand(hls, hlt))) )
} }
type RedHL[HL <: HList] = Reduced[_,_,HL] type RedHL[HL <: HList] = Reduced[_,_,HL]
def reduced[HL <: HList](settings: KList[ScopedTaskable, HL]): Reduced[_,_,HL] = def reduced[HL <: HList](settings: KList[ScopedTaskable, HL]): Reduced[_,_,HL] =
@ -519,59 +512,59 @@ object Scoped
def mkTuple15[A,B,C,D,E,F,G,H,I,J,K,L,N,O,P] = (a:A,b:B,c:C,d:D,e:E,f:F,g:G,h:H,i:I,j:J,k:K,l:L,n:N,o:O,p:P) => (a,b,c,d,e,f,g,h,i,j,k,l,n,o,p) def mkTuple15[A,B,C,D,E,F,G,H,I,J,K,L,N,O,P] = (a:A,b:B,c:C,d:D,e:E,f:F,g:G,h:H,i:I,j:J,k:K,l:L,n:N,o:O,p:P) => (a,b,c,d,e,f,g,h,i,j,k,l,n,o,p)
final class Apply2[A,B](t2: (Initialize[A], Initialize[B])) { final class Apply2[A,B](t2: (Initialize[A], Initialize[B])) {
def apply[T](z: (A,B) => T) = Project.app( k2(t2) )( hf2(z) ) def apply[T](z: (A,B) => T) = Def.app( k2(t2) )( hf2(z) )
def identity = apply(mkTuple2) def identity = apply(mkTuple2)
} }
final class Apply3[A,B,C](t3: (Initialize[A], Initialize[B], Initialize[C])) { final class Apply3[A,B,C](t3: (Initialize[A], Initialize[B], Initialize[C])) {
def apply[T](z: (A,B,C) => T) = Project.app( k3(t3) )( hf3(z) ) def apply[T](z: (A,B,C) => T) = Def.app( k3(t3) )( hf3(z) )
def identity = apply(mkTuple3) def identity = apply(mkTuple3)
} }
final class Apply4[A,B,C,D](t4: (Initialize[A], Initialize[B], Initialize[C], Initialize[D])) { final class Apply4[A,B,C,D](t4: (Initialize[A], Initialize[B], Initialize[C], Initialize[D])) {
def apply[T](z: (A,B,C,D) => T) = Project.app( k4(t4) )( hf4(z) ) def apply[T](z: (A,B,C,D) => T) = Def.app( k4(t4) )( hf4(z) )
def identity = apply(mkTuple4) def identity = apply(mkTuple4)
} }
final class Apply5[A,B,C,D,E](t5: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E])) { final class Apply5[A,B,C,D,E](t5: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E])) {
def apply[T](z: (A,B,C,D,E) => T) = Project.app( k5(t5) )( hf5(z) ) def apply[T](z: (A,B,C,D,E) => T) = Def.app( k5(t5) )( hf5(z) )
def identity = apply(mkTuple5) def identity = apply(mkTuple5)
} }
final class Apply6[A,B,C,D,E,F](t6: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F])) { final class Apply6[A,B,C,D,E,F](t6: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F])) {
def apply[T](z: (A,B,C,D,E,F) => T) = Project.app( k6(t6) )( hf6(z) ) def apply[T](z: (A,B,C,D,E,F) => T) = Def.app( k6(t6) )( hf6(z) )
def identity = apply(mkTuple6) def identity = apply(mkTuple6)
} }
final class Apply7[A,B,C,D,E,F,G](t7: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G])) { final class Apply7[A,B,C,D,E,F,G](t7: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G])) {
def apply[T](z: (A,B,C,D,E,F,G) => T) = Project.app( k7(t7) )( hf7(z) ) def apply[T](z: (A,B,C,D,E,F,G) => T) = Def.app( k7(t7) )( hf7(z) )
def identity = apply(mkTuple7) def identity = apply(mkTuple7)
} }
final class Apply8[A,B,C,D,E,F,G,H](t8: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H])) { final class Apply8[A,B,C,D,E,F,G,H](t8: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H])) {
def apply[T](z: (A,B,C,D,E,F,G,H) => T) = Project.app( k8(t8) )( hf8(z) ) def apply[T](z: (A,B,C,D,E,F,G,H) => T) = Def.app( k8(t8) )( hf8(z) )
def identity = apply(mkTuple8) def identity = apply(mkTuple8)
} }
final class Apply9[A,B,C,D,E,F,G,H,I](t9: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I])) { final class Apply9[A,B,C,D,E,F,G,H,I](t9: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I) => T) = Project.app( k9(t9) )( hf9(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I) => T) = Def.app( k9(t9) )( hf9(z) )
def identity = apply(mkTuple9) def identity = apply(mkTuple9)
} }
final class Apply10[A,B,C,D,E,F,G,H,I,J](t10: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J])) { final class Apply10[A,B,C,D,E,F,G,H,I,J](t10: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I,J) => T) = Project.app( k10(t10) )( hf10(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I,J) => T) = Def.app( k10(t10) )( hf10(z) )
def identity = apply(mkTuple10) def identity = apply(mkTuple10)
} }
final class Apply11[A,B,C,D,E,F,G,H,I,J,K](t11: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K])) { final class Apply11[A,B,C,D,E,F,G,H,I,J,K](t11: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K) => T) = Project.app( k11(t11) )( hf11(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K) => T) = Def.app( k11(t11) )( hf11(z) )
def identity = apply(mkTuple11) def identity = apply(mkTuple11)
} }
final class Apply12[A,B,C,D,E,F,G,H,I,J,K,L](t12: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L])) { final class Apply12[A,B,C,D,E,F,G,H,I,J,K,L](t12: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L) => T) = Project.app( k12(t12) )( hf12(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L) => T) = Def.app( k12(t12) )( hf12(z) )
def identity = apply(mkTuple12) def identity = apply(mkTuple12)
} }
final class Apply13[A,B,C,D,E,F,G,H,I,J,K,L,N](t13: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L], Initialize[N])) { final class Apply13[A,B,C,D,E,F,G,H,I,J,K,L,N](t13: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L], Initialize[N])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L,N) => T) = Project.app( k13(t13) )( hf13(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L,N) => T) = Def.app( k13(t13) )( hf13(z) )
def identity = apply(mkTuple13) def identity = apply(mkTuple13)
} }
final class Apply14[A,B,C,D,E,F,G,H,I,J,K,L,N,O](t14: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L], Initialize[N], Initialize[O])) { final class Apply14[A,B,C,D,E,F,G,H,I,J,K,L,N,O](t14: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L], Initialize[N], Initialize[O])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L,N,O) => T) = Project.app( k14(t14) )( hf14(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L,N,O) => T) = Def.app( k14(t14) )( hf14(z) )
def identity = apply(mkTuple14) def identity = apply(mkTuple14)
} }
final class Apply15[A,B,C,D,E,F,G,H,I,J,K,L,N,O,P](t15: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L], Initialize[N], Initialize[O], Initialize[P])) { final class Apply15[A,B,C,D,E,F,G,H,I,J,K,L,N,O,P](t15: (Initialize[A], Initialize[B], Initialize[C], Initialize[D], Initialize[E], Initialize[F], Initialize[G], Initialize[H], Initialize[I], Initialize[J], Initialize[K], Initialize[L], Initialize[N], Initialize[O], Initialize[P])) {
def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L,N,O,P) => T) = Project.app( k15(t15) )( hf15(z) ) def apply[T](z: (A,B,C,D,E,F,G,H,I,J,K,L,N,O,P) => T) = Def.app( k15(t15) )( hf15(z) )
def identity = apply(mkTuple15) def identity = apply(mkTuple15)
} }

View File

@ -120,10 +120,14 @@ object Sbt extends Build
classpathSub, completeSub, apiSub, compilerIntegrationSub, compilerIvySub, classpathSub, completeSub, apiSub, compilerIntegrationSub, compilerIvySub,
interfaceSub, ioSub, ivySub, logSub, processSub, runSub, relationSub, stdTaskSub, taskSub, trackingSub, testingSub) interfaceSub, ioSub, ivySub, logSub, processSub, runSub, relationSub, stdTaskSub, taskSub, trackingSub, testingSub)
// General command support and core commands not specific to a build system
lazy val commandSub = testedBaseProject(commandPath, "Command") dependsOn(interfaceSub, ioSub, launchInterfaceSub, logSub, completeSub, classpathSub) lazy val commandSub = testedBaseProject(commandPath, "Command") dependsOn(interfaceSub, ioSub, launchInterfaceSub, logSub, completeSub, classpathSub)
// Fixes scope=Scope for Setting (core defined in collectionSub) to define the settings system used in build definitions
lazy val settingsSub = testedBaseProject(settingsPath, "Settings") dependsOn(interfaceSub, ivySub, relationSub, logSub, ioSub, commandSub, completeSub,
classpathSub, stdTaskSub, processSub) settings( sbinary )
// The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions. // The main integration project for sbt. It brings all of the subsystems together, configures them, and provides for overriding conventions.
lazy val mainSub = testedBaseProject(mainPath, "Main") dependsOn(actionsSub, interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, runSub, commandSub) lazy val mainSub = testedBaseProject(mainPath, "Main") dependsOn(actionsSub, settingsSub, interfaceSub, ioSub, ivySub, launchInterfaceSub, logSub, processSub, runSub, commandSub)
// Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object // Strictly for bringing implicits and aliases from subsystems into the top-level sbt namespace through a single package object
// technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project // technically, we need a dependency on all of mainSub's dependencies, but we don't do that since this is strictly an integration project
@ -139,6 +143,7 @@ object Sbt extends Build
def compilePath = file("compile") def compilePath = file("compile")
def mainPath = file("main") def mainPath = file("main")
def commandPath = mainPath / "command" def commandPath = mainPath / "command"
def settingsPath = mainPath / "settings"
def scriptedPath = file("scripted") def scriptedPath = file("scripted")
def sbtSettings = Seq( def sbtSettings = Seq(

View File

@ -125,6 +125,7 @@ final case class Attributed[D](data: D)(val metadata: AttributeMap)
} }
object Attributed object Attributed
{ {
def data[T](in: Seq[Attributed[T]]): Seq[T] = in.map(_.data)
def blankSeq[T](in: Seq[T]): Seq[Attributed[T]] = in map blank def blankSeq[T](in: Seq[T]): Seq[Attributed[T]] = in map blank
def blank[T](data: T): Attributed[T] = Attributed(data)(AttributeMap.empty) def blank[T](data: T): Attributed[T] = Attributed(data)(AttributeMap.empty)
} }