mirror of https://github.com/sbt/sbt.git
Merge remote-tracking branch 'gkossakowski/separate-dependency-phase' into 0.13
This commit is contained in:
commit
7bcc00f637
|
|
@ -151,9 +151,6 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
|
||||||
apis(sourceFile) = (HashAPI(source), savedSource)
|
apis(sourceFile) = (HashAPI(source), savedSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
def endSource(sourcePath: File): Unit =
|
|
||||||
assert(apis.contains(sourcePath))
|
|
||||||
|
|
||||||
def get: Analysis = addCompilation( addExternals( addBinaries( addProducts( addSources(Analysis.Empty) ) ) ) )
|
def get: Analysis = addCompilation( addExternals( addBinaries( addProducts( addSources(Analysis.Empty) ) ) ) )
|
||||||
def addProducts(base: Analysis): Analysis = addAll(base, classes) { case (a, src, (prod, name)) => a.addProduct(src, prod, current product prod, name ) }
|
def addProducts(base: Analysis): Analysis = addAll(base, classes) { case (a, src, (prod, name)) => a.addProduct(src, prod, current product prod, name ) }
|
||||||
def addBinaries(base: Analysis): Analysis = addAll(base, binaryDeps)( (a, src, bin) => a.addBinaryDep(src, bin, binaryClassName(bin), current binary bin) )
|
def addBinaries(base: Analysis): Analysis = addAll(base, binaryDeps)( (a, src, bin) => a.addBinaryDep(src, bin, binaryClassName(bin), current binary bin) )
|
||||||
|
|
@ -178,6 +175,4 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
|
||||||
(outer /: bs) { (inner, b) =>
|
(outer /: bs) { (inner, b) =>
|
||||||
f(inner, a, b)
|
f(inner, a, b)
|
||||||
} }
|
} }
|
||||||
|
|
||||||
def beginSource(source: File) {}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,40 +23,13 @@ final class Analyzer(val global: CallbackGlobal) extends LocateClassFile
|
||||||
def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev)
|
def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev)
|
||||||
private class AnalyzerPhase(prev: Phase) extends Phase(prev)
|
private class AnalyzerPhase(prev: Phase) extends Phase(prev)
|
||||||
{
|
{
|
||||||
override def description = "Extracts dependency information, finds concrete instances of provided superclasses, and application entry points."
|
override def description = "Finds concrete instances of provided superclasses, and application entry points."
|
||||||
def name = Analyzer.name
|
def name = Analyzer.name
|
||||||
def run
|
def run
|
||||||
{
|
{
|
||||||
for(unit <- currentRun.units if !unit.isJava)
|
for(unit <- currentRun.units if !unit.isJava)
|
||||||
{
|
{
|
||||||
// build dependencies structure
|
|
||||||
val sourceFile = unit.source.file.file
|
val sourceFile = unit.source.file.file
|
||||||
callback.beginSource(sourceFile)
|
|
||||||
for(on <- unit.depends) processDependency(on, inherited=false)
|
|
||||||
for(on <- inheritedDependencies.getOrElse(sourceFile, Nil: Iterable[Symbol])) processDependency(on, inherited=true)
|
|
||||||
def processDependency(on: Symbol, inherited: Boolean)
|
|
||||||
{
|
|
||||||
def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile, inherited)
|
|
||||||
val onSource = on.sourceFile
|
|
||||||
if(onSource == null)
|
|
||||||
{
|
|
||||||
classFile(on) match
|
|
||||||
{
|
|
||||||
case Some((f,className,inOutDir)) =>
|
|
||||||
if(inOutDir && on.isJavaDefined) registerTopLevelSym(on)
|
|
||||||
f match
|
|
||||||
{
|
|
||||||
case ze: ZipArchive#Entry => for(zip <- ze.underlyingSource; zipFile <- Option(zip.file) ) binaryDependency(zipFile, className)
|
|
||||||
case pf: PlainFile => binaryDependency(pf.file, className)
|
|
||||||
case _ => ()
|
|
||||||
}
|
|
||||||
case None => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
callback.sourceDependency(onSource.file, sourceFile, inherited)
|
|
||||||
}
|
|
||||||
|
|
||||||
// build list of generated classes
|
// build list of generated classes
|
||||||
for(iclass <- unit.icode)
|
for(iclass <- unit.icode)
|
||||||
{
|
{
|
||||||
|
|
@ -75,10 +48,8 @@ final class Analyzer(val global: CallbackGlobal) extends LocateClassFile
|
||||||
else
|
else
|
||||||
addGenerated(false)
|
addGenerated(false)
|
||||||
}
|
}
|
||||||
callback.endSource(sourceFile)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,26 @@ private final class CachedCompiler0(args: Array[String], output: Output, initial
|
||||||
def newPhase(prev: Phase) = analyzer.newPhase(prev)
|
def newPhase(prev: Phase) = analyzer.newPhase(prev)
|
||||||
def name = phaseName
|
def name = phaseName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Phase that extracts dependency information */
|
||||||
|
object sbtDependency extends
|
||||||
|
{
|
||||||
|
val global: Compiler.this.type = Compiler.this
|
||||||
|
val phaseName = Dependency.name
|
||||||
|
val runsAfter = List(API.name)
|
||||||
|
override val runsBefore = List("refchecks")
|
||||||
|
// keep API and dependency close to each other
|
||||||
|
// we might want to merge them in the future and even if don't
|
||||||
|
// do that then it makes sense to run those phases next to each other
|
||||||
|
val runsRightAfter = Some(API.name)
|
||||||
|
}
|
||||||
|
with SubComponent
|
||||||
|
{
|
||||||
|
val dependency = new Dependency(global)
|
||||||
|
def newPhase(prev: Phase) = dependency.newPhase(prev)
|
||||||
|
def name = phaseName
|
||||||
|
}
|
||||||
|
|
||||||
/** This phase walks trees and constructs a representation of the public API, which is used for incremental recompilation.
|
/** This phase walks trees and constructs a representation of the public API, which is used for incremental recompilation.
|
||||||
*
|
*
|
||||||
* We extract the api after picklers, since that way we see the same symbol information/structure
|
* We extract the api after picklers, since that way we see the same symbol information/structure
|
||||||
|
|
@ -202,6 +222,7 @@ private final class CachedCompiler0(args: Array[String], output: Output, initial
|
||||||
override lazy val phaseDescriptors =
|
override lazy val phaseDescriptors =
|
||||||
{
|
{
|
||||||
phasesSet += sbtAnalyzer
|
phasesSet += sbtAnalyzer
|
||||||
|
phasesSet += sbtDependency
|
||||||
phasesSet += apiExtractor
|
phasesSet += apiExtractor
|
||||||
superComputePhaseDescriptors
|
superComputePhaseDescriptors
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
/* sbt -- Simple Build Tool
|
||||||
|
* Copyright 2008, 2009 Mark Harrah
|
||||||
|
*/
|
||||||
|
package xsbt
|
||||||
|
|
||||||
|
import scala.tools.nsc.{io, symtab, Phase}
|
||||||
|
import io.{AbstractFile, PlainFile, ZipArchive}
|
||||||
|
import symtab.Flags
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object Dependency
|
||||||
|
{
|
||||||
|
def name = "xsbt-dependency"
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extracts dependency information from each compilation unit.
|
||||||
|
*
|
||||||
|
* This phase uses CompilationUnit.depends and CallbackGlobal.inheritedDependencies
|
||||||
|
* to collect all symbols that given compilation unit depends on. Those symbols are
|
||||||
|
* guaranteed to represent Class-like structures.
|
||||||
|
*
|
||||||
|
* The CallbackGlobal.inheritedDependencies is populated by the API phase. See,
|
||||||
|
* ExtractAPI class.
|
||||||
|
*
|
||||||
|
* When dependency symbol is processed, it is mapped back to either source file where
|
||||||
|
* it's defined in (if it's available in current compilation run) or classpath entry
|
||||||
|
* where it originates from. The Symbol->Classfile mapping is implemented by
|
||||||
|
* LocateClassFile that we inherit from.
|
||||||
|
*/
|
||||||
|
final class Dependency(val global: CallbackGlobal) extends LocateClassFile
|
||||||
|
{
|
||||||
|
import global._
|
||||||
|
|
||||||
|
def newPhase(prev: Phase): Phase = new DependencyPhase(prev)
|
||||||
|
private class DependencyPhase(prev: Phase) extends Phase(prev)
|
||||||
|
{
|
||||||
|
override def description = "Extracts dependency information"
|
||||||
|
def name = Dependency.name
|
||||||
|
def run
|
||||||
|
{
|
||||||
|
for(unit <- currentRun.units if !unit.isJava)
|
||||||
|
{
|
||||||
|
// build dependencies structure
|
||||||
|
val sourceFile = unit.source.file.file
|
||||||
|
for(on <- unit.depends) processDependency(on, inherited=false)
|
||||||
|
for(on <- inheritedDependencies.getOrElse(sourceFile, Nil: Iterable[Symbol])) processDependency(on, inherited=true)
|
||||||
|
def processDependency(on: Symbol, inherited: Boolean)
|
||||||
|
{
|
||||||
|
def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile, inherited)
|
||||||
|
val onSource = on.sourceFile
|
||||||
|
if(onSource == null)
|
||||||
|
{
|
||||||
|
classFile(on) match
|
||||||
|
{
|
||||||
|
case Some((f,className,inOutDir)) =>
|
||||||
|
if(inOutDir && on.isJavaDefined) registerTopLevelSym(on)
|
||||||
|
f match
|
||||||
|
{
|
||||||
|
case ze: ZipArchive#Entry => for(zip <- ze.underlyingSource; zipFile <- Option(zip.file) ) binaryDependency(zipFile, className)
|
||||||
|
case pf: PlainFile => binaryDependency(pf.file, className)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
case None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
callback.sourceDependency(onSource.file, sourceFile, inherited)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -7,8 +7,6 @@ import java.io.File;
|
||||||
|
|
||||||
public interface AnalysisCallback
|
public interface AnalysisCallback
|
||||||
{
|
{
|
||||||
/** Called before the source at the given location is processed. */
|
|
||||||
public void beginSource(File source);
|
|
||||||
/** Called to indicate that the source file <code>source</code> depends on the source file
|
/** Called to indicate that the source file <code>source</code> depends on the source file
|
||||||
* <code>dependsOn</code>. Note that only source files included in the current compilation will
|
* <code>dependsOn</code>. Note that only source files included in the current compilation will
|
||||||
* passed to this method. Dependencies on classes generated by sources not in the current compilation will
|
* passed to this method. Dependencies on classes generated by sources not in the current compilation will
|
||||||
|
|
@ -24,8 +22,6 @@ public interface AnalysisCallback
|
||||||
/** Called to indicate that the source file <code>source</code> produces a class file at
|
/** Called to indicate that the source file <code>source</code> produces a class file at
|
||||||
* <code>module</code> contain class <code>name</code>.*/
|
* <code>module</code> contain class <code>name</code>.*/
|
||||||
public void generatedClass(File source, File module, String name);
|
public void generatedClass(File source, File module, String name);
|
||||||
/** Called after the source at the given location has been processed. */
|
|
||||||
public void endSource(File sourcePath);
|
|
||||||
/** Called when the public API of a source file is extracted. */
|
/** Called when the public API of a source file is extracted. */
|
||||||
public void api(File sourceFile, xsbti.api.SourceAPI source);
|
public void api(File sourceFile, xsbti.api.SourceAPI source);
|
||||||
/** Provides problems discovered during compilation. These may be reported (logged) or unreported.
|
/** Provides problems discovered during compilation. These may be reported (logged) or unreported.
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,14 @@ package xsbti
|
||||||
|
|
||||||
class TestCallback extends AnalysisCallback
|
class TestCallback extends AnalysisCallback
|
||||||
{
|
{
|
||||||
val beganSources = new ArrayBuffer[File]
|
|
||||||
val endedSources = new ArrayBuffer[File]
|
|
||||||
val sourceDependencies = new ArrayBuffer[(File, File, Boolean)]
|
val sourceDependencies = new ArrayBuffer[(File, File, Boolean)]
|
||||||
val binaryDependencies = new ArrayBuffer[(File, String, File, Boolean)]
|
val binaryDependencies = new ArrayBuffer[(File, String, File, Boolean)]
|
||||||
val products = new ArrayBuffer[(File, File, String)]
|
val products = new ArrayBuffer[(File, File, String)]
|
||||||
val apis = new ArrayBuffer[(File, xsbti.api.SourceAPI)]
|
val apis = new ArrayBuffer[(File, xsbti.api.SourceAPI)]
|
||||||
|
|
||||||
def beginSource(source: File) { beganSources += source }
|
|
||||||
|
|
||||||
def sourceDependency(dependsOn: File, source: File, inherited: Boolean) { sourceDependencies += ((dependsOn, source, inherited)) }
|
def sourceDependency(dependsOn: File, source: File, inherited: Boolean) { sourceDependencies += ((dependsOn, source, inherited)) }
|
||||||
def binaryDependency(binary: File, name: String, source: File, inherited: Boolean) { binaryDependencies += ((binary, name, source, inherited)) }
|
def binaryDependency(binary: File, name: String, source: File, inherited: Boolean) { binaryDependencies += ((binary, name, source, inherited)) }
|
||||||
def generatedClass(source: File, module: File, name: String) { products += ((source, module, name)) }
|
def generatedClass(source: File, module: File, name: String) { products += ((source, module, name)) }
|
||||||
def endSource(source: File) { endedSources += source }
|
|
||||||
|
|
||||||
def api(source: File, sourceAPI: xsbti.api.SourceAPI) { apis += ((source, sourceAPI)) }
|
def api(source: File, sourceAPI: xsbti.api.SourceAPI) { apis += ((source, sourceAPI)) }
|
||||||
def problem(category: String, pos: xsbti.Position, message: String, severity: xsbti.Severity, reported: Boolean) {}
|
def problem(category: String, pos: xsbti.Position, message: String, severity: xsbti.Severity, reported: Boolean) {}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ private[sbt] object Analyze
|
||||||
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.getName);
|
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.getName);
|
||||||
source <- guessSourcePath(sourceMap, classFile, log))
|
source <- guessSourcePath(sourceMap, classFile, log))
|
||||||
{
|
{
|
||||||
analysis.beginSource(source)
|
|
||||||
analysis.generatedClass(source, newClass, classFile.className)
|
analysis.generatedClass(source, newClass, classFile.className)
|
||||||
productToSource(newClass) = source
|
productToSource(newClass) = source
|
||||||
sourceToClassFiles.getOrElseUpdate(source, new ArrayBuffer[ClassFile]) += classFile
|
sourceToClassFiles.getOrElseUpdate(source, new ArrayBuffer[ClassFile]) += classFile
|
||||||
|
|
@ -69,13 +68,10 @@ private[sbt] object Analyze
|
||||||
val notInherited = classFiles.flatMap(_.types).toSet -- publicInherited
|
val notInherited = classFiles.flatMap(_.types).toSet -- publicInherited
|
||||||
processDependencies(notInherited, false)
|
processDependencies(notInherited, false)
|
||||||
processDependencies(publicInherited, true)
|
processDependencies(publicInherited, true)
|
||||||
analysis.endSource(source)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for( source <- sources filterNot sourceToClassFiles.keySet ) {
|
for( source <- sources filterNot sourceToClassFiles.keySet ) {
|
||||||
analysis.beginSource(source)
|
|
||||||
analysis.api(source, new xsbti.api.SourceAPI(Array(), Array()))
|
analysis.api(source, new xsbti.api.SourceAPI(Array(), Array()))
|
||||||
analysis.endSource(source)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private[this] def urlAsFile(url: URL, log: Logger): Option[File] =
|
private[this] def urlAsFile(url: URL, log: Logger): Option[File] =
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue