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
import Project.{ScopedKey, showContextKey}
import Def.{showRelativeKey, ScopedKey}
import Project.showContextKey
import Keys.{sessionSettings, thisProject}
import Load.BuildStructure
import complete.{DefaultParsers, Parser}
import Aggregation.{KeyValue,Values}
import DefaultParsers._
@ -31,7 +31,7 @@ object Act
def scopedKeySelected(index: KeyIndex, current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String],
keyMap: Map[String, AttributeKey[_]], data: Settings[Scope]): Parser[ParsedKey] =
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]]] =

View File

@ -3,8 +3,7 @@
*/
package sbt
import Project.ScopedKey
import Load.{BuildStructure,LoadedBuildUnit}
import Def.ScopedKey
import Keys.{aggregate, showSuccess, showTiming, timingFormat}
import sbt.complete.Parser
import java.net.URI
@ -30,7 +29,7 @@ final object Aggregation
Command.applyEffect(seqParser(ps)) { ts =>
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 std.TaskExtra._
@ -55,7 +54,7 @@ final object Aggregation
(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
}
@ -157,16 +156,7 @@ final object Aggregation
def aggregationEnabled(key: ScopedKey[_], data: Settings[Scope]): Boolean =
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] =
{
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
}
BuildUtil.aggregationRelation(units)
}

View File

