mirror of https://github.com/sbt/sbt.git
require a smaller set of sources in the third (transitive) step of inc. compilation
This commit is contained in:
parent
b4e64d37db
commit
8c0a2fbe1c
|
|
@ -108,7 +108,7 @@ object Incremental
|
|||
val dependsOnSrc = previous.usesInternalSrc _
|
||||
val propagated =
|
||||
if(transitive)
|
||||
invalidateTransitive(dependsOnSrc, changes.modified, log)
|
||||
transitiveDependencies(dependsOnSrc, changes.modified, log)
|
||||
else
|
||||
invalidateStage2(dependsOnSrc, changes.modified, log)
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ object Incremental
|
|||
def invalidateDirect(dependsOnSrc: File => Set[File], modified: Set[File]): Set[File] =
|
||||
(modified flatMap dependsOnSrc) -- modified
|
||||
|
||||
/** Invalidates transitive source dependencies including `modified`. It excludes any sources that were recompiled during the previous run.*/
|
||||
/** Invalidates transitive source dependencies including `modified`.*/
|
||||
@tailrec def invalidateTransitive(dependsOnSrc: File => Set[File], modified: Set[File], log: Logger): Set[File] =
|
||||
{
|
||||
val newInv = invalidateDirect(dependsOnSrc, modified)
|
||||
|
|
@ -140,6 +140,31 @@ object Incremental
|
|||
if(newInv.isEmpty) modified else invalidateTransitive(dependsOnSrc, modified ++ newInv, log)
|
||||
}
|
||||
|
||||
/** Returns the transitive source dependencies of `initial`, excluding the files in `initial` in most cases.
|
||||
* In three-stage incremental compilation, the `initial` files are the sources from step 2 that had API changes.
|
||||
* Because strongly connected components (cycles) are included in step 2, the files with API changes shouldn't
|
||||
* need to be compiled in step 3 if their dependencies haven't changed. If there are new cycles introduced after
|
||||
* step 2, these can require step 2 sources to be included in step 3 recompilation.
|
||||
*/
|
||||
def transitiveDependencies(dependsOnSrc: File => Set[File], initial: Set[File], log: Logger): Set[File] =
|
||||
{
|
||||
// include any file that depends on included files
|
||||
def recheck(included: Set[File], process: Set[File], excluded: Set[File]): Set[File] =
|
||||
{
|
||||
val newIncludes = (process flatMap dependsOnSrc) ** excluded
|
||||
if(newIncludes.isEmpty)
|
||||
included
|
||||
else
|
||||
recheck(included ++ newIncludes, newIncludes, excluded -- newIncludes)
|
||||
}
|
||||
val transitiveOnly = transitiveDepsOnly(initial)(dependsOnSrc)
|
||||
log.debug("Step 3 transitive dependencies:\n\t" + transitiveOnly)
|
||||
val stage3 = recheck(transitiveOnly, transitiveOnly, initial)
|
||||
log.debug("Step 3 sources from new step 2 source dependencies:\n\t" + (stage3 -- transitiveOnly))
|
||||
stage3
|
||||
}
|
||||
|
||||
|
||||
def invalidateStage2(dependsOnSrc: File => Set[File], initial: Set[File], log: Logger): Set[File] =
|
||||
{
|
||||
val initAndImmediate = initial ++ initial.flatMap(dependsOnSrc)
|
||||
|
|
@ -206,6 +231,22 @@ object Incremental
|
|||
|
||||
def orEmpty(o: Option[Source]): Source = o getOrElse APIs.emptySource
|
||||
def orTrue(o: Option[Boolean]): Boolean = o getOrElse true
|
||||
|
||||
private[this] def transitiveDepsOnly[T](nodes: Iterable[T])(dependencies: T => Iterable[T]): Set[T] =
|
||||
{
|
||||
val xs = new collection.mutable.HashSet[T]
|
||||
def all(ns: Iterable[T]): Unit = ns.foreach(visit)
|
||||
def visit(n: T): Unit =
|
||||
if (!xs.contains(n)) {
|
||||
xs += n
|
||||
all(dependencies(n))
|
||||
}
|
||||
all(nodes)
|
||||
xs --= nodes
|
||||
xs.toSet
|
||||
}
|
||||
|
||||
|
||||
// unmodifiedSources should not contain any sources in the previous compilation run
|
||||
// (this may unnecessarily invalidate them otherwise)
|
||||
/*def scopeInvalidation(previous: Analysis, otherSources: Set[File], names: NameChanges): Set[File] =
|
||||
|
|
|
|||
Loading…
Reference in New Issue