From b28d0361d7663d69555df3e733f65200295e2e86 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Fri, 21 May 2010 18:48:14 -0400 Subject: [PATCH 1/5] new method FileUtilities.stash --- util/io/FileUtilities.scala | 32 ++++++++++ util/io/src/test/scala/StashSpec.scala | 81 ++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 util/io/src/test/scala/StashSpec.scala diff --git a/util/io/FileUtilities.scala b/util/io/FileUtilities.scala index db879d5ad..0f4064be3 100644 --- a/util/io/FileUtilities.scala +++ b/util/io/FileUtilities.scala @@ -407,4 +407,36 @@ object FileUtilities /** Splits a String around path separator characters. */ def pathSplit(s: String) = PathSeparatorPattern.split(s) + + /** Move the provided files to a temporary location. + * If 'f' returns normally, delete the files. + * If 'f' throws an Exception, return the files to their original location.*/ + def stash[T](files: Set[File])(f: => T): T = + withTemporaryDirectory { dir => + val stashed = stashLocations(dir, files.toArray) + move(stashed) + + try { f } catch { case e: Exception => + try { move(stashed.map(_.swap)); throw e } + catch { case _: Exception => throw e } + } + } + + private def stashLocations(dir: File, files: Array[File]) = + for( (file, index) <- files.zipWithIndex) yield + (file, new File(dir, index.toHexString)) + + def move(files: Iterable[(File, File)]): Unit = + files.foreach(Function.tupled(move)) + + def move(a: File, b: File): Unit = + { + if(b.exists) + delete(b) + if(!a.renameTo(b)) + { + copyFile(a, b) + delete(a) + } + } } diff --git a/util/io/src/test/scala/StashSpec.scala b/util/io/src/test/scala/StashSpec.scala new file mode 100644 index 000000000..df76165d2 --- /dev/null +++ b/util/io/src/test/scala/StashSpec.scala @@ -0,0 +1,81 @@ +/* sbt -- Simple Build Tool + * Copyright 2010 Mark Harrah */ + +package xsbt + +import org.specs._ + +import FileUtilities._ +import java.io.File +import Function.tupled + +object CheckStash extends Specification +{ + "stash" should { + "handle empty files" in { + stash(Set()) { } + } + + "move files during execution" in { + WithFiles(TestFiles : _*) ( checkMove ) + } + + "restore files on exceptions but not errors" in { + WithFiles(TestFiles : _*) ( checkRestore ) + } + } + + def checkRestore(seq: Seq[File]) + { + allCorrect(seq) + + stash0(seq, throw new TestRuntimeException) must beFalse + allCorrect(seq) + + stash0(seq, throw new TestException) must beFalse + allCorrect(seq) + + stash0(seq, throw new TestError) must beFalse + noneExist(seq) + } + def checkMove(seq: Seq[File]) + { + allCorrect(seq) + stash0(seq, ()) must beTrue + noneExist(seq) + } + def stash0(seq: Seq[File], post: => Unit): Boolean = + try + { + stash(Set() ++ seq) { + noneExist(seq) + post + } + true + } + catch { + case _: TestError | _: TestException | _: TestRuntimeException => false + } + + def allCorrect(s: Seq[File]) = (s.toList zip TestFiles.toList).forall(tupled(correct)) + def correct(check: File, ref: (File, String)) = + { + check.exists must beTrue + read(check) must beEqual(ref._2) + } + def noneExist(s: Seq[File]) = s.forall(!_.exists) must beTrue + + lazy val TestFiles = + Seq( + "a/b/c" -> "content1", + "a/b/e" -> "content1", + "c" -> "", + "e/g" -> "asdf", + "a/g/c" -> "other" + ) map { + case (f, c) => (new File(f), c) + } +} +class TestError extends Error +class TestRuntimeException extends RuntimeException +class TestException extends Exception \ No newline at end of file From 85bc7a363de78fee968269e7be5593445386cdb6 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Thu, 27 May 2010 21:15:16 -0400 Subject: [PATCH 2/5] fix provided configuration --- .../main/scala/sbt/BasicProjectTypes.scala | 17 ++++----------- .../provided-multi/changes/A.scala | 6 ++++++ .../provided-multi/changes/B.scala | 6 ++++++ .../provided-multi/changes/P.scala | 19 +++++++++++++++++ .../provided-multi/project/build.properties | 2 ++ .../dependency-management/provided-multi/test | 21 +++++++++++++++++++ 6 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 sbt/src/sbt-test/dependency-management/provided-multi/changes/A.scala create mode 100644 sbt/src/sbt-test/dependency-management/provided-multi/changes/B.scala create mode 100644 sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala create mode 100644 sbt/src/sbt-test/dependency-management/provided-multi/project/build.properties create mode 100644 sbt/src/sbt-test/dependency-management/provided-multi/test diff --git a/sbt/src/main/scala/sbt/BasicProjectTypes.scala b/sbt/src/main/scala/sbt/BasicProjectTypes.scala index e8a646912..16b8b01e0 100644 --- a/sbt/src/main/scala/sbt/BasicProjectTypes.scala +++ b/sbt/src/main/scala/sbt/BasicProjectTypes.scala @@ -322,8 +322,6 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w def deliverIvyModule = newIvyModule(deliverModuleSettings) def publishModuleSettings = deliverModuleSettings def publishIvyModule = newIvyModule(publishModuleSettings) - /** True if the 'provided' configuration should be included on the 'compile' classpath. The default value is true.*/ - def includeProvidedWithCompile = true /** True if the default implicit extensions should be used when determining classpaths. The default value is true. */ def defaultConfigurationExtensions = true /** If true, verify that explicit dependencies on Scala libraries use the same version as scala.version. */ @@ -343,22 +341,15 @@ trait BasicManagedProject extends ManagedProject with ReflectiveManagedProject w case _ => None } } - /** Includes the Provided configuration on the Compile classpath, the Compile configuration on the Runtime classpath, - * and Compile and Runtime on the Test classpath. Including Provided can be disabled by setting - * includeProvidedWithCompile to false. Including Compile and Runtime can be disabled by setting - * defaultConfigurationExtensions to false.*/ + /** Includes the Compile configuration on the Runtime classpath, and Compile and Runtime on the Test classpath. + * Including Compile and Runtime can be disabled by setting defaultConfigurationExtensions to false.*/ override def managedClasspath(config: Configuration) = { - import Configurations.{Compile, CompilerPlugin, Default, Provided, Runtime, Test} + import Configurations.{Compile, Default, Runtime, Test} val baseClasspath = configurationClasspath(config) config match { - case Compile => - val baseCompileClasspath = baseClasspath +++ managedClasspath(Default) - if(includeProvidedWithCompile) - baseCompileClasspath +++ managedClasspath(Provided) - else - baseCompileClasspath + case Compile => baseClasspath +++ managedClasspath(Default) case Runtime if defaultConfigurationExtensions => baseClasspath +++ managedClasspath(Compile) case Test if defaultConfigurationExtensions => baseClasspath +++ managedClasspath(Runtime) case _ => baseClasspath diff --git a/sbt/src/sbt-test/dependency-management/provided-multi/changes/A.scala b/sbt/src/sbt-test/dependency-management/provided-multi/changes/A.scala new file mode 100644 index 000000000..40190d644 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/provided-multi/changes/A.scala @@ -0,0 +1,6 @@ +import sbinary._ + +trait A +{ + def format: Format[A] +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/provided-multi/changes/B.scala b/sbt/src/sbt-test/dependency-management/provided-multi/changes/B.scala new file mode 100644 index 000000000..3519cbacb --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/provided-multi/changes/B.scala @@ -0,0 +1,6 @@ +import sbinary._ + +trait B +{ + def format(a: A): Format[A] +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala b/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala new file mode 100644 index 000000000..37834dded --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/provided-multi/changes/P.scala @@ -0,0 +1,19 @@ +import sbt._ + +class P(info: ProjectInfo) extends ParentProject(info) +{ + val a = project("a", "A", new A(_)) + val b = project("b", "B", new B(_), a) + + def aLibrary = "org.scala-tools.sbinary" %% "sbinary" % "0.3" % "provided" + + class A(info: ProjectInfo) extends DefaultProject(info) + { + val a = aLibrary + } + class B(info: ProjectInfo) extends DefaultWebProject(info) + { + override def libraryDependencies = + if("declare.lib".asFile.exists) Set(aLibrary) else Set() + } +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/provided-multi/project/build.properties b/sbt/src/sbt-test/dependency-management/provided-multi/project/build.properties new file mode 100644 index 000000000..1960ba3b0 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/provided-multi/project/build.properties @@ -0,0 +1,2 @@ +project.name=Multi Project Provided +project.version=1.0 \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/provided-multi/test b/sbt/src/sbt-test/dependency-management/provided-multi/test new file mode 100644 index 000000000..9019dbd82 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/provided-multi/test @@ -0,0 +1,21 @@ +> set build.scala.versions 2.7.7 +$ copy-file changes/P.scala project/build/P.scala +$ copy-file changes/A.scala a/src/main/scala/A.scala +$ copy-file changes/B.scala b/src/main/scala/B.scala +> reload + +> project A +-> compile +> update +> compile + +> project B +-> compile +> update +-> compile + +$ touch b/declare.lib +> reload +-> compile +> update +> compile \ No newline at end of file From bae26e431b18130fe5e84fe8e8b7589bb5ca76f8 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 7 Jun 2010 10:50:51 -0400 Subject: [PATCH 3/5] cache updates --- cache/Cache.scala | 10 +- cache/FileInfo.scala | 15 +- cache/src/test/scala/CacheTest.scala | 21 +-- cache/tracking/Tracked.scala | 209 ++++++++++++++++----------- project/build/XSbt.scala | 7 +- 5 files changed, 151 insertions(+), 111 deletions(-) diff --git a/cache/Cache.scala b/cache/Cache.scala index 2f35d2c96..e7ba310dc 100644 --- a/cache/Cache.scala +++ b/cache/Cache.scala @@ -2,7 +2,6 @@ package xsbt import sbinary.{CollectionTypes, Format, JavaFormats} import java.io.File -import scala.reflect.Manifest trait Cache[I,O] { @@ -23,13 +22,6 @@ object Cache extends BasicCacheImplicits with SBinaryFormats with HListCacheImpl def wrapOutputCache[O,DO](implicit convert: O => DO, reverse: DO => O, base: OutputCache[DO]): OutputCache[O] = new WrappedOutputCache[O,DO](convert, reverse, base) - def apply[I,O](file: File)(f: I => Task[O])(implicit cache: Cache[I,O]): I => Task[O] = - in => - cache(file)(in) match - { - case Left(value) => Task(value) - case Right(store) => f(in) map { out => store(out); out } - } def cached[I,O](file: File)(f: I => O)(implicit cache: Cache[I,O]): I => O = in => cache(file)(in) match @@ -61,4 +53,4 @@ trait HListCacheImplicits extends HLists implicit def hConsOutputCache[H,T<:HList](implicit headCache: OutputCache[H], tailCache: OutputCache[T]): OutputCache[HCons[H,T]] = new HConsOutputCache(headCache, tailCache) implicit lazy val hNilOutputCache: OutputCache[HNil] = new HNilOutputCache -} \ No newline at end of file +} diff --git a/cache/FileInfo.scala b/cache/FileInfo.scala index 66c8c496b..d1b350fa8 100644 --- a/cache/FileInfo.scala +++ b/cache/FileInfo.scala @@ -18,8 +18,10 @@ sealed trait ModifiedFileInfo extends FileInfo { val lastModified: Long } +sealed trait PlainFileInfo extends FileInfo sealed trait HashModifiedFileInfo extends HashFileInfo with ModifiedFileInfo +private final case class PlainFile(file: File) extends PlainFileInfo private final case class FileHash(file: File, hash: List[Byte]) extends HashFileInfo private final case class FileModified(file: File, lastModified: Long) extends ModifiedFileInfo private final case class FileHashModified(file: File, hash: List[Byte], lastModified: Long) extends HashModifiedFileInfo @@ -32,8 +34,6 @@ object FileInfo implicit def apply(file: File): F implicit def unapply(info: F): File = info.file implicit val format: Format[F] - /*val manifest: Manifest[F] - def formatManifest: Manifest[Format[F]] = CacheIO.manifest[Format[F]]*/ import Cache._ implicit def infoInputCache: InputCache[File] = wrapInputCache[File,F] implicit def infoOutputCache: OutputCache[File] = wrapOutputCache[File,F] @@ -41,7 +41,6 @@ object FileInfo object full extends Style { type F = HashModifiedFileInfo - //val manifest: Manifest[F] = CacheIO.manifest[HashModifiedFileInfo] implicit def apply(file: File): HashModifiedFileInfo = make(file, Hash(file).toList, file.lastModified) def make(file: File, hash: List[Byte], lastModified: Long): HashModifiedFileInfo = FileHashModified(file.getAbsoluteFile, hash, lastModified) implicit val format: Format[HashModifiedFileInfo] = wrap(f => (f.file, f.hash, f.lastModified), tupled(make _)) @@ -49,7 +48,6 @@ object FileInfo object hash extends Style { type F = HashFileInfo - //val manifest: Manifest[F] = CacheIO.manifest[HashFileInfo] implicit def apply(file: File): HashFileInfo = make(file, computeHash(file).toList) def make(file: File, hash: List[Byte]): HashFileInfo = FileHash(file.getAbsoluteFile, hash) implicit val format: Format[HashFileInfo] = wrap(f => (f.file, f.hash), tupled(make _)) @@ -58,11 +56,17 @@ object FileInfo object lastModified extends Style { type F = ModifiedFileInfo - //val manifest: Manifest[F] = CacheIO.manifest[ModifiedFileInfo] implicit def apply(file: File): ModifiedFileInfo = make(file, file.lastModified) def make(file: File, lastModified: Long): ModifiedFileInfo = FileModified(file.getAbsoluteFile, lastModified) implicit val format: Format[ModifiedFileInfo] = wrap(f => (f.file, f.lastModified), tupled(make _)) } + object exists extends Style + { + type F = PlainFileInfo + implicit def apply(file: File): PlainFileInfo = make(file) + def make(file: File): PlainFileInfo = PlainFile(file.getAbsoluteFile) + implicit val format: Format[PlainFileInfo] = wrap(_.file, make) + } } final case class FilesInfo[F <: FileInfo] private(files: Set[F]) extends NotNull @@ -92,4 +96,5 @@ object FilesInfo lazy val full: Style = new BasicStyle(FileInfo.full) lazy val hash: Style = new BasicStyle(FileInfo.hash) lazy val lastModified: Style = new BasicStyle(FileInfo.lastModified) + lazy val exists: Style = new BasicStyle(FileInfo.exists) } \ No newline at end of file diff --git a/cache/src/test/scala/CacheTest.scala b/cache/src/test/scala/CacheTest.scala index 7bba6ec79..65703ecaa 100644 --- a/cache/src/test/scala/CacheTest.scala +++ b/cache/src/test/scala/CacheTest.scala @@ -7,22 +7,23 @@ object CacheTest// extends Properties("Cache test") val lengthCache = new File("/tmp/length-cache") val cCache = new File("/tmp/c-cache") - import Task._ import Cache._ import FileInfo.hash._ def test { - val createTask = Task { new File("test") } + lazy val create = new File("test") - val length = (f: File) => { println("File length: " + f.length); f.length } - val cachedLength = cached(lengthCache) ( length ) + val length = cached(lengthCache) { + (f: File) => { println("File length: " + f.length); f.length } + } - val lengthTask = createTask map cachedLength + lazy val fileLength = length(create) - val c = (file: File, len: Long) => { println("File: " + file + ", length: " + len); len :: file :: HNil } - val cTask = (createTask :: lengthTask :: TNil) map cached(cCache) { case (file :: len :: HNil) => c(file, len) } - - try { TaskRunner(cTask) } - catch { case TasksFailed(failures) => failures.foreach(_.exception.printStackTrace) } + val c = cached(cCache) { (in: (File :: Long :: HNil)) => + val file :: len :: HNil = in + println("File: " + file + " (" + file.exists + "), length: " + len) + (len+1) :: file :: HNil + } + c(create :: fileLength :: HNil) } } \ No newline at end of file diff --git a/cache/tracking/Tracked.scala b/cache/tracking/Tracked.scala index f79a2a7ee..49d33c622 100644 --- a/cache/tracking/Tracked.scala +++ b/cache/tracking/Tracked.scala @@ -7,112 +7,152 @@ import java.io.{File,IOException} import CacheIO.{fromFile, toFile} import sbinary.Format import scala.reflect.Manifest -import Task.{iterableToBuilder, iterableToForkBuilder} +import xsbt.FileUtilities.{delete, read, write} + +/* A proper implementation of fileTask that tracks inputs and outputs properly + +def fileTask(cacheBaseDirectory: Path)(inputs: PathFinder, outputs: PathFinder)(action: => Unit): Task = + fileTask(cacheBaseDirectory, FilesInfo.hash, FilesInfo.lastModified) +def fileTask(cacheBaseDirectory: Path, inStyle: FilesInfo.Style, outStyle: FilesInfo.Style)(inputs: PathFinder, outputs: PathFinder)(action: => Unit): Task = +{ + lazy val inCache = diffInputs(base / "in-cache", inStyle)(inputs) + lazy val outCache = diffOutputs(base / "out-cache", outStyle)(outputs) + task + { + inCache { inReport => + outCache { outReport => + if(inReport.modified.isEmpty && outReport.modified.isEmpty) () else action + } + } + } +} +*/ + +object Tracked +{ + /** Creates a tracker that provides the last time it was evaluated. + * If 'useStartTime' is true, the recorded time is the start of the evaluated function. + * If 'useStartTime' is false, the recorded time is when the evaluated function completes. + * In both cases, the timestamp is not updated if the function throws an exception.*/ + def tstamp(cacheFile: File, useStartTime: Boolean): Timestamp = new Timestamp(cacheFile) + /** Creates a tracker that only evaluates a function when the input has changed.*/ + def changed[O](cacheFile: File)(getValue: => O)(implicit input: InputCache[O]): Changed[O] = + new Changed[O](getValue, cacheFile) + + /** Creates a tracker that provides the difference between the set of input files provided for successive invocations.*/ + def diffInputs(cache: File, style: FilesInfo.Style)(files: => Set[File]): Difference = + Difference.inputs(files, style, cache) + /** Creates a tracker that provides the difference between the set of output files provided for successive invocations.*/ + def diffOutputs(cache: File, style: FilesInfo.Style)(files: => Set[File]): Difference = + Difference.outputs(files, style, cache) +} trait Tracked extends NotNull { - /** Cleans outputs. This operation might require information from the cache, so it should be called first if clear is also called.*/ - def clean: Task[Unit] - /** Clears the cache. If also cleaning, 'clean' should be called first as it might require information from the cache.*/ - def clear: Task[Unit] + /** Cleans outputs and clears the cache.*/ + def clean: Unit } -class Timestamp(val cacheFile: File) extends Tracked +class Timestamp(val cacheFile: File, useStartTime: Boolean) extends Tracked { - val clean = Clean(cacheFile) - def clear = Task.empty - def apply[T](f: Long => Task[T]): Task[T] = + def clean = delete(cacheFile) + /** Reads the previous timestamp, evaluates the provided function, and then updates the timestamp.*/ + def apply[T](f: Long => T): T = { - val getTimestamp = Task { readTimestamp } - getTimestamp bind f map { result => - FileUtilities.write(cacheFile, System.currentTimeMillis.toString) - result - } + val start = now() + val result = f(readTimestamp) + write(cacheFile, (if(useStartTime) start else now()).toString) + result } + private def now() = System.currentTimeMillis def readTimestamp: Long = - try { FileUtilities.read(cacheFile).toLong } + try { read(cacheFile).toLong } catch { case _: NumberFormatException | _: java.io.FileNotFoundException => 0 } } -object Clean -{ - def apply(src: Task[Set[File]]): Task[Unit] = src map FileUtilities.delete - def apply(srcs: File*): Task[Unit] = Task(FileUtilities.delete(srcs)) - def apply(srcs: Set[File]): Task[Unit] = Task(FileUtilities.delete(srcs)) -} -class Changed[O](val task: Task[O], val cacheFile: File)(implicit input: InputCache[O]) extends Tracked +class Changed[O](getValue: => O, val cacheFile: File)(implicit input: InputCache[O]) extends Tracked { - val clean = Clean(cacheFile) - def clear = Task.empty - def apply[O2](ifChanged: O => O2, ifUnchanged: O => O2): Task[O2] = - task map { value => - val cache = - try { OpenResource.fileInputStream(cacheFile)(input.uptodate(value)) } - catch { case _: IOException => new ForceResult(input)(value) } - if(cache.uptodate) - ifUnchanged(value) - else - { - OpenResource.fileOutputStream(false)(cacheFile)(cache.update) - ifChanged(value) - } + def clean = delete(cacheFile) + def apply[O2](ifChanged: O => O2, ifUnchanged: O => O2): O2 = + { + val value = getValue + val cache = + try { OpenResource.fileInputStream(cacheFile)(input.uptodate(value)) } + catch { case _: IOException => new ForceResult(input)(value) } + if(cache.uptodate) + ifUnchanged(value) + else + { + OpenResource.fileOutputStream(false)(cacheFile)(cache.update) + ifChanged(value) } + } } object Difference { sealed class Constructor private[Difference](defineClean: Boolean, filesAreOutputs: Boolean) extends NotNull { - def apply(filesTask: Task[Set[File]], style: FilesInfo.Style, cache: File): Difference = new Difference(filesTask, style, cache, defineClean, filesAreOutputs) - def apply(files: Set[File], style: FilesInfo.Style, cache: File): Difference = apply(Task(files), style, cache) + def apply(files: => Set[File], style: FilesInfo.Style, cache: File): Difference = new Difference(files, style, cache, defineClean, filesAreOutputs) } + /** Provides a constructor for a Difference that removes the files from the previous run on a call to 'clean' and saves the + * hash/last modified time of the files as they are after running the function. This means that this information must be evaluated twice: + * before and after running the function.*/ object outputs extends Constructor(true, true) + /** Provides a constructor for a Difference that does nothing on a call to 'clean' and saves the + * hash/last modified time of the files as they were prior to running the function.*/ object inputs extends Constructor(false, false) } -class Difference(val filesTask: Task[Set[File]], val style: FilesInfo.Style, val cache: File, val defineClean: Boolean, val filesAreOutputs: Boolean) extends Tracked +class Difference(getFiles: => Set[File], val style: FilesInfo.Style, val cache: File, val defineClean: Boolean, val filesAreOutputs: Boolean) extends Tracked { - val clean = if(defineClean) Clean(Task(raw(cachedFilesInfo))) else Task.empty - val clear = Clean(cache) + def clean = + { + if(defineClean) delete(raw(cachedFilesInfo)) else () + clearCache() + } + private def clearCache = delete(cache) private def cachedFilesInfo = fromFile(style.formats, style.empty)(cache)(style.manifest).files private def raw(fs: Set[style.F]): Set[File] = fs.map(_.file) - def apply[T](f: ChangeReport[File] => Task[T]): Task[T] = - filesTask bind { files => - val lastFilesInfo = cachedFilesInfo - val lastFiles = raw(lastFilesInfo) - val currentFiles = files.map(_.getAbsoluteFile) - val currentFilesInfo = style(currentFiles) + def apply[T](f: ChangeReport[File] => T): T = + { + val files = getFiles + val lastFilesInfo = cachedFilesInfo + val lastFiles = raw(lastFilesInfo) + val currentFiles = files.map(_.getAbsoluteFile) + val currentFilesInfo = style(currentFiles) - val report = new ChangeReport[File] - { - lazy val checked = currentFiles - lazy val removed = lastFiles -- checked // all files that were included previously but not this time. This is independent of whether the files exist. - lazy val added = checked -- lastFiles // all files included now but not previously. This is independent of whether the files exist. - lazy val modified = raw(lastFilesInfo -- currentFilesInfo.files) ++ added - lazy val unmodified = checked -- modified - } - - f(report) map { result => - val info = if(filesAreOutputs) style(currentFiles) else currentFilesInfo - toFile(style.formats)(info)(cache)(style.manifest) - result - } + val report = new ChangeReport[File] + { + lazy val checked = currentFiles + lazy val removed = lastFiles -- checked // all files that were included previously but not this time. This is independent of whether the files exist. + lazy val added = checked -- lastFiles // all files included now but not previously. This is independent of whether the files exist. + lazy val modified = raw(lastFilesInfo -- currentFilesInfo.files) ++ added + lazy val unmodified = checked -- modified } + + val result = f(report) + val info = if(filesAreOutputs) style(currentFiles) else currentFilesInfo + toFile(style.formats)(info)(cache)(style.manifest) + result + } } class DependencyTracked[T](val cacheDirectory: File, val translateProducts: Boolean, cleanT: T => Unit)(implicit format: Format[T], mf: Manifest[T]) extends Tracked { private val trackFormat = new TrackingFormat[T](cacheDirectory, translateProducts) private def cleanAll(fs: Set[T]) = fs.foreach(cleanT) - val clean = Task(cleanAll(trackFormat.read.allProducts)) - val clear = Clean(cacheDirectory) + def clean = + { + cleanAll(trackFormat.read.allProducts) + delete(cacheDirectory) + } - def apply[R](f: UpdateTracking[T] => Task[R]): Task[R] = + def apply[R](f: UpdateTracking[T] => R): R = { val tracker = trackFormat.read - f(tracker) map { result => - trackFormat.write(tracker) - result - } + val result = f(tracker) + trackFormat.write(tracker) + result } } object InvalidateFiles @@ -179,30 +219,29 @@ class InvalidateTransitive[T](cacheDirectory: File, translateProducts: Boolean, this(cacheDirectory, translateProducts, (_: T) => ()) private val tracked = new DependencyTracked(cacheDirectory, translateProducts, cleanT) - def clean = tracked.clean - def clear = tracked.clear - - def apply[R](changes: ChangeReport[T])(f: (InvalidationReport[T], UpdateTracking[T]) => Task[R]): Task[R] = - apply(Task(changes))(f) - def apply[R](changesTask: Task[ChangeReport[T]])(f: (InvalidationReport[T], UpdateTracking[T]) => Task[R]): Task[R] = + def clean { - changesTask bind { changes => - tracked { tracker => - val report = InvalidateTransitive.andClean[T](tracker, _.foreach(cleanT), changes.modified) - f(report, tracker) - } + tracked.clean + tracked.clear + } + + def apply[R](getChanges: => ChangeReport[T])(f: (InvalidationReport[T], UpdateTracking[T]) => R): R = + { + val changes = getChanges + tracked { tracker => + val report = InvalidateTransitive.andClean[T](tracker, _.foreach(cleanT), changes.modified) + f(report, tracker) } } } -class BasicTracked(filesTask: Task[Set[File]], style: FilesInfo.Style, cacheDirectory: File) extends Tracked +class BasicTracked(files: => Set[File], style: FilesInfo.Style, cacheDirectory: File) extends Tracked { - private val changed = Difference.inputs(filesTask, style, new File(cacheDirectory, "files")) + private val changed = Difference.inputs(files, style, new File(cacheDirectory, "files")) private val invalidation = InvalidateFiles(new File(cacheDirectory, "invalidation")) - private def onTracked(f: Tracked => Task[Unit]) = Seq(invalidation, changed).forkTasks(f).joinIgnore - val clear = onTracked(_.clear) - val clean = onTracked(_.clean) + private def onTracked(f: Tracked => Unit) = { f(invalidation); f(changed) } + def clean = onTracked(_.clean) - def apply[R](f: (ChangeReport[File], InvalidationReport[File], UpdateTracking[File]) => Task[R]): Task[R] = + def apply[R](f: (ChangeReport[File], InvalidationReport[File], UpdateTracking[File]) => R): R = changed { sourceChanges => invalidation(sourceChanges) { (report, tracking) => f(sourceChanges, report, tracking) diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala index 843898188..02f457dbd 100644 --- a/project/build/XSbt.scala +++ b/project/build/XSbt.scala @@ -26,17 +26,20 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths val compileInterfaceSub = project(compilePath / "interface", "Compiler Interface", new CompilerInterfaceProject(_), interfaceSub) val taskSub = project(tasksPath, "Tasks", new TaskProject(_), controlSub, collectionSub) - val cacheSub = project(cachePath, "Cache", new CacheProject(_), taskSub, ioSub) + val cacheSub = project(cachePath, "Cache", new CacheProject(_), ioSub, collectionSub) val trackingSub = baseProject(cachePath / "tracking", "Tracking", cacheSub) val compilerSub = project(compilePath, "Compile", new CompileProject(_), launchInterfaceSub, interfaceSub, ivySub, ioSub, classpathSub, compileInterfaceSub) - val stdTaskSub = project(tasksPath / "standard", "Standard Tasks", new StandardTaskProject(_), trackingSub, compilerSub, apiSub) + val stdTaskSub = project(tasksPath / "standard", "Standard Tasks", new StandardTaskProject(_), trackingSub, taskSub, compilerSub, apiSub) val altCompilerSub = baseProject("main", "Alternate Compiler Test", stdTaskSub, logSub) val sbtSub = project(sbtPath, "Simple Build Tool", new SbtProject(_) {}, compilerSub, launchInterfaceSub) val installerSub = project(sbtPath / "install", "Installer", new InstallerProject(_) {}, sbtSub) + + lazy val dist = task { None } dependsOn(launchSub.proguard, sbtSub.publishLocal, installerSub.publishLocal) + def baseProject(path: Path, name: String, deps: Project*) = project(path, name, new Base(_), deps : _*) /* Multi-subproject paths */ From 5e4fe7156071cdbbf99c5c9502af91248130f66c Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 7 Jun 2010 10:51:02 -0400 Subject: [PATCH 4/5] fix typo --- compile/api/SameAPI.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compile/api/SameAPI.scala b/compile/api/SameAPI.scala index 04b842ed3..1c7d2dc2c 100644 --- a/compile/api/SameAPI.scala +++ b/compile/api/SameAPI.scala @@ -78,7 +78,7 @@ private class SameAPI(a: Source, b: Source, includePrivate: Boolean) import SameAPI._ /** de Bruijn levels for type parameters in source `a`*/ private lazy val tagsA = TagTypeVariables(a) - /** de Bruijn levels for type parameters in source `a`*/ + /** de Bruijn levels for type parameters in source `b`*/ private lazy val tagsB = TagTypeVariables(b) def debug(flag: Boolean, msg: => String): Boolean = From 393580f1cf57b6d8a7f0b5f061367569d0910b28 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 7 Jun 2010 10:51:22 -0400 Subject: [PATCH 5/5] update comment --- launch/ConfigurationParser.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launch/ConfigurationParser.scala b/launch/ConfigurationParser.scala index 2ee4fb55a..242681fe4 100644 --- a/launch/ConfigurationParser.scala +++ b/launch/ConfigurationParser.scala @@ -35,7 +35,7 @@ class ConfigurationParser extends NotNull val (properties, m6) = processSection(m5, "app-properties", getAppProperties) val (cacheDir, m7) = processSection(m6, "ivy", getIvy) check(m7, "section") - val classifiers = Classifiers("" :: scalaClassifiers, "" :: appClassifiers) + val classifiers = Classifiers("" :: scalaClassifiers, "" :: appClassifiers) // the added "" ensures that the main jars are retrieved new LaunchConfiguration(scalaVersion, IvyOptions(cacheDir, classifiers, repositories), app, boot, logging, properties) } def getScala(m: LabelMap) = @@ -43,7 +43,7 @@ class ConfigurationParser extends NotNull val (scalaVersion, m1) = getVersion(m, "Scala version", "scala.version") val (scalaClassifiers, m2) = ids(m1, "classifiers", Nil) check(m2, "label") - (scalaVersion, scalaClassifiers) // the added "" ensures that the main jars are retrieved + (scalaVersion, scalaClassifiers) } def getVersion(m: LabelMap, label: String, defaultName: String): (Version, LabelMap) = process(m, "version", processVersion(label, defaultName)) def processVersion(label: String, defaultName: String)(value: Option[String]): Version =