@ -4,16 +4,8 @@
package sbt
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 Project.{ScopedKey, Setting}
import Scope.GlobalScope
import scala.annotation.tailrec
import Def.{ScopedKey, Setting}
// name is more like BuildDefinition, but that is too long
trait Build
@ -26,16 +18,16 @@ trait Build
trait Plugin
{
@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. */
def projectSettings: Seq[Project.Setting[_]] = Nil
def projectSettings: Seq[Setting[_]] = Nil
/** 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. */
def globalSettings: Seq[Project.Setting[_]] = Nil
def globalSettings: Seq[Setting[_]] = Nil
}
object Build
@ -47,283 +39,7 @@ object Build
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) }
}
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.net.URI
import Load.{BuildUnit, LoadBuildConfiguration, PartBuild}
import BuildLoader._
import Alternatives._
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
import java.net.URI
import java.net.URI
final class BuildUtil[Proj](
val keyIndex: KeyIndex,
@ -37,4 +37,44 @@ final class BuildUtil[Proj](
val configurationsForAxis: Option[ResolvedReference] => Seq[String] =
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 complete.{DefaultParsers, Parser}
import DefaultParsers._
import Project.{ScopedKey, Setting}
import Def.{ScopedKey, Setting}
import Scope.GlobalScope
object Cross

View File

@ -7,8 +7,8 @@ package sbt
import Scope.{fillTaskAxis, GlobalScope, ThisScope}
import xsbt.api.Discovery
import xsbti.compile.CompileOrder
import Project.{inConfig, Initialize, inScope, inTask, ScopedKey, Setting, SettingsDefinition}
import Load.LoadedBuild
import Project.{inConfig, inScope, inTask, richInitialize, richInitializeTask, richTaskSessionVar}
import Def.{Initialize, ScopedKey, Setting, SettingsDefinition}
import Artifact.{DocClassifier, SourceClassifier}
import Configurations.{Compile, CompilerPlugin, IntegrationTest, names, Provided, Runtime, Test}
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 {
case Some(Value(ps)) => ps
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)
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 ;
}
@ -773,7 +773,7 @@ object Classpaths
)
val baseSettings: Seq[Setting[_]] = sbtClassifiersTasks ++ Seq(
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",
normalizedName <<= name(StringUtilities.normalize),
isSnapshot <<= isSnapshot or version(_ endsWith "-SNAPSHOT"),
@ -859,7 +859,7 @@ object Classpaths
(module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) =>
val depsUpdated = reports.exists(!_.stats.cached)
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),
update <<= (conflictWarning, update, streams) map { (config, report, s) => ConflictWarning(config, report, s.log); report },
transitiveClassifiers in GlobalScope :== Seq(SourceClassifier, DocClassifier),
@ -1277,12 +1277,12 @@ trait BuildExtra extends BuildCommon
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]] =
externalIvySettingsURI(file(_.toURI), addMultiResolver)
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]] =
{
val other = (baseDirectory, appConfiguration, projectResolver, streams).identityMap
@ -1375,12 +1375,12 @@ trait BuildCommon
// 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]] =
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]] =
(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]] =
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]] =
(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
import java.io.File
import Project.{ScopedKey, Setting}
import Def.{displayFull, ScopedKey, Setting}
import Keys.{streams, Streams, TaskStreams}
import Keys.{dummyRoots, dummyState, dummyStreamsManager, executionRoots, pluginData, streamsManager, taskDefinitionKey, transformState}
import Project.richInitializeTask
import Scope.{GlobalScope, ThisScope}
import Types.const
import scala.Console.RED
@ -25,8 +26,6 @@ object PluginData
object EvaluateTask
{
import Load.BuildStructure
import Project.display
import std.{TaskExtra,Transform}
import TaskExtra._
import Keys.state
@ -34,7 +33,7 @@ object EvaluateTask
val SystemProcessors = Runtime.getRuntime.availableProcessors
def defaultConfig(state: State): EvaluateConfig =
EvaluateConfig(false, restrictions(state))
def defaultConfig(extracted: Extracted, structure: Load.BuildStructure) =
def defaultConfig(extracted: Extracted, structure: BuildStructure) =
EvaluateConfig(false, restrictions(extracted, structure))
def extractedConfig(extracted: Extracted, structure: BuildStructure): EvaluateConfig =
@ -45,7 +44,7 @@ object EvaluateTask
}
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
def restrictions(state: State): Seq[Tags.Rule] =
@ -53,16 +52,16 @@ object EvaluateTask
val extracted = Project.extract(state)
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)
def maxWorkers(extracted: Extracted, structure: Load.BuildStructure): Int =
def maxWorkers(extracted: Extracted, structure: BuildStructure): Int =
if(getSetting(Keys.parallelExecution, true, extracted, structure))
SystemProcessors
else
1
def cancelable(extracted: Extracted, structure: Load.BuildStructure): Boolean =
def cancelable(extracted: Extracted, structure: BuildStructure): Boolean =
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
def injectSettings: Seq[Setting[_]] = Seq(
@ -97,7 +96,7 @@ object EvaluateTask
def logIncomplete(result: Incomplete, state: State, streams: Streams)
{
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 }
import ExceptionCategory._
@ -199,7 +198,7 @@ object EvaluateTask
case _ => c.toString
}
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 = {
case i @ Incomplete(node, tpe, None, causes, None) =>
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
import Load._
import Project._
import Def.{ScopedKey,Setting}
import Scoped._
import Keys._
import Configurations.{Compile,Runtime}
@ -64,7 +64,7 @@ object GlobalPlugin
(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,
onLoadMessage <<= Keys.baseDirectory("Loading global plugins from " + _),
name := "global-plugin",

View File

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

View File

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

View File

@ -5,7 +5,7 @@ package sbt
import java.io.File
import java.net.URL
import Project.ScopedKey
import Def.ScopedKey
import complete._
import inc.Analysis
import inc.Locate.DefinesClass
@ -38,9 +38,9 @@ object Keys
// Project keys
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 stateBuildStructure = AttributeKey[Load.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 loadedBuild = SettingKey[Load.LoadedBuild]("loaded-build", "Provides access to the loaded project structure. This is the information available before settings are evaluated.", DSetting)
val stateBuildStructure = AttributeKey[BuildStructure]("build-structure", "Data structure containing all information about the build definition.", BSetting)
val buildStructure = TaskKey[BuildStructure]("build-structure", "Provides access to the build structure, settings, and streams manager.", DTask)
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 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)
@ -70,10 +70,6 @@ object 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 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 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)
// Classpath/Dependency Management Keys
type Classpath = Seq[Attributed[File]]
type Classpath = Def.Classpath
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)
@ -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 (state, dummyState) = dummy[State]("state", "Current build state.")
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)
private[sbt] val parseResult: TaskKey[Any] = TaskKey("$parse-result", "Internal: used to implement input tasks.", Invisible)
val triggeredBy = AttributeKey[Seq[Task[_]]]("triggered-by")
val runBefore = AttributeKey[Seq[Task[_]]]("run-before")
val triggeredBy = Def.triggeredBy
val runBefore = Def.runBefore
type Streams = std.Streams[ScopedKey[_]]
type TaskStreams = std.TaskStreams[ScopedKey[_]]
@ -351,47 +346,3 @@ object Keys
}
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 Compiler.{Compilers,Inputs}
import inc.{FileValueCache, Locate}
import Project.{inScope, ScopedKey, ScopeLocal, Setting}
import Keys.{appConfiguration, baseDirectory, configuration, fullResolvers, fullClasspath, pluginData, streams, Streams, thisProject, thisProjectRef, update}
import Keys.{exportedProducts, isDummy, loadedBuild, parseResult, resolvedScoped, taskDefinitionKey}
import Project.{inScope,makeSettings}
import Def.{parseResult, ScopedKey, ScopeLocal, Setting}
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 Build.{analyzed, data}
import Scope.{GlobalScope, ThisScope}
import Types.const
object Load
{
import BuildPaths._
import BuildStreams._
import Locate.DefinesClass
object Load
{
// 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) =
{
@ -55,7 +55,7 @@ object Load
new LoadBuildConfiguration(stagingDirectory, classpath, loader, compilers, evalPluginDef, definesClass, delegates,
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) +:
EvaluateTask.injectSettings
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)
val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings))
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 streams = mkStreams(projects, loaded.root, data)
(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 parseResult.key =>
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])
case _ => None
}
@ -180,7 +180,7 @@ object Load
def reapply(newSettings: Seq[Setting[_]], structure: BuildStructure)(implicit display: Show[ScopedKey[_]]): BuildStructure =
{
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 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)
@ -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.")
val plugs = plugins(pluginDir, s, config)
val defs = definitionSources(defDir)
val target = buildOutputDirectory(defDir, config.compilers)
val target = buildOutputDirectory(defDir, config.compilers.scalac.scalaInstance)
IO.createDirectory(target)
val loadedDefs =
if(defs.isEmpty)
@ -594,10 +594,6 @@ object Load
def loadPlugin(pluginName: String, loader: ClassLoader): 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 findDefinitions(analysis: inc.Analysis): Seq[String] = discover(analysis, "sbt.Build")
def discover(analysis: inc.Analysis, subclasses: String*): Seq[String] =
@ -634,93 +630,65 @@ object Load
}
def defaultEvalOptions: Seq[String] = Nil
def baseImports = "import sbt._, Process._, Keys._" :: Nil
final class EvaluatedConfigurations(val eval: Eval, val settings: Seq[Setting[_]])
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: Seq[File] = 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])
{
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)
@deprecated("Use BuildUtil.baseImports", "0.13.0")
def baseImports = BuildUtil.baseImports
@deprecated("Use BuildUtil.checkCycles", "0.13.0")
def checkCycles(units: Map[URI, LoadedBuildUnit]): Unit = BuildUtil.checkCycles(units)
@deprecated("Use BuildUtil.importAll", "0.13.0")
def importAll(values: Seq[String]): Seq[String] = BuildUtil.importAll(values)
@deprecated("Use BuildUtil.importAllRoot", "0.13.0")
def importAllRoot(values: Seq[String]): Seq[String] = BuildUtil.importAllRoot(values)
@deprecated("Use BuildUtil.rootedNames", "0.13.0")
def rootedName(s: String): String = BuildUtil.rootedName(s)
@deprecated("Use BuildUtil.getImports", "0.13.0")
def getImports(unit: BuildUnit): Seq[String] = BuildUtil.getImports(unit)
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)
{
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) }
}
def buildUtil(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 = Aggregation.relation(units)
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)
}
@deprecated("LoadedBuildUnit is now top-level", "0.13.0")
type LoadedBuildUnit = sbt.LoadedBuildUnit
@deprecated("BuildStructure is now top-level", "0.13.0")
type BuildStructure = sbt.BuildStructure
@deprecated("StructureIndex is now top-level", "0.13.0")
type StructureIndex = sbt.StructureIndex
@deprecated("LoadBuildConfiguration is now top-level", "0.13.0")
type LoadBuildConfiguration = sbt.LoadBuildConfiguration
@deprecated("LoadBuildConfiguration is now top-level", "0.13.0")
val LoadBuildConfiguration = sbt.LoadBuildConfiguration
final class EvaluatedConfigurations(val eval: Eval, val settings: 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
final class StructureIndex(
val keyMap: Map[String, AttributeKey[_]],
val taskToKey: Map[Task[_], ScopedKey[Task[_]]],
val triggers: Triggers[Task],
val keyIndex: KeyIndex,
val aggregateKeyIndex: KeyIndex
)
@deprecated("LoadedDefinitions is now top-level", "0.13.0")
type LoadedDefinitions = sbt.LoadedDefinitions
@deprecated("LoadedPlugins is now top-level", "0.13.0")
type LoadedPlugins = sbt.LoadedPlugins
@deprecated("BuildUnit is now top-level", "0.13.0")
type BuildUnit = sbt.BuildUnit
@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)

