mirror of https://github.com/sbt/sbt.git
speed up startup
This commit is contained in:
parent
5e9cc7ea5c
commit
babf642dfc
|
|
@ -22,7 +22,7 @@ object Load
|
|||
import BuildPaths._
|
||||
import BuildStreams._
|
||||
|
||||
// note that there is State is passed in but not pulled out
|
||||
// note that there is State passed in but not pulled out
|
||||
def defaultLoad(state: State, baseDirectory: File, log: Logger): (() => Eval, BuildStructure) =
|
||||
{
|
||||
val provider = state.configuration.provider
|
||||
|
|
@ -33,7 +33,7 @@ object Load
|
|||
val classpath = provider.mainClasspath ++ scalaProvider.jars
|
||||
val compilers = Compiler.compilers(state.configuration, log)
|
||||
val evalPluginDef = EvaluateTask.evalPluginDef(log) _
|
||||
val delegates = memo(defaultDelegates)
|
||||
val delegates = defaultDelegates
|
||||
val inject: Seq[Project.Setting[_]] = ((appConfiguration in GlobalScope) :== state.configuration) +: EvaluateTask.injectSettings
|
||||
val rawConfig = new LoadBuildConfiguration(stagingDirectory, Nil, classpath, loader, compilers, evalPluginDef, delegates, EvaluateTask.injectStreams, inject, log)
|
||||
val commonPlugins = buildGlobalPlugins(defaultGlobalPlugins, state, rawConfig)
|
||||
|
|
@ -46,7 +46,9 @@ object Load
|
|||
val rootProject = getRootProject(lb.units)
|
||||
def resolveRef(project: Reference): ResolvedReference = Scope.resolveReference(lb.root, rootProject, project)
|
||||
Scope.delegates(
|
||||
lb.allProjectRefs,
|
||||
resolveRef,
|
||||
rootProject,
|
||||
project => projectInherit(lb, project),
|
||||
(project, config) => configInherit(lb, project, config, rootProject),
|
||||
(project, task) => Nil,
|
||||
|
|
@ -62,13 +64,7 @@ object Load
|
|||
def configInheritRef(lb: LoadedBuild, ref: ProjectRef, config: ConfigKey): Seq[ConfigKey] =
|
||||
configurationOpt(lb.units, ref.build, ref.project, config).toList.flatMap(_.extendsConfigs).map(c => ConfigKey(c.name))
|
||||
|
||||
def projectInherit(lb: LoadedBuild, ref: ResolvedReference): Seq[ProjectRef] =
|
||||
ref match
|
||||
{
|
||||
case pr: ProjectRef => projectInheritRef(lb, pr)
|
||||
case BuildRef(uri) => Nil
|
||||
}
|
||||
def projectInheritRef(lb: LoadedBuild, ref: ProjectRef): Seq[ProjectRef] =
|
||||
def projectInherit(lb: LoadedBuild, ref: ProjectRef): Seq[ProjectRef] =
|
||||
getProject(lb.units, ref.build, ref.project).delegates
|
||||
|
||||
// build, load, and evaluate all units.
|
||||
|
|
@ -414,6 +410,21 @@ object Load
|
|||
}
|
||||
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ object Project extends Init[Scope] with ProjectExtra
|
|||
lazy val aggregate = aggregate0
|
||||
lazy val dependencies = dependencies0
|
||||
lazy val delegates = delegates0
|
||||
|
||||
Dag.topologicalSort(configurations)(_.extendsConfigs) // checks for cyclic references here instead of having to do it in Scope.delegates
|
||||
}
|
||||
|
||||
def apply(id: String, base: File, aggregate: => Seq[ProjectReference] = Nil, dependencies: => Seq[ClasspathDep[ProjectReference]] = Nil, delegates: => Seq[ProjectReference] = Nil,
|
||||
|
|
@ -158,7 +160,7 @@ 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[_]]) =
|
||||
translateUninitialized( make(settings)(delegates, scopeLocal) )
|
||||
translateCyclic( make(settings)(delegates, scopeLocal) )
|
||||
|
||||
def display(scoped: ScopedKey[_]): String = Scope.display(scoped.scope, scoped.key.label)
|
||||
def display(ref: Reference): String =
|
||||
|
|
@ -197,14 +199,8 @@ object Project extends Init[Scope] with ProjectExtra
|
|||
val f = mapScope(g)
|
||||
ss.map(_ mapReferenced f)
|
||||
}
|
||||
def translateUninitialized[T](f: => T): T =
|
||||
try { f } catch {
|
||||
case u: Project.Uninitialized =>
|
||||
val msg = "Uninitialized reference to " + display(u.key) + " from " + display(u.refKey)
|
||||
throw new Uninitialized(u.key, u.refKey, msg)
|
||||
case c: Dag.Cyclic =>
|
||||
throw new MessageOnlyException(c.getMessage)
|
||||
}
|
||||
def translateCyclic[T](f: => T): T =
|
||||
try { f } catch { case c: Dag.Cyclic => throw new MessageOnlyException(c.getMessage) }
|
||||
|
||||
def delegates(structure: BuildStructure, scope: Scope, key: AttributeKey[_]): Seq[ScopedKey[_]] =
|
||||
structure.delegates(scope).map(d => ScopedKey(d, key))
|
||||
|
|
|
|||
|
|
@ -117,10 +117,23 @@ object Scope
|
|||
|
||||
// *Inherit functions should be immediate delegates and not include argument itself. Transitivity will be provided by this method
|
||||
def delegates(
|
||||
refs: Seq[(ProjectRef, ResolvedProject)],
|
||||
resolve: Reference => ResolvedReference,
|
||||
projectInherit: ResolvedReference => Seq[ResolvedReference],
|
||||
rootProject: URI => String,
|
||||
projectInherit: ProjectRef => Seq[ProjectRef],
|
||||
configInherit: (ResolvedReference, ConfigKey) => Seq[ConfigKey],
|
||||
taskInherit: (ResolvedReference, AttributeKey[_]) => Seq[AttributeKey[_]],
|
||||
extraInherit: (ResolvedReference, AttributeMap) => Seq[AttributeMap]): Scope => Seq[Scope] =
|
||||
{
|
||||
val index = delegates(refs, projectInherit, configInherit)
|
||||
scope => indexedDelegates(resolve, index, rootProject, taskInherit, extraInherit)(scope)
|
||||
}
|
||||
|
||||
def indexedDelegates(
|
||||
resolve: Reference => ResolvedReference,
|
||||
index: DelegateIndex,
|
||||
rootProject: URI => String,
|
||||
taskInherit: (ResolvedReference, AttributeKey[_]) => Seq[AttributeKey[_]],
|
||||
extraInherit: (ResolvedReference, AttributeMap) => Seq[AttributeMap])(rawScope: Scope): Seq[Scope] =
|
||||
{
|
||||
val scope = Scope.replaceThis(GlobalScope)(rawScope)
|
||||
|
|
@ -128,9 +141,10 @@ object Scope
|
|||
def nonProjectScopes(resolvedProj: ResolvedReference)(px: ScopeAxis[ResolvedReference]) =
|
||||
{
|
||||
val p = px.toOption getOrElse resolvedProj
|
||||
val cLin = linearize(scope.config)(configInherit(p, _))
|
||||
val tLin = linearize(scope.task)(taskInherit(p,_))
|
||||
val eLin = linearize(scope.extra)(extraInherit(p,_))
|
||||
val configProj = p match { case pr: ProjectRef => pr; case br: BuildRef => ProjectRef(br.build, rootProject(br.build)) }
|
||||
val cLin = scope.config match { case Select(conf) => index.config(configProj, conf); case _ => withGlobalAxis(scope.config) }
|
||||
val tLin = withGlobalAxis(scope.task)
|
||||
val eLin = withGlobalAxis(scope.extra)
|
||||
for(c <- cLin; t <- tLin; e <- eLin) yield Scope(px, c, t, e)
|
||||
}
|
||||
scope.project match
|
||||
|
|
@ -139,24 +153,56 @@ object Scope
|
|||
case This => withGlobalScope(scope.copy(project = Global))
|
||||
case Select(proj) =>
|
||||
val resolvedProj = resolve(proj)
|
||||
val prod = withRawBuilds(linearize(scope.project map resolve, Nil)(projectInherit)) flatMap nonProjectScopes(resolvedProj)
|
||||
(prod :+ GlobalScope).distinct
|
||||
val projAxes: Seq[ScopeAxis[ResolvedReference]] =
|
||||
resolvedProj match
|
||||
{
|
||||
case pr: ProjectRef => index.project(pr)
|
||||
case br: BuildRef => Select(br) :: Global :: Nil
|
||||
}
|
||||
projAxes flatMap nonProjectScopes(resolvedProj)
|
||||
}
|
||||
}
|
||||
|
||||
def withGlobalAxis[T](base: ScopeAxis[T]): Seq[ScopeAxis[T]] = if(base.isSelect) base :: Global :: Nil else Global :: Nil
|
||||
def withGlobalScope(base: Scope): Seq[Scope] = if(base == GlobalScope) GlobalScope :: Nil else base :: GlobalScope :: Nil
|
||||
def withRawBuilds(ps: Seq[ScopeAxis[ResolvedReference]]): Seq[ScopeAxis[ResolvedReference]] =
|
||||
(ps ++ (ps flatMap rawBuilds).map(Select.apply) :+ Global).distinct
|
||||
def withRawBuilds(ps: Seq[ScopeAxis[ProjectRef]]): Seq[ScopeAxis[ResolvedReference]] =
|
||||
ps ++ (ps flatMap rawBuild) :+ Global
|
||||
|
||||
def rawBuilds(ps: ScopeAxis[ResolvedReference]): Seq[ResolvedReference] = ps match { case Select(ref) => rawBuilds(ref); case _ => Nil }
|
||||
def rawBuilds(ps: ResolvedReference): Seq[ResolvedReference] = (Reference.uri(ps) map BuildRef.apply).toList
|
||||
def rawBuild(ps: ScopeAxis[ProjectRef]): Seq[ScopeAxis[BuildRef]] = ps match { case Select(ref) => Select(BuildRef(ref.build)) :: Nil; case _ => Nil }
|
||||
|
||||
def linearize[T](axis: ScopeAxis[T], append: Seq[ScopeAxis[T]] = Global :: Nil)(inherit: T => Seq[T]): Seq[ScopeAxis[T]] =
|
||||
|
||||
def delegates(
|
||||
refs: Seq[(ProjectRef, ResolvedProject)],
|
||||
projectInherit: ProjectRef => Seq[ProjectRef],
|
||||
configInherit: (ResolvedReference, ConfigKey) => Seq[ConfigKey]): DelegateIndex =
|
||||
{
|
||||
val pDelegates = refs map { case (ref, project) =>
|
||||
(ref, delegateIndex(ref, project.configurations)(projectInherit, configInherit) )
|
||||
} toMap ;
|
||||
new DelegateIndex0(pDelegates)
|
||||
}
|
||||
private[this] def delegateIndex(ref: ProjectRef, confs: Seq[Configuration])(projectInherit: ProjectRef => Seq[ProjectRef], configInherit: (ResolvedReference, ConfigKey) => Seq[ConfigKey]): ProjectDelegates =
|
||||
{
|
||||
val refDelegates = withRawBuilds(linearize(Select(ref), false)(projectInherit))
|
||||
val configs = confs map { c => axisDelegates(configInherit, ref, ConfigKey(c.name)) }
|
||||
val tasks = confs map { c => axisDelegates(configInherit, ref, ConfigKey(c.name)) }
|
||||
new ProjectDelegates(ref, refDelegates, configs.toMap)
|
||||
}
|
||||
def axisDelegates[T](direct: (ResolvedReference, T) => Seq[T], ref: ResolvedReference, init: T): (T, Seq[ScopeAxis[T]]) =
|
||||
( init, linearize(Select(init))(direct(ref, _)) )
|
||||
|
||||
def linearize[T](axis: ScopeAxis[T], appendGlobal: Boolean = true)(inherit: T => Seq[T]): Seq[ScopeAxis[T]] =
|
||||
axis match
|
||||
{
|
||||
case Select(x) => (Dag.topologicalSort(x)(inherit).map(Select.apply).reverse ++ append).distinct
|
||||
case Global | This => append
|
||||
case Select(x) => topologicalSort(x, appendGlobal)(inherit)
|
||||
case Global | This => if(appendGlobal) Global :: Nil else Nil
|
||||
}
|
||||
|
||||
def topologicalSort[T](node: T, appendGlobal: Boolean)(dependencies: T => Seq[T]): Seq[ScopeAxis[T]] =
|
||||
{
|
||||
val o = Dag.topologicalSortUnchecked(node)(dependencies).map(Select.apply)
|
||||
if(appendGlobal) o ::: Global :: Nil else o
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -186,4 +232,22 @@ 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 => Nil }
|
||||
case None => Nil
|
||||
}
|
||||
}
|
||||
private final class ProjectDelegates(val ref: ProjectRef, val refs: Seq[ScopeAxis[ResolvedReference]], val confs: Map[ConfigKey, Seq[ScopeAxis[ConfigKey]]])
|
||||
|
|
@ -36,6 +36,24 @@ object Dag
|
|||
|
||||
finished.toList;
|
||||
}
|
||||
// doesn't check for cycles
|
||||
def topologicalSortUnchecked[T](node: T)(dependencies: T => Iterable[T]): List[T] =
|
||||
{
|
||||
val discovered = new mutable.HashSet[T]
|
||||
var finished: List[T] = Nil
|
||||
|
||||
def visitAll(nodes: Iterable[T]) = nodes foreach visit
|
||||
def visit(node : T){
|
||||
if (!discovered(node)) {
|
||||
discovered(node) = true;
|
||||
visitAll(dependencies(node))
|
||||
finished ::= node;
|
||||
}
|
||||
}
|
||||
|
||||
visit(node);
|
||||
finished;
|
||||
}
|
||||
final class Cyclic(val value: Any, val all: List[Any], val complete: Boolean)
|
||||
extends Exception( "Cyclic reference involving " + (if(complete) all.mkString(", ") else value) )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ trait RMap[K[_], V[_]]
|
|||
def get[T](k: K[T]): Option[V[T]]
|
||||
def contains[T](k: K[T]): Boolean
|
||||
def toSeq: Seq[(K[_], V[_])]
|
||||
def keys: Iterable[K[_]]
|
||||
def values: Iterable[V[_]]
|
||||
}
|
||||
|
||||
trait IMap[K[_], V[_]] extends (K ~> V) with RMap[K,V]
|
||||
|
|
@ -54,6 +56,8 @@ object IMap
|
|||
def mapValues[V2[_]](f: V ~> V2) =
|
||||
new IMap0[K,V2](backing.mapValues(x => f(x)).toMap)
|
||||
def toSeq = backing.toSeq
|
||||
def keys = backing.keys
|
||||
def values = backing.values
|
||||
|
||||
override def toString = backing.toString
|
||||
}
|
||||
|
|
@ -83,6 +87,9 @@ class DelegatingPMap[K[_], V[_]](backing: mutable.Map[K[_], V[_]]) extends Abstr
|
|||
v
|
||||
}
|
||||
def toSeq = backing.toSeq
|
||||
def keys = backing.keys
|
||||
def values = backing.values
|
||||
|
||||
|
||||
private[this] def cast[T](v: V[_]): V[T] = v.asInstanceOf[V[T]]
|
||||
private[this] def cast[T](o: Option[V[_]]): Option[V[T]] = o map cast[T]
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ trait Init[Scope]
|
|||
def asTransform(s: Settings[Scope]): ScopedKey ~> Id = new (ScopedKey ~> Id) {
|
||||
def apply[T](k: ScopedKey[T]): T = getValue(s, k)
|
||||
}
|
||||
def getValue[T](s: Settings[Scope], k: ScopedKey[T]) = s.get(k.scope, k.key).get
|
||||
def getValue[T](s: Settings[Scope], k: ScopedKey[T]) = s.get(k.scope, k.key) getOrElse error("Internal settings error: invalid reference to " + display(k))
|
||||
def asFunction[T](s: Settings[Scope]): ScopedKey[T] => T = k => getValue(s, k)
|
||||
|
||||
def compiled(init: Seq[Setting[_]], actual: Boolean = true)(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopeLocal): CompiledMap =
|
||||
|
|
@ -124,18 +124,16 @@ trait Init[Scope]
|
|||
}
|
||||
private[this] def delegateForKey[T](sMap: ScopedMap, k: ScopedKey[T], scopes: Seq[Scope], refKey: ScopedKey[_], isFirst: Boolean): ScopedKey[T] =
|
||||
{
|
||||
val scache = PMap.empty[ScopedKey, ScopedKey]
|
||||
def resolve(search: Seq[Scope]): ScopedKey[T] =
|
||||
search match {
|
||||
case Seq() => throw Uninitialized(k, refKey)
|
||||
case Seq(x, xs @ _*) =>
|
||||
val sk = ScopedKey(x, k.key)
|
||||
scache.getOrUpdate(sk, if(defines(sMap, sk, refKey, isFirst)) sk else resolve(xs))
|
||||
val definesKey = (refKey != sk || !isFirst) && (sMap contains sk)
|
||||
if(definesKey) sk else resolve(xs)
|
||||
}
|
||||
resolve(scopes)
|
||||
}
|
||||
private[this] def defines(map: ScopedMap, key: ScopedKey[_], refKey: ScopedKey[_], isFirst: Boolean): Boolean =
|
||||
(map get key) match { case Some(Seq(x, _*)) => (refKey != key) || !isFirst; case _ => false }
|
||||
|
||||
private[this] def applyInits(ordered: Seq[Compiled])(implicit delegates: Scope => Seq[Scope]): Settings[Scope] =
|
||||
(empty /: ordered){ (m, comp) => comp.eval(m) }
|
||||
|
|
@ -149,7 +147,7 @@ trait Init[Scope]
|
|||
|
||||
final class Uninitialized(val key: ScopedKey[_], val refKey: ScopedKey[_], msg: String) extends Exception(msg)
|
||||
def Uninitialized(key: ScopedKey[_], refKey: ScopedKey[_]): Uninitialized =
|
||||
new Uninitialized(key, refKey, "Reference to uninitialized setting " + key.key.label + " (in " + key.scope + ") from " + refKey.key.label +" (in " + refKey.scope + ")")
|
||||
new Uninitialized(key, refKey, "Reference to uninitialized setting " + display(key) + " from " + display(refKey))
|
||||
final class Compiled(val key: ScopedKey[_], val dependencies: Iterable[ScopedKey[_]], val eval: Settings[Scope] => Settings[Scope])
|
||||
{
|
||||
override def toString = display(key)
|
||||
|
|
|
|||
Loading…
Reference in New Issue