summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiles Sabin <miles@milessabin.com>2009-08-02 18:01:22 +0000
committerMiles Sabin <miles@milessabin.com>2009-08-02 18:01:22 +0000
commitd339959ff129d9c3ccabad25d924618d21b7a471 (patch)
treeea1ca1aa197c9152da29ede1dd528735e8c2e20b
parent11ee847d384dcd0f45295380809f66961ebe25a3 (diff)
downloadscala-d339959ff129d9c3ccabad25d924618d21b7a471.tar.gz
scala-d339959ff129d9c3ccabad25d924618d21b7a471.tar.bz2
scala-d339959ff129d9c3ccabad25d924618d21b7a471.zip
More work on build manager.
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala35
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala42
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/Files.scala69
-rw-r--r--src/compiler/scala/tools/nsc/interactive/BuildManager.scala5
-rw-r--r--src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala106
-rw-r--r--src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala11
6 files changed, 150 insertions, 118 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 20053d112b..9ceb470565 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -221,7 +221,27 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
case x =>
val jfile = new java.io.File(x)
if (!jfile.exists) jfile.createNewFile
- else dependencyAnalysis.loadFrom(AbstractFile.getFile(jfile))
+ else {
+ // This logic moved here from scala.tools.nsc.dependencies.File.
+ // Note that it will trip an assertion in lookupPathUnchecked
+ // if the path being looked at is absolute.
+
+ /** The directory where file lookup should start at. */
+ val rootDirectory: AbstractFile = {
+ AbstractFile.getDirectory(".")
+// val roots = java.io.File.listRoots()
+// assert(roots.length > 0)
+// new PlainFile(roots(0))
+ }
+
+ def toFile(path: String) = {
+ val file = rootDirectory.lookupPathUnchecked(path, false)
+ assert(file ne null, path)
+ file
+ }
+
+ dependencyAnalysis.loadFrom(AbstractFile.getFile(jfile), toFile)
+ }
}
lazy val classPath0 = new ClassPath(false && onlyPresentation)
@@ -830,8 +850,17 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
for ((sym, file) <- symSource.iterator) resetPackageClass(sym.owner)
informTime("total", startTime)
- if (!dependencyAnalysis.off)
- dependencyAnalysis.saveDependencies()
+ if (!dependencyAnalysis.off) {
+
+ def fromFile(file: AbstractFile): String = {
+ val path = file.path
+ if (path.startsWith("./"))
+ path.substring(2, path.length)
+ else path
+ }
+
+ dependencyAnalysis.saveDependencies(fromFile)
+ }
}
/** Compile list of abstract files */
diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
index b6ad064f0f..ec1bacfd59 100644
--- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
@@ -38,6 +38,8 @@ trait DependencyAnalysis extends SubComponent with Files {
var dependencies = newDeps
+ def managedFiles = dependencies.dependencies.keySet
+
/** Top level definitions per source file. */
val definitions: mutable.Map[AbstractFile, List[Symbol]] =
new mutable.HashMap[AbstractFile, List[Symbol]] {
@@ -45,28 +47,34 @@ trait DependencyAnalysis extends SubComponent with Files {
}
/** External references used by source file. */
- var references: immutable.Map[AbstractFile, immutable.Set[String]] =
- new immutable.HashMap[AbstractFile, immutable.Set[String]] {
+ val references: mutable.Map[AbstractFile, immutable.Set[String]] =
+ new mutable.HashMap[AbstractFile, immutable.Set[String]] {
override def default(f : AbstractFile) = immutable.Set()
}
/** Write dependencies to the current file. */
- def saveDependencies() =
+ def saveDependencies(fromFile: AbstractFile => String) =
if(dependenciesFile.isDefined)
- dependencies.writeTo(dependenciesFile.get)
+ dependencies.writeTo(dependenciesFile.get, fromFile)
/** Load dependencies from the given file and save the file reference for
* future saves.
*/
- def loadFrom(f: AbstractFile) {
+ def loadFrom(f: AbstractFile, toFile: String => AbstractFile) : Boolean = {
dependenciesFile = f
- val fd = FileDependencies.readFrom(f);
- dependencies = if (fd.classpath != classpath) {
- if(settings.debug.value){
- println("Classpath has changed. Nuking dependencies");
- }
- newDeps
- } else fd
+ FileDependencies.readFrom(f, toFile) match {
+ case Some(fd) =>
+ val success = fd.classpath == classpath
+ dependencies = if (success) fd else {
+ if(settings.debug.value){
+ println("Classpath has changed. Nuking dependencies");
+ }
+ newDeps
+ }
+
+ success
+ case None => false
+ }
}
def filter(files : List[SourceFile]) : List[SourceFile] =
@@ -80,7 +88,7 @@ trait DependencyAnalysis extends SubComponent with Files {
else {
val (direct, indirect) = dependencies.invalidatedFiles(maxDepth);
val filtered = files.filter(x => {
- val f = x.path.absolute;
+ val f = x.file.absolute
direct(f) || indirect(f) || !dependencies.containsFile(f);
})
filtered match {
@@ -102,7 +110,11 @@ trait DependencyAnalysis extends SubComponent with Files {
if (f != null){
val source: AbstractFile = unit.source.file;
for (d <- unit.icode){
- dependencies.emits(source, nameToFile(unit.source.file, d.toString))
+ val name = d.symbol match {
+ case _ : ModuleClassSymbol => d.toString+"$"
+ case _ => d.toString
+ }
+ dependencies.emits(source, nameToFile(unit.source.file, name))
}
for (d <- unit.depends; if (d.sourceFile != null)){
@@ -124,7 +136,7 @@ trait DependencyAnalysis extends SubComponent with Files {
&& (!tree.symbol.hasFlag(Flags.JAVA))
&& ((tree.symbol.sourceFile eq null)
|| (tree.symbol.sourceFile.path != file.path))) {
- references = references.updated(file, references(file) + tree.symbol.fullNameString)
+ references += file -> (references(file) + tree.symbol.fullNameString)
}
tree match {
case cdef: ClassDef if !cdef.symbol.isModuleClass && !cdef.symbol.hasFlag(Flags.PACKAGE) =>
diff --git a/src/compiler/scala/tools/nsc/dependencies/Files.scala b/src/compiler/scala/tools/nsc/dependencies/Files.scala
index b4852ee0ce..501936ee4e 100644
--- a/src/compiler/scala/tools/nsc/dependencies/Files.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/Files.scala
@@ -6,22 +6,7 @@ import io.{AbstractFile, PlainFile}
import scala.collection._;
-trait Files {
-
- /** Resolve the given name to a file. */
- implicit def toFile(name: String): AbstractFile = {
- val file = rootDirectory.lookupPathUnchecked(name, false)
- assert(file ne null, name)
- file
- }
-
- /** The directory where file lookup should start at. */
- var rootDirectory: AbstractFile = {
- AbstractFile.getDirectory(".")
-// val roots = java.io.File.listRoots()
-// assert(roots.length > 0)
-// new PlainFile(roots(0))
- }
+trait Files { self : SubComponent =>
class FileDependencies(val classpath : String) {
@@ -73,7 +58,7 @@ trait Files {
(direct, indirect);
}
- /** Return the sef of files that depend on the given changed files.
+ /** Return the set of files that depend on the given changed files.
* It computes the transitive closure up to the given depth.
*/
def dependentFiles(depth: Int, changed: Set[AbstractFile]): Set[AbstractFile] = {
@@ -99,21 +84,16 @@ trait Files {
indirect --= changed
}
- def writeTo(file: AbstractFile) {
- writeToFile(file)(out => writeTo(new PrintStream(out)))
+ def writeTo(file: AbstractFile, fromFile : AbstractFile => String) {
+ writeToFile(file)(out => writeTo(new PrintStream(out), fromFile))
}
- def writeTo(print : PrintStream) : Unit = {
- def prettify(path: String): String =
- if (path.startsWith("./"))
- path.substring(2, path.length)
- else path
-
+ def writeTo(print : PrintStream, fromFile : AbstractFile => String) : Unit = {
cleanEmpty();
def emit(tracker : Tracker){
for ((f, ds) <- tracker;
d <- ds){
- print.println(prettify(f.toString) + " -> " + prettify(d.toString));
+ print.println(fromFile(f) + " -> " + fromFile(d));
}
}
@@ -126,52 +106,47 @@ trait Files {
}
}
-
-
object FileDependencies{
val Separator = "-------";
- def readFrom(file: AbstractFile): FileDependencies = readFromFile(file) { in =>
- val reader = new BufferedReader(new InputStreamReader(in));
- val it = new FileDependencies(reader.readLine);
- reader.readLine;
- var line : String = null;
+ def readFrom(file: AbstractFile, toFile : String => AbstractFile): Option[FileDependencies] = readFromFile(file) { in =>
+ val reader = new BufferedReader(new InputStreamReader(in))
+ val it = new FileDependencies(reader.readLine)
+ reader.readLine
+ var line : String = null
while ({line = reader.readLine; (line != null) && (line != Separator)}){
line.split(" -> ") match {
- case Array(from, on) => it.depends(from, on);
- case x => error("Parse error: Unrecognised string " + line);
- };
+ case Array(from, on) => it.depends(toFile(from), toFile(on));
+ case x => global.inform("Parse error: Unrecognised string " + line); return None
+ }
}
while ({line = reader.readLine; (line != null) && (line != Separator)}){
line.split(" -> ") match {
- case Array(source, target) => it.emits(source, target);
- case x => error("Parse error: Unrecognised string " + line);
- };
+ case Array(source, target) => it.emits(toFile(source), toFile(target));
+ case x => global.inform("Parse error: Unrecognised string " + line); return None
+ }
}
- it;
+ Some(it)
}
}
-
def writeToFile[T](file: AbstractFile)(f: OutputStream => T) : T = {
val out = file.output
try {
- f(out);
+ f(out)
} finally {
- out.close;
+ out.close
}
}
def readFromFile[T](file: AbstractFile)(f: InputStream => T) : T = {
val in = file.input
try{
- f(in);
+ f(in)
} finally {
- in.close;
+ in.close
}
}
}
-
-object Files extends Files;
diff --git a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala
index 0b35920ca2..3512d17bb8 100644
--- a/src/compiler/scala/tools/nsc/interactive/BuildManager.scala
+++ b/src/compiler/scala/tools/nsc/interactive/BuildManager.scala
@@ -26,16 +26,15 @@ trait BuildManager {
def buildingFiles(included: Set[AbstractFile]) {}
/** Load saved dependency information. */
- def loadFrom(file: AbstractFile)
+ def loadFrom(file: AbstractFile, toFile: String => AbstractFile) : Boolean
/** Save dependency information to `file'. */
- def saveTo(file: AbstractFile)
+ def saveTo(file: AbstractFile, fromFile: AbstractFile => String)
def compiler: scala.tools.nsc.Global
}
-
/** Simple driver for testing the build manager. It presents
* the user to a 'resident compiler' prompt. Each line is
* interpreted as a set of files that have changed. The builder
diff --git a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
index c0849065f6..c07cb62277 100644
--- a/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
+++ b/src/compiler/scala/tools/nsc/interactive/RefinedBuildManager.scala
@@ -41,7 +41,7 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
}
/** External references used by source file. */
- private var references: immutable.Map[AbstractFile, immutable.Set[String]] = _
+ private var references: mutable.Map[AbstractFile, immutable.Set[String]] = _
/** Add the given source files to the managed build process. */
def addSourceFiles(files: Set[AbstractFile]) {
@@ -114,60 +114,71 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
break
}
- for ((oldSym, changes) <- changesOf; change <- changes) {
+ // changesOf will be empty just after initialization with a saved
+ // dependencies file.
+ if (changesOf.isEmpty)
+ buf ++= directDeps
+ else {
+ for ((oldSym, changes) <- changesOf; change <- changes) {
- def checkParents(cls: Symbol, file: AbstractFile) {
- val parentChange = cls.info.parents.exists(_.typeSymbol.fullNameString == oldSym.fullNameString)
-// println("checkParents " + cls + " oldSym: " + oldSym + " parentChange: " + parentChange + " " + cls.info.parents)
- change match {
- case Changed(Class(_)) if parentChange =>
- invalidate(file, "parents have changed", change)
+ def checkParents(cls: Symbol, file: AbstractFile) {
+ val parentChange = cls.info.parents.exists(_.typeSymbol.fullNameString == oldSym.fullNameString)
+// println("checkParents " + cls + " oldSym: " + oldSym + " parentChange: " + parentChange + " " + cls.info.parents)
+ change match {
+ case Changed(Class(_)) if parentChange =>
+ invalidate(file, "parents have changed", change)
- case Added(Definition(_)) if parentChange =>
- invalidate(file, "inherited new method", change)
+ case Added(Definition(_)) if parentChange =>
+ invalidate(file, "inherited new method", change)
- case Removed(Definition(_)) if parentChange =>
- invalidate(file, "inherited method removed", change)
+ case Removed(Definition(_)) if parentChange =>
+ invalidate(file, "inherited method removed", change)
- case _ => ()
+ case _ => ()
+ }
}
- }
- def checkInterface(cls: Symbol, file: AbstractFile) {
- change match {
- case Added(Definition(name)) =>
- if (cls.info.decls.iterator.exists(_.fullNameString == name))
- invalidate(file, "of new method with existing name", change)
- case Changed(Class(name)) =>
- if (cls.info.typeSymbol.fullNameString == name)
- invalidate(file, "self type changed", change)
- case _ =>
- ()
+ def checkInterface(cls: Symbol, file: AbstractFile) {
+ change match {
+ case Added(Definition(name)) =>
+ if (cls.info.decls.iterator.exists(_.fullNameString == name))
+ invalidate(file, "of new method with existing name", change)
+ case Changed(Class(name)) =>
+ if (cls.info.typeSymbol.fullNameString == name)
+ invalidate(file, "self type changed", change)
+ case _ =>
+ ()
+ }
}
- }
- def checkReferences(file: AbstractFile) {
-// println(file + ":" + references(file))
- val refs = references(file)
- change match {
- case Removed(Definition(name)) if refs(name) =>
- invalidate(file, " it references deleted definition", change)
- case Removed(Class(name)) if (refs(name)) =>
- invalidate(file, " it references deleted class", change)
- case Changed(Definition(name)) if (refs(name)) =>
- invalidate(file, " it references changed definition", change)
- case _ => ()
+ def checkReferences(file: AbstractFile) {
+// println(file + ":" + references(file))
+ val refs = references(file)
+ if (refs.isEmpty)
+ invalidate(file, "it is a direct dependency and we don't yet have finer-grained dependency information", change)
+ else {
+ change match {
+ case Removed(Definition(name)) if refs(name) =>
+ invalidate(file, "it references deleted definition", change)
+ case Removed(Class(name)) if (refs(name)) =>
+ invalidate(file, "it references deleted class", change)
+ case Changed(Definition(name)) if (refs(name)) =>
+ invalidate(file, "it references changed definition", change)
+ case _ => ()
+ }
+ }
}
- }
- breakable {
- for (file <- directDeps) {
- for (cls <- definitions(file)) checkParents(cls, file)
- for (cls <- definitions(file)) checkInterface(cls, file)
- checkReferences(file)
+ breakable {
+ for (file <- directDeps) {
+ for (cls <- definitions(file)) checkParents(cls, file)
+ for (cls <- definitions(file)) checkInterface(cls, file)
+ checkReferences(file)
+ }
}
}
}
+
buf
}
@@ -180,13 +191,16 @@ class RefinedBuildManager(val settings: Settings) extends Changes with BuildMana
}
/** Load saved dependency information. */
- def loadFrom(file: AbstractFile) {
- compiler.dependencyAnalysis.loadFrom(file)
+ def loadFrom(file: AbstractFile, toFile: String => AbstractFile) : Boolean = {
+ val success = compiler.dependencyAnalysis.loadFrom(file, toFile)
+ if (success)
+ sources ++= compiler.dependencyAnalysis.managedFiles
+ success
}
/** Save dependency information to `file'. */
- def saveTo(file: AbstractFile) {
+ def saveTo(file: AbstractFile, fromFile: AbstractFile => String) {
compiler.dependencyAnalysis.dependenciesFile = file
- compiler.dependencyAnalysis.saveDependencies()
+ compiler.dependencyAnalysis.saveDependencies(fromFile)
}
}
diff --git a/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala b/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala
index 37ed782868..9ecf51ae42 100644
--- a/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala
+++ b/src/compiler/scala/tools/nsc/interactive/SimpleBuildManager.scala
@@ -68,13 +68,16 @@ class SimpleBuildManager(val settings: Settings) extends BuildManager {
}
/** Load saved dependency information. */
- def loadFrom(file: AbstractFile) {
- compiler.dependencyAnalysis.loadFrom(file)
+ def loadFrom(file: AbstractFile, toFile: String => AbstractFile) : Boolean = {
+ val success = compiler.dependencyAnalysis.loadFrom(file, toFile)
+ if (success)
+ sources ++= compiler.dependencyAnalysis.managedFiles
+ success
}
/** Save dependency information to `file'. */
- def saveTo(file: AbstractFile) {
+ def saveTo(file: AbstractFile, fromFile: AbstractFile => String) {
compiler.dependencyAnalysis.dependenciesFile = file
- compiler.dependencyAnalysis.saveDependencies()
+ compiler.dependencyAnalysis.saveDependencies(fromFile)
}
}