View File

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

View File

@ -94,7 +94,7 @@ object BuiltinCommands
if(Project.isProjectLoaded(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 built = if(sc.isEmpty) "" else "The current project is built against " + sc + "\n"
current + built + aboutPlugins(e)
@ -199,7 +199,7 @@ object BuiltinCommands
s
}
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...")
val newStructure = Load.reapply(newSession.mergeSettings, structure)( Project.showContextKey(newSession, structure) )
@ -215,13 +215,13 @@ object BuiltinCommands
reapply(setResult.session, structure, s)
}
// @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)
def inspect = Command(InspectCommand, inspectBrief, inspectDetailed)(inspectParser) { case (s, (option, sk)) =>
s.log.info(inspectOutput(s, option, sk))
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)
import extracted._
@ -262,7 +262,7 @@ object BuiltinCommands
import InspectOption._
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))
}
val spacedInspectOptionParser: (State => Parser[InspectOption]) = (s: State) => {
@ -322,7 +322,7 @@ object BuiltinCommands
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)
def prefix(id: String) = if(currentID != id) " " else if(current) " * " else "(*)"

View File

@ -33,7 +33,8 @@ object DefaultOptions {
import Opts._
import Path._
import BuildPaths.{getGlobalBase, getGlobalSettingsDirectory}
import Project.{Setting, extract}
import Project.{extract, richInitializeTask}
import Def.Setting
def javac: 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.io.File
import Keys.{Streams, TaskStreams}
import Project.ScopedKey
import Def.ScopedKey
import Aggregation.{KeyValue, Values}
import Types.idFun
import Highlight.{bold, showMatches}

View File

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

View File

@ -6,10 +6,10 @@ package sbt
import java.io.File
import java.net.URI
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 Load.BuildStructure
import Types.{idFun, Id}
import Def.{Flattened, Initialize, ScopedKey, Setting}
import Types.idFun
import complete.DefaultParsers
sealed trait ProjectDefinition[PR <: ProjectReference]
@ -17,7 +17,7 @@ sealed trait ProjectDefinition[PR <: ProjectReference]
def id: String
def base: File
def configurations: Seq[Configuration]
def settings: Seq[Project.Setting[_]]
def settings: Seq[Setting[_]]
def aggregate: Seq[PR]
@deprecated("Delegation between projects should be replaced by directly sharing settings.", "0.13.0")
def delegates: Seq[PR]
@ -36,7 +36,7 @@ sealed trait ProjectDefinition[PR <: ProjectReference]
sealed trait Project extends ProjectDefinition[ProjectReference]
{
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 =
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 aggregate(refs: ProjectReference*): Project = copy(aggregate = (aggregate: Seq[ProjectReference]) ++ refs)
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 : _*))
}
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] }
final case class ResolvedClasspathDependency(project: ProjectRef, configuration: Option[String]) extends ClasspathDep[ProjectRef]
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[_]] =
showContextKey(state, None)
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[_]] =
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[_]] =
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) + "/"
}
def showLoadingKey(loaded: LoadedBuild, keyNameColor: Option[String] = None): Show[ScopedKey[_]] =
Def.showRelativeKey( ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head), loaded.allProjectRefs.size > 1, keyNameColor)
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]
@ -183,8 +126,8 @@ object Project extends Init[Scope] with ProjectExtra
def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] =
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: Load.LoadedBuild): Option[ResolvedProject] = getProject(ref, structure.units)
def getProject(ref: ProjectRef, units: Map[URI, Load.LoadedBuildUnit]): Option[ResolvedProject] =
def getProject(ref: ProjectRef, structure: LoadedBuild): Option[ResolvedProject] = getProject(ref, structure.units)
def getProject(ref: ProjectRef, units: Map[URI, LoadedBuildUnit]): Option[ResolvedProject] =
(units get ref.build).flatMap(_.defined get ref.project)
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 =
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[_]]) =
make(settings)(delegates, scopeLocal, display)
Def.make(settings)(delegates, scopeLocal, display)
def equal(a: ScopedKey[_], b: ScopedKey[_], mask: ScopeMask): Boolean =
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[_] =
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 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 =>
def fmt(s: Setting[_]) = s.pos match {
case pos: FilePosition => Some(pos.path + ":" + pos.startLine)
@ -309,7 +223,7 @@ object Project extends Init[Scope] with ProjectExtra
} getOrElse ""
val cMap = flattenLocals(comp)
val cMap = Def.flattenLocals(comp)
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 }
@ -343,7 +257,7 @@ object Project extends Init[Scope] with ProjectExtra
def relation(structure: BuildStructure, actual: Boolean)(implicit display: Show[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)) =>
r + (key, value.dependencies)
}
@ -412,26 +326,25 @@ object Project extends Init[Scope] with ProjectExtra
val extracted = Project.extract(state)
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)
{
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 _
/** Many methods were moved to Def in 0.13. This implicit makes those methods still available on Project for the transition. */
@inline
@deprecated("Use Def directly", "0.13.0")
implicit def projectToDef(p: Project.type): Def.type = Def
implicit def projectToRef(p: Project): ProjectReference = LocalProject(p.id)
final class RichTaskSessionVar[S](i: Initialize[Task[S]])
{
import SessionVar.{persistAndSet, resolveContext, set, transform => tx}
def updateState(f: (State, S) => State): Initialize[Task[S]] = i(t => tx(t, f))
def storeAs(key: TaskKey[S])(implicit f: sbinary.Format[S]): Initialize[Task[S]] = (Keys.resolvedScoped, i) { (scoped, task) =>
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
@ -439,6 +352,14 @@ trait ProjectExtra
implicit def configDependencyConstructor[T <% ProjectReference](p: T): Constructor = new Constructor(p)
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[_]] =
inScope(ThisScope.copy(config = Select(conf)) )( (configuration :== conf) +: ss)
def inTask(t: Scoped)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
@ -446,69 +367,3 @@ trait ProjectExtra
def inScope(scope: Scope)(ss: Seq[Setting[_]]): Seq[Setting[_]] =
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.net.URI
import Def.{ScopedKey,Setting}
import Project._
import Types.Endo
import compiler.Eval
@ -89,7 +90,7 @@ object SessionSettings
val newSession = session.copy(append = newAppend.toMap, original = newOriginal.flatten.toSeq)
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 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 =
withSettings(s){ session =>
for( (ref, settings) <- session.append if !settings.isEmpty) {
println("In " + Project.display(ref))
println("In " + Reference.display(ref))
printSettings(settings)
}
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.net.URI
import Project._
import Def.{ScopedKey, Setting}
import Scope.{GlobalScope,ThisScope}
import Load.BuildStructure
import Types.{const, idFun, Id}
import complete._
import DefaultParsers._
@ -31,7 +31,7 @@ private[sbt] object SettingCompletions
{
val akey = setting.key.key
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 =>
if(d.key == akey)
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. */
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._
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.io.File
import Project.{ScopedKey, flattenLocals, compiled}
import Load.BuildStructure
import Def.{compiled,flattenLocals,ScopedKey}
import Predef.{any2stringadd => _, _}
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
import java.io.File
import Keys.Classpath
import Def.Classpath
import scala.annotation.implicitNotFound
object Append
{
{
@implicitNotFound(msg = "No implicit for Append.Value[${A}, ${B}] found,\n so ${B} cannot be appended to ${A}")
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 {
case BuildRef(b) => b
case ProjectRef(b, _) => b
@ -78,5 +101,4 @@ object Reference
implicit def uriToRef(u: URI): ProjectReference = RootProject(u)
implicit def fileToRef(f: File): ProjectReference = RootProject(f)
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.net.URI
import Types.some
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)
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) =
{
@ -231,68 +230,3 @@ object Scope
else
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. */
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.net.URI
import complete.Parser
import ConcurrentRestrictions.Tag
import Def.{Initialize, KeyedInitialize, ScopedKey, Setting, setting}
import Path._
import std.TaskExtra.{task => mktask, _}
import Task._
import Types._
/** Parses input and produces a task to run. Constructed using the companion object. */
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 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]] =
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
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]]
(p zip Keys.resolvedScoped zipWith action(key)) { case ((parserF, scoped), act) =>
val key: TaskKey[I] = Def.parseResult.asInstanceOf[TaskKey[I]]
(p zip Def.resolvedScoped zipWith action(key)) { case ((parserF, scoped), act) =>
new InputDynamic[T]
{
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]] =
apply(Project.value(p))(action)
apply(Def.value(p))(action)
}
sealed trait Scoped { def scope: Scope; val key: AttributeKey[_] }
@ -153,13 +155,13 @@ object Scoped
def scopedKey: ScopedKey[S]
private[sbt] final def :==(value: S): Setting[S] = :=(value)
final def := (value: => S): Setting[S] = setting(scopedKey, Project.value(value))
final def ~= (f: S => S): Setting[S] = Project.update(scopedKey)(f)
final def := (value: => S): Setting[S] = setting(scopedKey, Def.value(value))
final def ~= (f: S => S): Setting[S] = Def.update(scopedKey)(f)
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 ? : 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 ??[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])
{
@ -172,12 +174,12 @@ object Scoped
{ self: TaskKey[S] =>
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))
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 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")
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 ??[T >: S](or: => T): Initialize[Task[T]] = Project.optional(scopedKey)( _ getOrElse mktask(or) )
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]] = 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 _ ))
}
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 : _*) }
import SessionVar.{persistAndSet, resolveContext, set, transform}
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)
def triggeredBy(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Def.triggeredBy)
def runBefore(tasks: AnyInitTask*): Initialize[Task[S]] = nonLocal(tasks, Def.runBefore)
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)) }
}
@ -231,8 +224,8 @@ object Scoped
def || [T >: S](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 tagw(tags: (Tags.Tag, Int)*): Initialize[R[S]] = onTask(_.tagw(tags : _*))
def tag(tags: Tag*): Initialize[R[S]] = onTask(_.tag(tags: _*))
def tagw(tags: (Tag, Int)*): Initialize[R[S]] = onTask(_.tagw(tags : _*))
}
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]] =
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]
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)
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}

View File

@ -120,10 +120,14 @@ object Sbt extends Build
classpathSub, completeSub, apiSub, compilerIntegrationSub, compilerIvySub,
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)
// 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.
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
// 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 mainPath = file("main")
def commandPath = mainPath / "command"
def settingsPath = mainPath / "settings"
def scriptedPath = file("scripted")
def sbtSettings = Seq(

View File

@ -125,6 +125,7 @@ final case class Attributed[D](data: D)(val metadata: AttributeMap)
}
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 blank[T](data: T): Attributed[T] = Attributed(data)(AttributeMap.empty)
}