diff --git a/cache/Cache.scala b/cache/Cache.scala
index e7ba310dc..c638e94f0 100644
--- a/cache/Cache.scala
+++ b/cache/Cache.scala
@@ -1,7 +1,11 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
import sbinary.{CollectionTypes, Format, JavaFormats}
import java.io.File
+import Types.:+:
trait Cache[I,O]
{
@@ -44,13 +48,13 @@ trait BasicCacheImplicits extends NotNull
new SeparatedCache(input, output)
implicit def defaultEquiv[T]: Equiv[T] = new Equiv[T] { def equiv(a: T, b: T) = a == b }
}
-trait HListCacheImplicits extends HLists
+trait HListCacheImplicits
{
- implicit def hConsInputCache[H,T<:HList](implicit headCache: InputCache[H], tailCache: InputCache[T]): InputCache[HCons[H,T]] =
+ implicit def hConsInputCache[H,T<:HList](implicit headCache: InputCache[H], tailCache: InputCache[T]): InputCache[H :+: T] =
new HConsInputCache(headCache, tailCache)
implicit lazy val hNilInputCache: InputCache[HNil] = new HNilInputCache
- implicit def hConsOutputCache[H,T<:HList](implicit headCache: OutputCache[H], tailCache: OutputCache[T]): OutputCache[HCons[H,T]] =
+ implicit def hConsOutputCache[H,T<:HList](implicit headCache: OutputCache[H], tailCache: OutputCache[T]): OutputCache[H :+: T] =
new HConsOutputCache(headCache, tailCache)
implicit lazy val hNilOutputCache: OutputCache[HNil] = new HNilOutputCache
}
diff --git a/cache/CacheIO.scala b/cache/CacheIO.scala
index e5c643c6a..7ff1eb519 100644
--- a/cache/CacheIO.scala
+++ b/cache/CacheIO.scala
@@ -1,4 +1,7 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
import java.io.{File, FileNotFoundException}
import sbinary.{DefaultProtocol, Format, Operations}
@@ -24,7 +27,7 @@ object CacheIO
toFile(value)(file)(format, mf)
def toFile[T](value: T)(file: File)(implicit format: Format[T], mf: Manifest[Format[T]]): Unit =
{
- FileUtilities.createDirectory(file.getParentFile)
+ IO.createDirectory(file.getParentFile)
Operations.toFile(value)(file)(stampedFormat(format))
}
def stampedFormat[T](format: Format[T])(implicit mf: Manifest[Format[T]]): Format[T] =
diff --git a/cache/FileInfo.scala b/cache/FileInfo.scala
index d1b350fa8..425a8598d 100644
--- a/cache/FileInfo.scala
+++ b/cache/FileInfo.scala
@@ -1,9 +1,11 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
import java.io.{File, IOException}
import sbinary.{DefaultProtocol, Format}
import DefaultProtocol._
-import Function.tupled
import scala.reflect.Manifest
sealed trait FileInfo extends NotNull
@@ -43,22 +45,22 @@ object FileInfo
type F = 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 _))
+ implicit val format: Format[HashModifiedFileInfo] = wrap(f => (f.file, f.hash, f.lastModified), (make _).tupled)
}
object hash extends Style
{
type F = HashFileInfo
- implicit def apply(file: File): HashFileInfo = make(file, computeHash(file).toList)
+ implicit def apply(file: File): HashFileInfo = make(file, computeHash(file))
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 _))
- private def computeHash(file: File) = try { Hash(file) } catch { case e: Exception => Nil }
+ implicit val format: Format[HashFileInfo] = wrap(f => (f.file, f.hash), (make _).tupled)
+ private def computeHash(file: File): List[Byte] = try { Hash(file).toList } catch { case e: Exception => Nil }
}
object lastModified extends Style
{
type F = 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 _))
+ implicit val format: Format[ModifiedFileInfo] = wrap(f => (f.file, f.lastModified), (make _).tupled)
}
object exists extends Style
{
diff --git a/cache/HListCache.scala b/cache/HListCache.scala
index 90f00f47d..2bb3def3b 100644
--- a/cache/HListCache.scala
+++ b/cache/HListCache.scala
@@ -1,12 +1,15 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
import java.io.{InputStream,OutputStream}
-import HLists._
+import Types._
class HNilInputCache extends NoInputCache[HNil]
-class HConsInputCache[H,T <: HList](val headCache: InputCache[H], val tailCache: InputCache[T]) extends InputCache[HCons[H,T]]
+class HConsInputCache[H,T <: HList](val headCache: InputCache[H], val tailCache: InputCache[T]) extends InputCache[H :+: T]
{
- def uptodate(in: HCons[H,T])(cacheStream: InputStream) =
+ def uptodate(in: H :+: T)(cacheStream: InputStream) =
{
val headResult = headCache.uptodate(in.head)(cacheStream)
val tailResult = tailCache.uptodate(in.tail)(cacheStream)
@@ -20,7 +23,7 @@ class HConsInputCache[H,T <: HList](val headCache: InputCache[H], val tailCache:
}
}
}
- def force(in: HCons[H,T])(cacheStream: OutputStream) =
+ def force(in: H :+: T)(cacheStream: OutputStream) =
{
headCache.force(in.head)(cacheStream)
tailCache.force(in.tail)(cacheStream)
@@ -28,7 +31,7 @@ class HConsInputCache[H,T <: HList](val headCache: InputCache[H], val tailCache:
}
class HNilOutputCache extends NoOutputCache[HNil](HNil)
-class HConsOutputCache[H,T <: HList](val headCache: OutputCache[H], val tailCache: OutputCache[T]) extends OutputCache[HCons[H,T]]
+class HConsOutputCache[H,T <: HList](val headCache: OutputCache[H], val tailCache: OutputCache[T]) extends OutputCache[H :+: T]
{
def loadCached(cacheStream: InputStream) =
{
@@ -36,7 +39,7 @@ class HConsOutputCache[H,T <: HList](val headCache: OutputCache[H], val tailCach
val tail = tailCache.loadCached(cacheStream)
HCons(head, tail)
}
- def update(out: HCons[H,T])(cacheStream: OutputStream)
+ def update(out: H :+: T)(cacheStream: OutputStream)
{
headCache.update(out.head)(cacheStream)
tailCache.update(out.tail)(cacheStream)
diff --git a/cache/NoCache.scala b/cache/NoCache.scala
index a9cce3e99..bdb9c4f1b 100644
--- a/cache/NoCache.scala
+++ b/cache/NoCache.scala
@@ -1,4 +1,7 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
import java.io.{InputStream,OutputStream}
diff --git a/cache/SeparatedCache.scala b/cache/SeparatedCache.scala
index 91ecda713..6509e05bf 100644
--- a/cache/SeparatedCache.scala
+++ b/cache/SeparatedCache.scala
@@ -1,4 +1,7 @@
-package xsbt
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
import sbinary.Format
import sbinary.JavaIO._
@@ -31,11 +34,11 @@ class SeparatedCache[I,O](input: InputCache[I], output: OutputCache[O]) extends
catch { case _: Exception => Right(update(file)(in)) }
protected def applyImpl(file: File, in: I) =
{
- OpenResource.fileInputStream(file) { stream =>
+ Using.fileInputStream(file) { stream =>
val cache = input.uptodate(in)(stream)
lazy val doUpdate = (result: O) =>
{
- OpenResource.fileOutputStream(false)(file) { stream =>
+ Using.fileOutputStream(false)(file) { stream =>
cache.update(stream)
output.update(result)(stream)
}
@@ -49,7 +52,7 @@ class SeparatedCache[I,O](input: InputCache[I], output: OutputCache[O]) extends
}
protected def update(file: File)(in: I)(out: O)
{
- OpenResource.fileOutputStream(false)(file) { stream =>
+ Using.fileOutputStream(false)(file) { stream =>
input.force(in)(stream)
output.update(out)(stream)
}
diff --git a/cache/src/test/scala/CacheTest.scala b/cache/src/test/scala/CacheTest.scala
index 65703ecaa..ad6085fc1 100644
--- a/cache/src/test/scala/CacheTest.scala
+++ b/cache/src/test/scala/CacheTest.scala
@@ -1,6 +1,7 @@
-package xsbt
+package sbt
import java.io.File
+import Types.:+:
object CacheTest// extends Properties("Cache test")
{
@@ -19,11 +20,11 @@ object CacheTest// extends Properties("Cache test")
lazy val fileLength = length(create)
- val c = cached(cCache) { (in: (File :: Long :: HNil)) =>
- val file :: len :: HNil = in
+ val c = cached(cCache) { (in: (File :+: Long :+: HNil)) =>
+ val file :+: len :+: HNil = in
println("File: " + file + " (" + file.exists + "), length: " + len)
- (len+1) :: file :: HNil
+ (len+1) :+: file :+: HNil
}
- c(create :: fileLength :: HNil)
+ c(create :+: fileLength :+: HNil)
}
}
\ No newline at end of file
diff --git a/cache/tracking/ChangeReport.scala b/cache/tracking/ChangeReport.scala
index c8f3a52eb..d25b1bbaa 100644
--- a/cache/tracking/ChangeReport.scala
+++ b/cache/tracking/ChangeReport.scala
@@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
-package xsbt
+package sbt
object ChangeReport
{
diff --git a/cache/tracking/DependencyTracking.scala b/cache/tracking/DependencyTracking.scala
index e34930f5a..30e060af3 100644
--- a/cache/tracking/DependencyTracking.scala
+++ b/cache/tracking/DependencyTracking.scala
@@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
-package xsbt
+package sbt
private object DependencyTracking
{
@@ -24,7 +24,6 @@ trait UpdateTracking[T] extends NotNull
// removes sources as keys/values in source, product maps and as values in reverseDependencies map
def pending(sources: Iterable[T]): Unit
}
-import scala.collection.Set
trait ReadTracking[T] extends NotNull
{
def isProduct(file: T): Boolean
@@ -75,13 +74,13 @@ private abstract class DependencyTracking[T](translateProducts: Boolean) extends
def isUsed(file: T): Boolean = exists(reverseUses, file)
- final def allProducts = Set() ++ sourceMap.keys
- final def allSources = Set() ++ productMap.keys
- final def allUsed = Set() ++ reverseUses.keys
+ final def allProducts = sourceMap.keysIterator.toSet
+ final def allSources = productMap.keysIterator.toSet
+ final def allUsed = reverseUses.keysIterator.toSet
final def allTags = tagMap.toSeq
private def exists(map: DMap[T], value: T): Boolean = map.contains(value)
- private def get(map: DMap[T], value: T): Set[T] = map.getOrElse(value, Set.empty[T])
+ private def get(map: DMap[T], value: T): Set[T] = map.getOrElse[collection.Set[T]](value, Set.empty[T]).toSet
final def dependency(sourceFile: T, dependsOn: T)
{
@@ -89,7 +88,7 @@ private abstract class DependencyTracking[T](translateProducts: Boolean) extends
if(!translateProducts)
Seq(dependsOn)
else
- sourceMap.getOrElse(dependsOn, Seq(dependsOn))
+ sourceMap.getOrElse[Iterable[T]](dependsOn, Seq(dependsOn))
actualDependencies.foreach { actualDependency => reverseDependencies.add(actualDependency, sourceFile) }
}
final def product(sourceFile: T, product: T)
diff --git a/cache/tracking/Tracked.scala b/cache/tracking/Tracked.scala
index 49d33c622..77c7447f5 100644
--- a/cache/tracking/Tracked.scala
+++ b/cache/tracking/Tracked.scala
@@ -1,13 +1,13 @@
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
-package xsbt
+package sbt
import java.io.{File,IOException}
import CacheIO.{fromFile, toFile}
import sbinary.Format
import scala.reflect.Manifest
-import xsbt.FileUtilities.{delete, read, write}
+import IO.{delete, read, write}
/* A proper implementation of fileTask that tracks inputs and outputs properly
@@ -34,7 +34,7 @@ object Tracked
* 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)
+ def tstamp(cacheFile: File, useStartTime: Boolean = true): Timestamp = new Timestamp(cacheFile, useStartTime)
/** 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)
@@ -76,13 +76,13 @@ class Changed[O](getValue: => O, val cacheFile: File)(implicit input: InputCache
{
val value = getValue
val cache =
- try { OpenResource.fileInputStream(cacheFile)(input.uptodate(value)) }
+ try { Using.fileInputStream(cacheFile)(input.uptodate(value)) }
catch { case _: IOException => new ForceResult(input)(value) }
if(cache.uptodate)
ifUnchanged(value)
else
{
- OpenResource.fileOutputStream(false)(cacheFile)(cache.update)
+ Using.fileOutputStream(false)(cacheFile)(cache.update)
ifChanged(value)
}
}
@@ -108,7 +108,7 @@ class Difference(getFiles: => Set[File], val style: FilesInfo.Style, val cache:
if(defineClean) delete(raw(cachedFilesInfo)) else ()
clearCache()
}
- private def clearCache = delete(cache)
+ 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)
@@ -161,7 +161,7 @@ object InvalidateFiles
def apply(cacheDirectory: File, translateProducts: Boolean): InvalidateTransitive[File] =
{
import sbinary.DefaultProtocol.FileFormat
- new InvalidateTransitive[File](cacheDirectory, translateProducts, FileUtilities.delete)
+ new InvalidateTransitive[File](cacheDirectory, translateProducts, IO.delete)
}
}
diff --git a/cache/tracking/TrackingFormat.scala b/cache/tracking/TrackingFormat.scala
index 1318c6096..d8a5e0f2c 100644
--- a/cache/tracking/TrackingFormat.scala
+++ b/cache/tracking/TrackingFormat.scala
@@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
-package xsbt
+package sbt
import java.io.File
import scala.collection.mutable.{HashMap, Map, MultiMap, Set}
@@ -34,16 +34,22 @@ private class TrackingFormat[T](directory: File, translateProducts: Boolean)(imp
}
private object TrackingFormat
{
- implicit def mutableMapFormat[S, T](implicit binS : Format[S], binT : Format[T]) : Format[Map[S, T]] =
- viaArray( (x : Array[(S, T)]) => Map(x :_*));
- implicit def depMapFormat[T](implicit bin: Format[T]) : Format[DMap[T]] =
- {
- viaArray { (x : Array[(T, Set[T])]) =>
- val map = newMap[T]
- map ++= x
- map
+ implicit def mutableMapFormat[S, T](implicit binS : Format[S], binT : Format[T]) : Format[HashMap[S, T]] =
+ new LengthEncoded[HashMap[S, T], (S, T)] {
+ def build(size : Int, ts : Iterator[(S, T)]) : HashMap[S, T] = {
+ val b = new HashMap[S, T]
+ b ++= ts
+ b
+ }
+ }
+ implicit def depMapFormat[T](implicit bin: Format[T]) : Format[DMap[T]] =
+ new LengthEncoded[DMap[T], (T, Set[T])] {
+ def build(size : Int, ts : Iterator[(T, Set[T])]) : DMap[T] = {
+ val b = newMap[T]
+ b ++= ts
+ b
+ }
}
- }
def trackingFormat[T](translateProducts: Boolean)(implicit tFormat: Format[T]): Format[DependencyTracking[T]] =
asProduct4((a: DMap[T],b: DMap[T],c: DMap[T], d:TagMap[T]) => new DefaultTracking(translateProducts)(a,b,c,d) : DependencyTracking[T]
)(dt => (dt.reverseDependencies, dt.reverseUses, dt.sourceMap, dt.tagMap))
diff --git a/interface/src/main/java/xsbti/AnalysisCallback.java b/interface/src/main/java/xsbti/AnalysisCallback.java
index 4db5f28c3..03c4798c9 100644
--- a/interface/src/main/java/xsbti/AnalysisCallback.java
+++ b/interface/src/main/java/xsbti/AnalysisCallback.java
@@ -31,6 +31,12 @@ public interface AnalysisCallback
/** Called to indicate that the source file source depends on the class file
* clazz.*/
public void classDependency(File clazz, File source);
+ /** Called to indicate that the source file sourcePath depends on the class file
+ * classFile that is a product of some source. This differs from classDependency
+ * because it is really a sourceDependency. The source corresponding to classFile
+ * was not incuded in the compilation so the plugin doesn't know what the source is though. It
+ * only knows that the class file came from the output directory.*/
+ public void productDependency(File classFile, File sourcePath);
/** Called to indicate that the source file source produces a class file at
* module.*/
public void generatedClass(File source, File module);
diff --git a/interface/src/test/scala/TestCallback.scala b/interface/src/test/scala/TestCallback.scala
index 8e7014af7..75e8d77af 100644
--- a/interface/src/test/scala/TestCallback.scala
+++ b/interface/src/test/scala/TestCallback.scala
@@ -13,6 +13,7 @@ class TestCallback(val superclassNames: Array[String], val annotationNames: Arra
val sourceDependencies = new ArrayBuffer[(File, File)]
val jarDependencies = new ArrayBuffer[(File, File)]
val classDependencies = new ArrayBuffer[(File, File)]
+ val productDependencies = new ArrayBuffer[(File, File)]
val products = new ArrayBuffer[(File, File)]
val applications = new ArrayBuffer[(File, String)]
@@ -25,6 +26,7 @@ class TestCallback(val superclassNames: Array[String], val annotationNames: Arra
def sourceDependency(dependsOn: File, source: File) { sourceDependencies += ((dependsOn, source)) }
def jarDependency(jar: File, source: File) { jarDependencies += ((jar, source)) }
def classDependency(clazz: File, source: File) { classDependencies += ((clazz, source)) }
+ def productDependency(clazz: File, source: File) { productDependencies += ((clazz, source)) }
def generatedClass(source: File, module: File) { products += ((source, module)) }
def endSource(source: File) { endedSources += source }
def foundApplication(source: File, className: String) { applications += ((source, className)) }
diff --git a/project/build.properties b/project/build.properties
index a055fdc51..06ee8d50c 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -2,4 +2,4 @@ project.organization=org.scala-tools.sbt
project.name=xsbt
sbt.version=0.7.4
project.version=0.9.0-SNAPSHOT
-build.scala.versions=2.8.0.RC3
+build.scala.versions=2.8.0.RC4
diff --git a/project/build/XSbt.scala b/project/build/XSbt.scala
index 98221cdc9..bca223f91 100644
--- a/project/build/XSbt.scala
+++ b/project/build/XSbt.scala
@@ -16,6 +16,8 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
val collectionSub = baseProject(utilPath / "collection", "Collections")
val ioSub = project(utilPath / "io", "IO", new IOProject(_), controlSub)
val classpathSub = baseProject(utilPath / "classpath", "Classpath")
+ val classfileSub = project(utilPath / "classfile", "Classfile", new ClassfileProject(_), ioSub, interfaceSub)
+ val completeSub = project(utilPath / "complete", "Completion", new CompletionProject(_), ioSub)
val ivySub = project("ivy", "Ivy", new IvyProject(_), interfaceSub, launchInterfaceSub)
val logSub = project(utilPath / "log", "Logging", new LogProject(_), interfaceSub)
@@ -84,26 +86,28 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
}
trait TestDependencies extends Project
{
- val sc = "org.scala-tools.testing" %% "scalacheck" % "1.7" % "test"
- val sp = "org.scala-tools.testing" %% "specs" % "1.6.5-SNAPSHOT" % "test"
+ val sc = "org.scala-tools.testing" % "scalacheck_2.8.0.RC3" % "1.7" % "test"
+ val sp = "org.scala-tools.testing" % "specs_2.8.0.RC3" % "1.6.5-SNAPSHOT" % "test"
val snaps = ScalaToolsSnapshots
}
class StandardTaskProject(info: ProjectInfo) extends Base(info)
{
override def testClasspath = super.testClasspath +++ compilerSub.testClasspath --- compilerInterfaceClasspath
}
- class LogProject(info: ProjectInfo) extends Base(info)
+ class LogProject(info: ProjectInfo) extends Base(info) with TestDependencies
{
val jline = jlineDep
}
class IOProject(info: ProjectInfo) extends Base(info) with TestDependencies
class TaskProject(info: ProjectInfo) extends Base(info) with TestDependencies
+ class ClassfileProject(info: ProjectInfo) extends Base(info) with TestDependencies
+ class CompletionProject(info: ProjectInfo) extends Base(info) with TestDependencies
class CacheProject(info: ProjectInfo) extends Base(info)
{
// these compilation options are useful for debugging caches and task composition
//override def compileOptions = super.compileOptions ++ List(Unchecked,ExplainTypes, CompileOption("-Xlog-implicits"))
- val sbinary = "org.scala-tools.sbinary" %% "sbinary" % "0.3"
+ val sbinary = "org.scala-tools.sbinary" %% "sbinary" % "0.3.1-SNAPSHOT"
}
class Base(info: ProjectInfo) extends DefaultProject(info) with ManagedBase with Component with Licensed
{
@@ -201,7 +205,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
// sub projects for each version of Scala to precompile against other than the one sbt is built against
// each sub project here will add ~100k to the download
- lazy val precompiled28 = precompiledSub("2.8.0.RC2")
+ lazy val precompiled28 = precompiledSub("2.8.0.RC4")
def precompiledSub(v: String) =
project(info.projectPath, "Precompiled " + v, new Precompiled(v)(_), cip.info.dependencies.toSeq : _* /*doesn't include subprojects of cip*/ )
diff --git a/sbt/install/plugin/src/main/scala/SelfExtractingProject.scala b/sbt/install/plugin/src/main/scala/SelfExtractingProject.scala
index 8dc079e76..3c31694a3 100644
--- a/sbt/install/plugin/src/main/scala/SelfExtractingProject.scala
+++ b/sbt/install/plugin/src/main/scala/SelfExtractingProject.scala
@@ -28,7 +28,7 @@ trait SelfExtractingProject extends Project
write(new File(tmp, "install"), installContents, log) orElse
unzip(this.getClass.getResource(extractorJarLocation), tmpPath, log).left.toOption orElse
Control.thread(compressLoader(loaderJar)) { compressedLoader =>
- zip( (tmpPath ##) :: flat(projectZip) :: compressedLoader :: Nil, outputJar, true, log)
+ zip( (tmpPath ###) :: flat(projectZip) :: compressedLoader :: Nil, outputJar, true, log)
}
}
}
@@ -49,7 +49,7 @@ trait SelfExtractingProject extends Project
else jarName
val packedName = baseName + ".pack"
val packed = outputPath / packedName
- val packedAndGzip = (outputPath ##) / (packedName + ".gz")
+ val packedAndGzip = (outputPath ###) / (packedName + ".gz")
val result =
Pack.pack(loaderJar, packed, log) orElse
FileUtilities.gzip(packed, packedAndGzip, log)
@@ -73,7 +73,7 @@ object SelfExtractingProject
private def flat(p: Path) =
p match
{
- case rp: RelativePath => (rp.parentPath ##) / rp.component
+ case rp: RelativePath => (rp.parentPath ###) / rp.component
case _ => p
}
}
\ No newline at end of file
diff --git a/sbt/src/main/scala/sbt/Analysis.scala b/sbt/src/main/scala/sbt/Analysis.scala
index da117c33f..139bd85b1 100644
--- a/sbt/src/main/scala/sbt/Analysis.scala
+++ b/sbt/src/main/scala/sbt/Analysis.scala
@@ -179,7 +179,7 @@ class BasicCompileAnalysis protected (analysisPath: Path, projectPath: Path, log
def getClasses(sources: PathFinder, outputDirectory: Path): PathFinder =
Path.lazyPathFinder
{
- val basePath = (outputDirectory ##)
+ val basePath = (outputDirectory ###)
for(c <- products(sources.get)) yield
Path.relativize(basePath, c).getOrElse(c)
}
diff --git a/sbt/src/main/scala/sbt/DefaultProject.scala b/sbt/src/main/scala/sbt/DefaultProject.scala
index 6ca5c65a7..62350fa8d 100644
--- a/sbt/src/main/scala/sbt/DefaultProject.scala
+++ b/sbt/src/main/scala/sbt/DefaultProject.scala
@@ -295,7 +295,7 @@ abstract class BasicScalaProject extends ScalaProject with BasicDependencyProjec
protected def packageAction = packageTask(packagePaths, jarPath, packageOptions).dependsOn(compile) describedAs PackageDescription
protected def packageTestAction = packageTask(packageTestPaths, packageTestJar).dependsOn(testCompile) describedAs TestPackageDescription
- protected def packageDocsAction = packageTask(mainDocPath ##, packageDocsJar, Recursive).dependsOn(doc) describedAs DocPackageDescription
+ protected def packageDocsAction = packageTask(mainDocPath ###, packageDocsJar, Recursive).dependsOn(doc) describedAs DocPackageDescription
protected def packageSrcAction = packageTask(packageSourcePaths, packageSrcJar) describedAs SourcePackageDescription
protected def packageTestSrcAction = packageTask(packageTestSourcePaths, packageTestSrcJar) describedAs TestSourcePackageDescription
protected def packageProjectAction = zipTask(packageProjectPaths, packageProjectZip) describedAs ProjectPackageDescription
diff --git a/sbt/src/main/scala/sbt/FileUtilities.scala b/sbt/src/main/scala/sbt/FileUtilities.scala
index 504d6ce02..0d0477906 100644
--- a/sbt/src/main/scala/sbt/FileUtilities.scala
+++ b/sbt/src/main/scala/sbt/FileUtilities.scala
@@ -88,7 +88,7 @@ object FileUtilities
/** Creates a jar file.
* @param sources The files to include in the jar file. The path used for the jar is
* relative to the base directory for the source. That is, the path in the jar for source
- * (basePath ##) / x / y is x / y.
+ * (basePath ###) / x / y is x / y.
* @param outputJar The file to write the jar to.
* @param manifest The manifest for the jar.
* @param recursive If true, any directories in sources are recursively processed. Otherwise,
@@ -99,7 +99,7 @@ object FileUtilities
/** Creates a zip file.
* @param sources The files to include in the jar file. The path used for the jar is
* relative to the base directory for the source. That is, the path in the jar for source
- * (basePath ##) / x / y is x / y.
+ * (basePath ###) / x / y is x / y.
* @param outputZip The file to write the zip to.
* @param recursive If true, any directories in sources are recursively processed. Otherwise,
* they are not
@@ -465,7 +465,7 @@ object FileUtilities
* directory. Directories are not recursively entered. The destination hierarchy matches the
* source paths relative to any base directories. For example:
*
- * A source (basePath ##) / x / y is copied to destinationDirectory / x / y.
+ * A source (basePath ###) / x / y is copied to destinationDirectory / x / y.
*
* @param overwrite if true, existing destination files are always overwritten
* @param preserveLastModified if true, the last modified time of copied files will be set equal to
@@ -575,7 +575,7 @@ object FileUtilities
/** Synchronizes the contents of the sourceDirectory directory to the
* targetDirectory directory.*/
def sync(sourceDirectory: Path, targetDirectory: Path, log: Logger): Option[String] =
- syncPaths((sourceDirectory ##) ** AllPassFilter, targetDirectory, log)
+ syncPaths((sourceDirectory ###) ** AllPassFilter, targetDirectory, log)
def syncPaths(sources: PathFinder, targetDirectory: Path, log: Logger): Option[String] =
{
copy(sources.get, targetDirectory, log).right.flatMap
@@ -583,7 +583,7 @@ object FileUtilities
}
def prune(directory: Path, keepOnly: Iterable[Path], log: Logger): Option[String] =
{
- val existing = ((directory ##) ** AllPassFilter).get
+ val existing = ((directory ###) ** AllPassFilter).get
val toRemove = scala.collection.mutable.HashSet(existing.toSeq: _*)
toRemove --= keepOnly
if(log.atLevel(Level.Debug))
@@ -808,7 +808,7 @@ object FileUtilities
def readChannelValue[R](file: File, log: Logger)(f: FileChannel => Either[String, R]): Either[String, R] =
fileInputChannel.io(file, Reading, log)(f)
- private[sbt] def wrapNull(a: Array[File]): Array[File] =
+ private[sbt] (a: Array[File]): Array[File] =
if(a == null)
new Array[File](0)
else
diff --git a/sbt/src/main/scala/sbt/NameFilter.scala b/sbt/src/main/scala/sbt/NameFilter.scala
deleted file mode 100644
index 3387806b6..000000000
--- a/sbt/src/main/scala/sbt/NameFilter.scala
+++ /dev/null
@@ -1,72 +0,0 @@
-/* sbt -- Simple Build Tool
- * Copyright 2008, 2009 Mark Harrah
- */
-package sbt
-
-import java.io.File
-import java.util.regex.Pattern
-
-trait FileFilter extends java.io.FileFilter with NotNull
-{
- def || (filter: FileFilter): FileFilter = new SimpleFileFilter( file => accept(file) || filter.accept(file) )
- def && (filter: FileFilter): FileFilter = new SimpleFileFilter( file => accept(file) && filter.accept(file) )
- def -- (filter: FileFilter): FileFilter = new SimpleFileFilter( file => accept(file) && !filter.accept(file) )
- def unary_- : FileFilter = new SimpleFileFilter( file => !accept(file) )
-}
-trait NameFilter extends FileFilter with NotNull
-{
- def accept(name: String): Boolean
- final def accept(file: File): Boolean = accept(file.getName)
- def | (filter: NameFilter): NameFilter = new SimpleFilter( name => accept(name) || filter.accept(name) )
- def & (filter: NameFilter): NameFilter = new SimpleFilter( name => accept(name) && filter.accept(name) )
- def - (filter: NameFilter): NameFilter = new SimpleFilter( name => accept(name) && !filter.accept(name) )
- override def unary_- : NameFilter = new SimpleFilter( name => !accept(name) )
-}
-object HiddenFileFilter extends FileFilter {
- def accept(file: File) = file.isHidden && file.getName != "."
-}
-object ExistsFileFilter extends FileFilter {
- def accept(file: File) = file.exists
-}
-object DirectoryFilter extends FileFilter {
- def accept(file: File) = file.isDirectory
-}
-class SimpleFileFilter(val acceptFunction: File => Boolean) extends FileFilter
-{
- def accept(file: File) = acceptFunction(file)
-}
-class ExactFilter(val matchName: String) extends NameFilter
-{
- def accept(name: String) = matchName == name
-}
-class SimpleFilter(val acceptFunction: String => Boolean) extends NameFilter
-{
- def accept(name: String) = acceptFunction(name)
-}
-class PatternFilter(val pattern: Pattern) extends NameFilter
-{
- def accept(name: String) = pattern.matcher(name).matches
-}
-object AllPassFilter extends NameFilter
-{
- def accept(name: String) = true
-}
-object NothingFilter extends NameFilter
-{
- def accept(name: String) = false
-}
-
-object GlobFilter
-{
- def apply(expression: String): NameFilter =
- {
- require(!expression.exists(java.lang.Character.isISOControl), "Control characters not allowed in filter expression.")
- if(expression == "*")
- AllPassFilter
- else if(expression.indexOf('*') < 0) // includes case where expression is empty
- new ExactFilter(expression)
- else
- new PatternFilter(Pattern.compile(expression.split("\\*", -1).map(quote).mkString(".*")))
- }
- private def quote(s: String) = if(s.isEmpty) "" else Pattern.quote(s.replaceAll("\n", """\n"""))
-}
\ No newline at end of file
diff --git a/sbt/src/main/scala/sbt/Process.scala b/sbt/src/main/scala/sbt/Process.scala
index a26635230..51290207b 100644
--- a/sbt/src/main/scala/sbt/Process.scala
+++ b/sbt/src/main/scala/sbt/Process.scala
@@ -156,7 +156,7 @@ trait ProcessBuilder extends SourcePartialBuilder with SinkPartialBuilder
/** Constructs a command that will run this command and pipes the output to `other`. `other` must be a simple command.*/
def #| (other: ProcessBuilder): ProcessBuilder
/** Constructs a command that will run this command and then `other`. The exit code will be the exit code of `other`.*/
- def ## (other: ProcessBuilder): ProcessBuilder
+ def ### (other: ProcessBuilder): ProcessBuilder
def canPipeTo: Boolean
}
diff --git a/sbt/src/main/scala/sbt/ProjectPaths.scala b/sbt/src/main/scala/sbt/ProjectPaths.scala
index f08129761..cfd285adf 100644
--- a/sbt/src/main/scala/sbt/ProjectPaths.scala
+++ b/sbt/src/main/scala/sbt/ProjectPaths.scala
@@ -83,17 +83,17 @@ trait BasicScalaPaths extends Project with ScalaPaths
}
def testSources = sources(testSourceRoots)
- def mainResources = descendents(mainResourcesPath ##, "*")
- def testResources = descendents(testResourcesPath ##, "*")
+ def mainResources = descendents(mainResourcesPath ###, "*")
+ def testResources = descendents(testResourcesPath ###, "*")
- def mainClasses = (mainCompilePath ##) ** "*.class"
- def testClasses = (testCompilePath ##) ** "*.class"
+ def mainClasses = (mainCompilePath ###) ** "*.class"
+ def testClasses = (testCompilePath ###) ** "*.class"
def packagePaths = mainClasses +++ mainResources
def packageTestPaths = testClasses +++ testResources
def packageSourcePaths = mainSources +++ mainResources
def packageTestSourcePaths = testSources +++ testResources
- def packageProjectPaths = descendents( (info.projectPath ##), "*") --- (packageProjectExcludes ** "*")
+ def packageProjectPaths = descendents( (info.projectPath ###), "*") --- (packageProjectExcludes ** "*")
protected def packageProjectExcludes: PathFinder =
outputRootPath +++ managedDependencyRootPath +++
info.bootPath +++ info.builderProjectOutputPath +++
@@ -159,8 +159,8 @@ trait MavenStyleScalaPaths extends BasicScalaPaths with BasicPackagePaths
testResourcesPath ::
Nil
- def mainSourceRoots = (mainJavaSourcePath##) +++ (mainScalaSourcePath##)
- def testSourceRoots = (testJavaSourcePath##) +++ (testScalaSourcePath##)
+ def mainSourceRoots = (mainJavaSourcePath###) +++ (mainScalaSourcePath##)
+ def testSourceRoots = (testJavaSourcePath###) +++ (testScalaSourcePath##)
}
trait BasicPackagePaths extends ScalaPaths with PackagePaths
@@ -222,7 +222,7 @@ trait MavenStyleWebScalaPaths extends WebScalaPaths with MavenStyleScalaPaths
def warPath = outputPath / defaultWarName
/** Additional files to include in the web application. */
protected def extraWebappFiles: PathFinder = Path.emptyPathFinder
- def webappResources = descendents(webappPath ##, "*") +++ extraWebappFiles
+ def webappResources = descendents(webappPath ###, "*") +++ extraWebappFiles
}
object WebProjectPaths
{
diff --git a/sbt/src/main/scala/sbt/ScalaProject.scala b/sbt/src/main/scala/sbt/ScalaProject.scala
index 9bdf9fb6c..e2eacad59 100644
--- a/sbt/src/main/scala/sbt/ScalaProject.scala
+++ b/sbt/src/main/scala/sbt/ScalaProject.scala
@@ -330,7 +330,7 @@ trait ScalaProject extends SimpleScalaProject with FileTasks with MultiTaskProje
trait WebScalaProject extends ScalaProject
{
protected def packageWarAction(stagedWarPath: Path, ignore: PathFinder, outputWarPath: => Path, options: => Seq[PackageOption]): Task =
- packageTask(descendents(stagedWarPath ##, "*") --- ignore, outputWarPath, options)
+ packageTask(descendents(stagedWarPath ###, "*") --- ignore, outputWarPath, options)
@deprecated protected def prepareWebappTask(webappContents: PathFinder, warPath: => Path, classpath: PathFinder, extraJars: => Iterable[File]): Task =
prepareWebappTask(webappContents, warPath, classpath, Path.finder(extraJars))
@@ -344,7 +344,7 @@ trait WebScalaProject extends ScalaProject
val classesTargetDirectory = webInfPath / "classes"
val (libs, directories) = classpath.get.toList.partition(ClasspathUtilities.isArchive)
- val classesAndResources = descendents(Path.lazyPathFinder(directories) ##, "*")
+ val classesAndResources = descendents(Path.lazyPathFinder(directories) ###, "*")
if(log.atLevel(Level.Debug))
directories.foreach(d => log.debug(" Copying the contents of directory " + d + " to " + classesTargetDirectory))
diff --git a/sbt/src/main/scala/sbt/Webstart.scala b/sbt/src/main/scala/sbt/Webstart.scala
index bd3d382a1..24c54ff59 100644
--- a/sbt/src/main/scala/sbt/Webstart.scala
+++ b/sbt/src/main/scala/sbt/Webstart.scala
@@ -61,7 +61,7 @@ trait WebstartScalaProject extends ScalaProject
FileUtilities.createDirectories(webstartOutputDirectory :: webstartLibDirectory :: Nil, log) // ignore errors
verifyOptions(options)
- def relativize(jar: Path) = Path.relativize(webstartOutputDirectory ##, jar) getOrElse
+ def relativize(jar: Path) = Path.relativize(webstartOutputDirectory ###, jar) getOrElse
error("Jar (" + jar + ") was not in webstart output directory (" + webstartOutputDirectory + ").")
def signAndPack(jars: List[Path], targetDirectory: Path): Either[String, List[Path]] =
{
@@ -104,7 +104,7 @@ trait WebstartScalaProject extends ScalaProject
val keep = jnlpFile +++ Path.lazyPathFinder(mainJars ++ libJars ++ copiedResources) +++
webstartOutputDirectory +++ webstartLibDirectory
prune(webstartOutputDirectory, keep.get, log) orElse
- webstartZip.flatMap( zipPath => zip(List(webstartOutputDirectory ##), zipPath, true, log) )
+ webstartZip.flatMap( zipPath => zip(List(webstartOutputDirectory ###), zipPath, true, log) )
}
}
}
@@ -276,7 +276,7 @@ abstract class BasicWebstartProject extends BasicScalaProject with WebstartScala
def webstartExtraLibraries = mainDependencies.scalaJars
def webstartLibraries = publicClasspath +++ jarsOfProjectDependencies
- def webstartResources = descendents(jnlpResourcesPath ##, AllPassFilter)
+ def webstartResources = descendents(jnlpResourcesPath ###, AllPassFilter)
def webstartPack200 = true
def webstartGzip = true
diff --git a/sbt/src/main/scala/sbt/impl/ProcessImpl.scala b/sbt/src/main/scala/sbt/impl/ProcessImpl.scala
index 67e6b187a..f1e8271bf 100644
--- a/sbt/src/main/scala/sbt/impl/ProcessImpl.scala
+++ b/sbt/src/main/scala/sbt/impl/ProcessImpl.scala
@@ -121,7 +121,7 @@ private abstract class AbstractProcessBuilder extends ProcessBuilder with SinkPa
require(other.canPipeTo, "Piping to multiple processes is not supported.")
new PipedProcessBuilder(this, other, false)
}
- def ##(other: ProcessBuilder): ProcessBuilder = new SequenceProcessBuilder(this, other)
+ def ###(other: ProcessBuilder): ProcessBuilder = new SequenceProcessBuilder(this, other)
protected def toSource = this
protected def toSink = this
@@ -246,7 +246,7 @@ private class OrProcessBuilder(first: ProcessBuilder, second: ProcessBuilder) ex
{
override def createProcess(io: ProcessIO) = new OrProcess(first, second, io)
}
-private class SequenceProcessBuilder(first: ProcessBuilder, second: ProcessBuilder) extends SequentialProcessBuilder(first, second, "##")
+private class SequenceProcessBuilder(first: ProcessBuilder, second: ProcessBuilder) extends SequentialProcessBuilder(first, second, "###")
{
override def createProcess(io: ProcessIO) = new ProcessSequence(first, second, io)
}
diff --git a/sbt/src/sbt-test/project/flatten/project/build/src/FlatProject.scala b/sbt/src/sbt-test/project/flatten/project/build/src/FlatProject.scala
index f9cb648fc..4ff35e60f 100644
--- a/sbt/src/sbt-test/project/flatten/project/build/src/FlatProject.scala
+++ b/sbt/src/sbt-test/project/flatten/project/build/src/FlatProject.scala
@@ -6,12 +6,12 @@ class FlatProject(info: ProjectInfo) extends DefaultProject(info)
val sc = "org.scalacheck" % "scalacheck" % "1.5" % "test"
def sourceFilter = "*.java" | "*.scala"
- override def mainSources = descendents(sourcePath ##, sourceFilter)
- override def mainResources = descendents(sourcePath ##, -sourceFilter)
+ override def mainSources = descendents(sourcePath ###, sourceFilter)
+ override def mainResources = descendents(sourcePath ###, -sourceFilter)
override def testSourcePath = "test-src"
- override def testSources = descendents(testSourcePath ##, sourceFilter)
- override def testResources = descendents(testSourcePath ##, -sourceFilter)
+ override def testSources = descendents(testSourcePath ###, sourceFilter)
+ override def testResources = descendents(testSourcePath ###, -sourceFilter)
lazy val unpackageProject =
task
diff --git a/sbt/src/test/scala/sbt/ProcessSpecification.scala b/sbt/src/test/scala/sbt/ProcessSpecification.scala
index ed722128b..fe02609df 100644
--- a/sbt/src/test/scala/sbt/ProcessSpecification.scala
+++ b/sbt/src/test/scala/sbt/ProcessSpecification.scala
@@ -15,7 +15,7 @@ object ProcessSpecification extends Properties("Process I/O")
specify("Correct exit code", (exitCode: Byte) => checkExit(exitCode))
specify("#&& correct", (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #&& _)(_ && _))
specify("#|| correct", (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #|| _)(_ || _))
- specify("## correct", (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ ## _)( (x,latest) => latest))
+ specify("### correct", (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ ### _)( (x,latest) => latest))
specify("Pipe to output file", (data: Array[Byte]) => checkFileOut(data))
specify("Pipe to input file", (data: Array[Byte]) => checkFileIn(data))
specify("Pipe to process", (data: Array[Byte]) => checkPipe(data))
diff --git a/sbt/src/main/scala/sbt/classfile/Analyze.scala b/util/classfile/Analyze.scala
similarity index 89%
rename from sbt/src/main/scala/sbt/classfile/Analyze.scala
rename to util/classfile/Analyze.scala
index cf1643152..7f6a1b297 100644
--- a/sbt/src/main/scala/sbt/classfile/Analyze.scala
+++ b/util/classfile/Analyze.scala
@@ -1,9 +1,10 @@
/* sbt -- Simple Build Tool
- * Copyright 2009 Mark Harrah
+ * Copyright 2009, 2010 Mark Harrah
*/
-package sbt.classfile
-import sbt._
+package sbt
+package classfile
+import ClassfileLogger._
import scala.collection.mutable
import mutable.{ArrayBuffer, Buffer}
import java.io.File
@@ -13,8 +14,8 @@ import java.lang.reflect.Modifier.{STATIC, PUBLIC, ABSTRACT}
private[sbt] object Analyze
{
- def apply[T](basePath: Path, outputDirectory: Path, sources: Iterable[Path], roots: Iterable[Path], log: Logger)
- (allProducts: => scala.collection.Set[Path], analysis: AnalysisCallback, loader: ClassLoader)
+ def apply[T](basePath: Path, outputDirectory: Path, sources: Iterable[Path], roots: Iterable[Path], log: ClassfileLogger)
+ (allProducts: => scala.collection.Set[Path], analysis: xsbti.AnalysisCallback, loader: ClassLoader)
(compile: => Option[String]): Option[String] =
{
val sourceSet = Set(sources.toSeq : _*)
@@ -35,15 +36,15 @@ private[sbt] object Analyze
val sourceToClassFiles = new mutable.HashMap[Path, Buffer[ClassFile]]
val superclasses = analysis.superclassNames flatMap { tpe => load(tpe, "Could not load superclass '" + tpe + "'") }
- val annotations = analysis.annotationNames
+ val annotations = analysis.annotationNames.toSeq
- def annotated(fromClass: Seq[Annotation]) = if(fromClass.isEmpty) Nil else annotations.filter(Set() ++ fromClass.map(_.annotationType.getName))
+ def annotated(fromClass: Seq[Annotation]) = if(fromClass.isEmpty) Nil else annotations.filter(fromClass.map(_.annotationType.getName).toSet)
// parse class files and assign classes to sources. This must be done before dependencies, since the information comes
// as class->class dependencies that must be mapped back to source->class dependencies using the source+class assignment
for(newClass <- newClasses;
path <- Path.relativize(outputDirectory, newClass);
- classFile = Parser(newClass.asFile, log);
+ classFile = Parser(newClass.asFile);
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.asFile.getName);
source <- guessSourcePath(sourceSet, roots, classFile, log))
{
@@ -75,10 +76,10 @@ private[sbt] object Analyze
}
def processDependency(tpe: String)
{
- Control.trapAndLog(log)
+ trapAndLog(log)
{
val loaded = load(tpe, "Problem processing dependencies of source " + source)
- for(clazz <- loaded; file <- Control.convertException(FileUtilities.classLocationFile(clazz)).right)
+ for(clazz <- loaded; file <- ErrorHandling.convert(IO.classLocationFile(clazz)).right)
{
if(file.isDirectory)
{
@@ -107,7 +108,7 @@ private[sbt] object Analyze
}
}
- compile orElse Control.convertErrorMessage(log)(analyze()).left.toOption
+ compile orElse ClassfileLogger.convertErrorMessage(log)(analyze()).left.toOption
}
private def guessSourceName(name: String) = Some( takeToDollar(trimClassExt(name)) )
private def takeToDollar(name: String) =
@@ -118,7 +119,7 @@ private[sbt] object Analyze
private final val ClassExt = ".class"
private def trimClassExt(name: String) = if(name.endsWith(ClassExt)) name.substring(0, name.length - ClassExt.length) else name
private def resolveClassFile(file: File, className: String): File = (file /: (className.replace('.','/') + ClassExt).split("/"))(new File(_, _))
- private def guessSourcePath(sources: scala.collection.Set[Path], roots: Iterable[Path], classFile: ClassFile, log: Logger) =
+ private def guessSourcePath(sources: scala.collection.Set[Path], roots: Iterable[Path], classFile: ClassFile, log: ClassfileLogger) =
{
val classNameParts = classFile.className.split("""\.""")
val lastIndex = classNameParts.length - 1
diff --git a/sbt/src/main/scala/sbt/classfile/ClassFile.scala b/util/classfile/ClassFile.scala
similarity index 96%
rename from sbt/src/main/scala/sbt/classfile/ClassFile.scala
rename to util/classfile/ClassFile.scala
index df004c855..df73acf9b 100644
--- a/sbt/src/main/scala/sbt/classfile/ClassFile.scala
+++ b/util/classfile/ClassFile.scala
@@ -1,7 +1,8 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
-package sbt.classfile
+package sbt
+package classfile
import Constants._
import java.io.File
@@ -31,7 +32,7 @@ private[sbt] final case class Constant(tag: Byte, nameIndex: Int, typeIndex: Int
def this(tag: Byte, value: AnyRef) = this(tag, -1, -1, Some(value))
def wide = tag == ConstantLong || tag == ConstantDouble
}
-private[sbt] final case class FieldOrMethodInfo(accessFlags: Int, name: Option[String], descriptor: Option[String], attributes: RandomAccessSeq[AttributeInfo]) extends NotNull
+private[sbt] final case class FieldOrMethodInfo(accessFlags: Int, name: Option[String], descriptor: Option[String], attributes: IndexedSeq[AttributeInfo]) extends NotNull
{
def isStatic = (accessFlags&ACC_STATIC)== ACC_STATIC
def isPublic = (accessFlags&ACC_PUBLIC)==ACC_PUBLIC
diff --git a/util/classfile/ClassfileLogger.scala b/util/classfile/ClassfileLogger.scala
new file mode 100644
index 000000000..6c2ede1f9
--- /dev/null
+++ b/util/classfile/ClassfileLogger.scala
@@ -0,0 +1,25 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2009, 2010 Mark Harrah
+ */
+package sbt
+package classfile
+
+trait ClassfileLogger
+{
+ def warn(msg: => String): Unit
+ def error(msg: => String): Unit
+ def trace(exception: => Throwable): Unit
+}
+object ClassfileLogger
+{
+ def convertErrorMessage[T](log: ClassfileLogger)(t: => T): Either[String, T] =
+ {
+ try { Right(t) }
+ catch { case e: Exception => log.trace(e); Left(e.toString) }
+ }
+ def trapAndLog(log: ClassfileLogger)(execute: => Unit)
+ {
+ try { execute }
+ catch { case e => log.trace(e); log.error(e.toString) }
+ }
+}
\ No newline at end of file
diff --git a/sbt/src/main/scala/sbt/classfile/Parser.scala b/util/classfile/Parser.scala
similarity index 91%
rename from sbt/src/main/scala/sbt/classfile/Parser.scala
rename to util/classfile/Parser.scala
index b4c85fada..cf33fca2e 100644
--- a/sbt/src/main/scala/sbt/classfile/Parser.scala
+++ b/util/classfile/Parser.scala
@@ -1,8 +1,8 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
-package sbt.classfile
-import sbt._
+package sbt
+package classfile
import java.io.{DataInputStream, File, InputStream}
@@ -15,9 +15,9 @@ import Constants._
private[sbt] object Parser
{
- def apply(file: File, log: Logger): ClassFile = FileUtilities.readStreamValue(file, log)(parse(file.getCanonicalPath, log)).right.get
- private def parse(fileName: String, log: Logger)(is: InputStream): Either[String, ClassFile] = Right(parseImpl(fileName, is, log))
- private def parseImpl(filename: String, is: InputStream, log: Logger): ClassFile =
+ def apply(file: File): ClassFile = Using.fileInputStream(file)(parse(file.getCanonicalPath)).right.get
+ private def parse(fileName: String)(is: InputStream): Either[String, ClassFile] = Right(parseImpl(fileName, is))
+ private def parseImpl(filename: String, is: InputStream): ClassFile =
{
val in = new DataInputStream(is)
new ClassFile
@@ -114,7 +114,7 @@ private[sbt] object Parser
}
}
}
- private def array[T](size: Int)(f: => T)(implicit mf: scala.reflect.Manifest[T]) = Array.fromFunction(i => f)(size)
+ private def array[T : scala.reflect.Manifest](size: Int)(f: => T) = Array.tabulate(size)(_ => f)
private def parseConstantPool(in: DataInputStream) =
{
val constantPoolSize = in.readUnsignedShort()
diff --git a/sbt/src/main/scala/sbt/complete/History.scala b/util/complete/History.scala
similarity index 69%
rename from sbt/src/main/scala/sbt/complete/History.scala
rename to util/complete/History.scala
index cb4fae033..bf009f626 100644
--- a/sbt/src/main/scala/sbt/complete/History.scala
+++ b/util/complete/History.scala
@@ -1,15 +1,19 @@
-package sbt.complete
+/* sbt -- Simple Build Tool
+ * Copyright 2010 Mark Harrah
+ */
+package sbt
+package complete
import History.number
-final class History private(lines: Array[String], log: Logger) extends NotNull
+final class History private(lines: IndexedSeq[String], error: (=> String) => Unit) extends NotNull
{
private def reversed = lines.reverse
- def all: Seq[String] = lines.toArray
+ def all: Seq[String] = lines
def size = lines.length
def !! : Option[String] = !- (1)
- def apply(i: Int): Option[String] = if(0 <= i && i < size) Some( lines(i) ) else { log.error("Invalid history index: " + i); None }
+ def apply(i: Int): Option[String] = if(0 <= i && i < size) Some( lines(i) ) else { error("Invalid history index: " + i); None }
def !(i: Int): Option[String] = apply(i)
def !(s: String): Option[String] =
@@ -25,7 +29,7 @@ final class History private(lines: Array[String], log: Logger) extends NotNull
private def nonEmpty[T](s: String)(act: => Option[T]): Option[T] =
if(s.isEmpty)
{
- log.error("No action specified to history command")
+ error("No action specified to history command")
None
}
else
@@ -37,7 +41,7 @@ final class History private(lines: Array[String], log: Logger) extends NotNull
object History
{
- def apply(lines: Seq[String], log: Logger): History = new History(lines.toArray, log)
+ def apply(lines: Seq[String], error: (=> String) => Unit): History = new History(lines.toIndexedSeq, error)
def number(s: String): Option[Int] =
try { Some(s.toInt) }
diff --git a/sbt/src/main/scala/sbt/complete/HistoryCommands.scala b/util/complete/HistoryCommands.scala
similarity index 71%
rename from sbt/src/main/scala/sbt/complete/HistoryCommands.scala
rename to util/complete/HistoryCommands.scala
index a65893d78..a03c9cfca 100644
--- a/sbt/src/main/scala/sbt/complete/HistoryCommands.scala
+++ b/util/complete/HistoryCommands.scala
@@ -1,4 +1,8 @@
-package sbt.complete
+/* sbt -- Simple Build Tool
+ * Copyright 2010 Mark Harrah
+ */
+package sbt
+package complete
object HistoryCommands
{
@@ -30,26 +34,27 @@ object HistoryCommands
StartsWithString -> "Execute the most recent command starting with 'string'",
ContainsString -> "Execute the most recent command containing 'string'"
)
- def printHelp(log: Logger): Unit =
- println("History commands:\n " + (descriptions.map{ case (c,d) => c + " " + d}).mkString("\n "))
+ def helpString = "History commands:\n " + (descriptions.map{ case (c,d) => c + " " + d}).mkString("\n ")
+ def printHelp(): Unit =
+ println(helpString)
- def apply(s: String, historyPath: Option[Path], maxLines: Int, log: Logger): Option[List[String]] =
+ def apply(s: String, historyPath: Option[Path], maxLines: Int, error: (=> String) => Unit): Option[List[String]] =
if(s.isEmpty)
{
- printHelp(log)
+ printHelp()
Some(Nil)
}
else
{
- val lines = historyPath.toList.flatMap(h => xsbt.FileUtilities.readLines(h.asFile) ).toArray
+ val lines = historyPath.toList.flatMap(h => IO.readLines(h.asFile) ).toArray
if(lines.isEmpty)
{
- log.warn("No history")
+ error("No history")
None
}
else
{
- val history = complete.History(lines, log)
+ val history = complete.History(lines, error)
if(s.startsWith(ListCommands))
{
val rest = s.substring(ListCommands.length)
@@ -57,16 +62,17 @@ object HistoryCommands
printHistory(history, maxLines, show)
Some(Nil)
}
- else {
- val command = historyCommand(history, s, log)
+ else
+ {
+ val command = historyCommand(history, s)
command.foreach(lines(lines.length - 1) = _)
- historyPath foreach { h => xsbt.FileUtilities.writeLines(h.asFile, lines) }
+ historyPath foreach { h => IO.writeLines(h.asFile, lines) }
Some(command.toList)
}
}
}
def printHistory(history: complete.History, historySize: Int, show: Int): Unit = history.list(historySize, show).foreach(println)
- def historyCommand(history: complete.History, s: String, log: Logger): Option[String] =
+ def historyCommand(history: complete.History, s: String): Option[String] =
{
if(s == Last)
history !!
diff --git a/util/control/ErrorHandling.scala b/util/control/ErrorHandling.scala
index f4d42993b..4072edff3 100644
--- a/util/control/ErrorHandling.scala
+++ b/util/control/ErrorHandling.scala
@@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
-package xsbt
+package sbt
object ErrorHandling
{
@@ -22,7 +22,7 @@ object ErrorHandling
try { Right(f) }
catch { case e: Exception => Left(e) }
}
-final class TranslatedException private[xsbt](msg: String, cause: Throwable) extends RuntimeException(msg, cause)
+final class TranslatedException private[sbt](msg: String, cause: Throwable) extends RuntimeException(msg, cause)
{
override def toString = msg
}
\ No newline at end of file
diff --git a/util/datatype/Generator.scala b/util/datatype/Generator.scala
index a6eeec5e7..521473360 100644
--- a/util/datatype/Generator.scala
+++ b/util/datatype/Generator.scala
@@ -5,6 +5,7 @@ package xsbt
package api
import java.io.File
+import sbt.Path
import sbt.IO.write
import Generator._
@@ -25,8 +26,8 @@ abstract class GeneratorBase(val basePkgName: String, val baseDirectory: File) e
def writeSource(name: String, pkgName: String, content: String)
{
- import sbt.Paths._
- val file = baseDirectory / packagePath(pkgName) / (name+ ".java")
+ import Path._
+ val file = Path.fromString(baseDirectory, packagePath(pkgName)) / (name+ ".java")
file.getParentFile.mkdirs()
write(file, "package " + pkgName + ";\n\n" + content)
}
diff --git a/util/io/IO.scala b/util/io/IO.scala
index b506ab08d..7113e7aea 100644
--- a/util/io/IO.scala
+++ b/util/io/IO.scala
@@ -4,7 +4,7 @@
package sbt
import Using._
-import xsbt.ErrorHandling.translate
+import ErrorHandling.translate
import java.io.{ByteArrayOutputStream, BufferedWriter, File, FileInputStream, InputStream, OutputStream}
import java.net.{URI, URISyntaxException, URL}
@@ -24,7 +24,7 @@ object IO
val temporaryDirectory = new File(System.getProperty("java.io.tmpdir"))
/** The size of the byte or char buffer used in various methods.*/
private val BufferSize = 8192
- private val Newline = System.getProperty("line.separator")
+ val Newline = System.getProperty("line.separator")
val utf8 = Charset.forName("UTF-8")
@@ -91,8 +91,38 @@ object IO
else
error(failBase)
}
- def unzip(from: File, toDirectory: File, filter: NameFilter = AllPassFilter): Set[File] = fileInputStream(from)(in => unzip(in, toDirectory, filter))
- def unzip(from: InputStream, toDirectory: File, filter: NameFilter): Set[File] =
+
+ /** Gzips the file 'in' and writes it to 'out'. 'in' cannot be the same file as 'out'. */
+ def gzip(in: File, out: File)
+ {
+ require(in != out, "Input file cannot be the same as the output file.")
+ Using.fileInputStream(in) { inputStream =>
+ Using.fileOutputStream()(out) { outputStream =>
+ gzip(inputStream, outputStream)
+ }
+ }
+ }
+ /** Gzips the InputStream 'in' and writes it to 'output'. Neither stream is closed.*/
+ def gzip(input: InputStream, output: OutputStream): Unit =
+ gzipOutputStream(output) { gzStream => transfer(input, gzStream) }
+
+ /** Gunzips the file 'in' and writes it to 'out'. 'in' cannot be the same file as 'out'. */
+ def gunzip(in: File, out: File)
+ {
+ require(in != out, "Input file cannot be the same as the output file.")
+ Using.fileInputStream(in) { inputStream =>
+ Using.fileOutputStream()(out) { outputStream =>
+ gunzip(inputStream, outputStream)
+ }
+ }
+ }
+ /** Gunzips the InputStream 'input' and writes it to 'output'. Neither stream is closed.*/
+ def gunzip(input: InputStream, output: OutputStream): Unit =
+ gzipInputStream(input) { gzStream => transfer(gzStream, output) }
+
+ def unzip(from: File, toDirectory: File, filter: NameFilter = AllPassFilter): Set[File] = fileInputStream(from)(in => unzipStream(in, toDirectory, filter))
+ def unzipURL(from: URL, toDirectory: File, filter: NameFilter = AllPassFilter): Set[File] = urlInputStream(from)(in => unzipStream(in, toDirectory, filter))
+ def unzipStream(from: InputStream, toDirectory: File, filter: NameFilter = AllPassFilter): Set[File] =
{
createDirectory(toDirectory)
zipInputStream(from) { zipInput => extract(zipInput, toDirectory, filter) }
@@ -135,6 +165,14 @@ object IO
Set() ++ set
}
+ /** Retrieves the content of the given URL and writes it to the given File. */
+ def download(url: URL, to: File) =
+ Using.urlInputStream(url) { inputStream =>
+ Using.fileOutputStream()(to) { outputStream =>
+ transfer(inputStream, outputStream)
+ }
+ }
+
/** Copies all bytes from the given input stream to the given output stream.
* Neither stream is closed.*/
def transfer(in: InputStream, out: OutputStream): Unit = transferImpl(in, out, false)
@@ -185,6 +223,12 @@ object IO
}
create(0)
}
+ def withTemporaryFile[T](prefix: String, postfix: String)(action: File => T): T =
+ {
+ val file = File.createTempFile(prefix, postfix)
+ try { action(file) }
+ finally { file.delete() }
+ }
private[sbt] def jars(dir: File): Iterable[File] = listFiles(dir, GlobFilter("*.jar"))
@@ -205,7 +249,7 @@ object IO
def listFiles(filter: java.io.FileFilter)(dir: File): Array[File] = wrapNull(dir.listFiles(filter))
def listFiles(dir: File, filter: java.io.FileFilter): Array[File] = wrapNull(dir.listFiles(filter))
def listFiles(dir: File): Array[File] = wrapNull(dir.listFiles())
- private def wrapNull(a: Array[File]) =
+ private[sbt] def wrapNull(a: Array[File]) =
{
if(a == null)
new Array[File](0)
@@ -219,14 +263,14 @@ object IO
* @param outputJar The file to write the jar to.
* @param manifest The manifest for the jar.*/
def jar(sources: Iterable[(File,String)], outputJar: File, manifest: Manifest): Unit =
- archive(sources, outputJar, Some(manifest))
+ archive(sources.toSeq, outputJar, Some(manifest))
/** Creates a zip file.
* @param sources The files to include in the zip file paired with the entry name in the zip.
* @param outputZip The file to write the zip to.*/
def zip(sources: Iterable[(File,String)], outputZip: File): Unit =
- archive(sources, outputZip, None)
+ archive(sources.toSeq, outputZip, None)
- private def archive(sources: Iterable[(File,String)], outputFile: File, manifest: Option[Manifest])
+ private def archive(sources: Seq[(File,String)], outputFile: File, manifest: Option[Manifest])
{
if(outputFile.isDirectory)
error("Specified output file " + outputFile + " is a directory.")
@@ -241,7 +285,7 @@ object IO
}
}
}
- private def writeZip(sources: Iterable[(File,String)], output: ZipOutputStream)(createEntry: String => ZipEntry)
+ private def writeZip(sources: Seq[(File,String)], output: ZipOutputStream)(createEntry: String => ZipEntry)
{
def add(sourceFile: File, name: String)
{
@@ -316,22 +360,26 @@ object IO
else
None
}
- def copy(sources: Iterable[(File,File)]): Set[File] = Set( sources.map(tupled(copyImpl)).toSeq.toArray : _*)
- private def copyImpl(from: File, to: File): File =
+ def copy(sources: Iterable[(File,File)], overwrite: Boolean = false, preserveLastModified: Boolean = false): Set[File] =
+ sources.map( tupled(copyImpl(overwrite, preserveLastModified)) ).toSet
+ private def copyImpl(overwrite: Boolean, preserveLastModified: Boolean)(from: File, to: File): File =
{
- if(!to.exists || from.lastModified > to.lastModified)
+ if(overwrite || !to.exists || from.lastModified > to.lastModified)
{
if(from.isDirectory)
createDirectory(to)
else
{
createDirectory(to.getParentFile)
- copyFile(from, to)
+ copyFile(from, to, preserveLastModified)
}
}
to
}
- def copyFile(sourceFile: File, targetFile: File)
+ def copyDirectory(source: File, target: File, overwrite: Boolean = false, preserveLastModified: Boolean = false): Unit =
+ copy( (Path.fromFile(source) ***) x Path.rebase(source, target), overwrite, preserveLastModified)
+
+ def copyFile(sourceFile: File, targetFile: File, preserveLastModified: Boolean = false)
{
require(sourceFile.exists, "Source file '" + sourceFile.getAbsolutePath + "' does not exist.")
require(!sourceFile.isDirectory, "Source file '" + sourceFile.getAbsolutePath + "' is a directory.")
@@ -342,7 +390,10 @@ object IO
error("Could not copy '" + sourceFile + "' to '" + targetFile + "' (" + copied + "/" + in.size + " bytes copied)")
}
}
+ if(preserveLastModified)
+ copyLastModified(sourceFile, targetFile)
}
+ def copyLastModified(sourceFile: File, targetFile: File) = targetFile.setLastModified( sourceFile.lastModified )
def defaultCharset = utf8
def write(file: File, content: String, charset: Charset = defaultCharset, append: Boolean = false): Unit =
writeCharset(file, content, charset, append) { _.write(content) }
@@ -427,7 +478,7 @@ object IO
delete(b)
if(!a.renameTo(b))
{
- copyFile(a, b)
+ copyFile(a, b, true)
delete(a)
}
}
diff --git a/sbt/src/main/scala/sbt/Path.scala b/util/io/Path.scala
similarity index 85%
rename from sbt/src/main/scala/sbt/Path.scala
rename to util/io/Path.scala
index 69c6a6ce3..c2b5e4e64 100644
--- a/sbt/src/main/scala/sbt/Path.scala
+++ b/util/io/Path.scala
@@ -1,32 +1,31 @@
/* sbt -- Simple Build Tool
- * Copyright 2008, 2009 Mark Harrah
+ * Copyright 2008, 2009, 2010 Mark Harrah
*/
package sbt
import Path._
-import FileUtilities.wrapNull
+import IO.{pathSplit, wrapNull}
import java.io.File
import java.net.URL
-import scala.collection.{immutable, mutable}
-import mutable.{Set, HashSet}
+import scala.collection.{generic, immutable, mutable, TraversableLike}
/** A Path represents a file in a project.
* @see sbt.PathFinder*/
-sealed abstract class Path extends PathFinder with NotNull
+sealed abstract class Path extends PathFinder
{
/** Creates a base directory for this path. This is used by copy and zip functions
* to determine the relative path that should be used in the destination. For example,
* if the following path is specified to be copied to directory 'd',
*
- * ((a / b) ##) / x / y
+ * ((a / b) ###) / x / y
*
* the copied path would be
*
* d / x / y
*
* The relativePath method is used to return the relative path to the base directory. */
- override def ## : Path = new BaseDirectory(this)
- private[sbt] def addTo(pathSet: Set[Path])
+ override def ### : Path = new BaseDirectory(this)
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
{
if(asFile.exists)
pathSet += this
@@ -49,7 +48,7 @@ sealed abstract class Path extends PathFinder with NotNull
/** The file represented by this path converted to a URL.*/
def asURL = asFile.toURI.toURL
/** The string representation of this path relative to the base directory. The project directory is the
- * default base directory if one is not specified explicitly using the ## operator.*/
+ * default base directory if one is not specified explicitly using the ### operator.*/
lazy val relativePath: String = relativePathString(sep.toString)
def relativePathString(separator: String): String
final def projectRelativePath: String = projectRelativePathString(sep.toString)
@@ -82,7 +81,7 @@ sealed abstract class Path extends PathFinder with NotNull
}
private final class BaseDirectory(private[sbt] val path: Path) extends Path
{
- override def ## : Path = this
+ override def ### : Path = this
override def toString = path.toString
def asFile = path.asFile
def relativePathString(separator: String) = ""
@@ -124,10 +123,14 @@ private[sbt] final class RelativePath(val parentPath: Path, val component: Strin
parentRelative + separator + component
}
}
-object Path
+object Path extends Alternatives with Mapper
{
import java.io.File
import File.pathSeparator
+ implicit def fileToPath(file: File): Path = Path.fromFile(file)
+ implicit def pathToFile(path: Path): File = path.asFile
+ implicit def pathsToFiles[CC[X] <: TraversableLike[X,CC[X]]](cc: CC[Path])(implicit cb: generic.CanBuildFrom[CC[Path], File, CC[File]]): CC[File] =
+ cc.map(_.asFile)
def fileProperty(name: String) = Path.fromFile(System.getProperty(name))
def userHome = fileProperty("user.home")
@@ -146,7 +149,7 @@ object Path
def splitString(projectPath: Path, value: String): Iterable[Path] =
{
- for(pathString <- FileUtilities.pathSplit(value) if pathString.length > 0) yield
+ for(pathString <- pathSplit(value) if pathString.length > 0) yield
Path.fromString(projectPath, pathString)
}
@@ -154,14 +157,14 @@ object Path
def emptyPathFinder =
new PathFinder
{
- private[sbt] def addTo(pathSet: Set[Path]) {}
+ private[sbt] def addTo(pathSet: mutable.Set[Path]) {}
}
/** A PathFinder that selects the paths provided by the paths argument, which is
* reevaluated on each call to the PathFinder's get method. */
def lazyPathFinder(paths: => Iterable[Path]): PathFinder =
new PathFinder
{
- private[sbt] def addTo(pathSet: Set[Path]) = pathSet ++= paths
+ private[sbt] def addTo(pathSet: mutable.Set[Path]) = pathSet ++= paths
}
def finder(files: => Iterable[File]): PathFinder = lazyPathFinder { fromFiles(files) }
@@ -243,11 +246,8 @@ object Path
def fromFile(file: File): Path = new FilePath(file)
def fromFiles(files: Iterable[File]): Iterable[Path] = files.map(fromFile)
- // done this way because collection.Set.map returns Iterable that is Set underneath, so no need to create a new set
- def mapSet[T](files: Iterable[Path])(f: Path => T): immutable.Set[T] =
- files.map(f) match { case s: immutable.Set[T] => s; case x => immutable.Set() ++ x }
- def getFiles(files: Iterable[Path]): immutable.Set[File] = mapSet(files)(_.asFile)
- def getURLs(files: Iterable[Path]): Array[URL] = files.map(_.asURL).toSeq.toArray
+ def getFiles(files: Traversable[Path]): immutable.Set[File] = files.map(_.asFile).toSet
+ def getURLs(files: Traversable[Path]): Array[URL] = files.map(_.asURL).toArray
}
/** A path finder constructs a set of paths. The set is evaluated by a call to the get
@@ -274,9 +274,20 @@ sealed abstract class PathFinder extends NotNull
final def \ (literal: String): PathFinder = this / literal
/** Makes the paths selected by this finder into base directories.
- * @see Path.##
+ * @see Path.###
*/
- def ## : PathFinder = new BasePathFinder(this)
+ def ### : PathFinder = new BasePathFinder(this)
+
+ /** Applies `mapper` to each path selected by this PathFinder and returns the path paired with the non-empty result.
+ * If the result is empty (None) and `errorIfNone` is true, an exception is thrown.
+ * If `errorIfNone` is false, the path is dropped from the returned Traversable.*/
+ def x[T](mapper: File => Option[T], errorIfNone: Boolean = true): Traversable[(File,T)] =
+ {
+ val apply = if(errorIfNone) mapper | fail else mapper
+ for(file <- getFiles; mapped <- apply(file)) yield (file, mapped)
+ }
+ /** Pairs each path selected by this PathFinder with its relativePath.*/
+ def xx: Traversable[(File, String)] = get.map(path => (path.asFile, path.relativePath))
/** Selects all descendent paths with a name that matches include and do not have an intermediate
* path with a name that matches intermediateExclude. Typical usage is:
@@ -287,11 +298,11 @@ sealed abstract class PathFinder extends NotNull
/** Evaluates this finder. The set returned by this method will reflect the underlying filesystem at the
* time of calling. If the filesystem changes, two calls to this method might be different.*/
- final def get: scala.collection.Set[Path] =
+ final def get: immutable.Set[Path] =
{
- val pathSet = new HashSet[Path]
+ val pathSet = new mutable.HashSet[Path]
addTo(pathSet)
- wrap.Wrappers.readOnly(pathSet)
+ pathSet.toSet
}
/** Only keeps paths for which `f` returns true. It is non-strict, so it is not evaluated until the returned finder is evaluated.*/
final def filter(f: Path => Boolean): PathFinder = Path.lazyPathFinder(get.filter(f))
@@ -305,8 +316,8 @@ sealed abstract class PathFinder extends NotNull
final def getPaths: immutable.Set[String] = strictMap(_.absolutePath)
/** Evaluates this finder and converts the results to a `Set` of relative path strings.*/
final def getRelativePaths: immutable.Set[String] = strictMap(_.relativePath)
- final def strictMap[T](f: Path => T): immutable.Set[T] = Path.mapSet(get)(f)
- private[sbt] def addTo(pathSet: Set[Path])
+ final def strictMap[T](f: Path => T): immutable.Set[T] = get.map(f).toSet
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
/** Create a PathFinder from this one where each path has a unique name.
* A single path is arbitrarily selected from the set of paths with the same name.*/
@@ -321,10 +332,10 @@ sealed abstract class PathFinder extends NotNull
}
private class BasePathFinder(base: PathFinder) extends PathFinder
{
- private[sbt] def addTo(pathSet: Set[Path])
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
{
for(path <- base.get)
- pathSet += (path ##)
+ pathSet += (path ###)
}
}
private abstract class FilterPath extends PathFinder with FileFilter
@@ -333,7 +344,7 @@ private abstract class FilterPath extends PathFinder with FileFilter
def filter: FileFilter
final def accept(file: File) = filter.accept(file)
- protected def handlePath(path: Path, pathSet: Set[Path])
+ protected def handlePath(path: Path, pathSet: mutable.Set[Path])
{
for(matchedFile <- wrapNull(path.asFile.listFiles(this)))
pathSet += path / matchedFile.getName
@@ -341,7 +352,7 @@ private abstract class FilterPath extends PathFinder with FileFilter
}
private class DescendentOrSelfPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterPath
{
- private[sbt] def addTo(pathSet: Set[Path])
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
{
for(path <- parent.get)
{
@@ -350,7 +361,7 @@ private class DescendentOrSelfPathFinder(val parent: PathFinder, val filter: Fil
handlePathDescendent(path, pathSet)
}
}
- private def handlePathDescendent(path: Path, pathSet: Set[Path])
+ private def handlePathDescendent(path: Path, pathSet: mutable.Set[Path])
{
handlePath(path, pathSet)
for(childDirectory <- wrapNull(path.asFile.listFiles(DirectoryFilter)))
@@ -359,7 +370,7 @@ private class DescendentOrSelfPathFinder(val parent: PathFinder, val filter: Fil
}
private class ChildPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterPath
{
- private[sbt] def addTo(pathSet: Set[Path])
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
{
for(path <- parent.get)
handlePath(path, pathSet)
@@ -367,7 +378,7 @@ private class ChildPathFinder(val parent: PathFinder, val filter: FileFilter) ex
}
private class Paths(a: PathFinder, b: PathFinder) extends PathFinder
{
- private[sbt] def addTo(pathSet: Set[Path])
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
{
a.addTo(pathSet)
b.addTo(pathSet)
@@ -375,12 +386,12 @@ private class Paths(a: PathFinder, b: PathFinder) extends PathFinder
}
private class ExcludePaths(include: PathFinder, exclude: PathFinder) extends PathFinder
{
- private[sbt] def addTo(pathSet: Set[Path])
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
{
- val includeSet = new HashSet[Path]
+ val includeSet = new mutable.HashSet[Path]
include.addTo(includeSet)
- val excludeSet = new HashSet[Path]
+ val excludeSet = new mutable.HashSet[Path]
exclude.addTo(excludeSet)
includeSet --= excludeSet
diff --git a/util/io/PathMapper.scala b/util/io/PathMapper.scala
index 4d3ab2ee4..fd0327225 100644
--- a/util/io/PathMapper.scala
+++ b/util/io/PathMapper.scala
@@ -5,45 +5,50 @@ package sbt
import java.io.File
-trait PathMapper extends NotNull
+trait Mapper
{
- def apply(file: File): String
- def apply(files: Set[File]): Iterable[(File,String)] = files.view.map(f => (f,apply(f)))
-}
-final case class RelativePathMapper(base: File) extends PMapper(file => IO.relativize(base, file).getOrElse(file.getPath))
-final case object BasicPathMapper extends PMapper(_.getPath)
-final case object FlatPathMapper extends PMapper(_.getName)
-class PMapper(val f: File => String) extends PathMapper
-{
- def apply(file: File): String = f(file)
-}
-object PathMapper
-{
- val basic: PathMapper = BasicPathMapper
- def relativeTo(base: File): PathMapper = RelativePathMapper(base)
- def rebase(oldBase: File, newBase: File): PathMapper =
- new PMapper(file => if(file == oldBase) "." else IO.relativize(oldBase, file).getOrElse(error(file + " not a descendent of " + oldBase)))
- val flat = FlatPathMapper
- def apply(f: File => String): PathMapper = new PMapper(f)
+ type PathMap = File => Option[String]
+ type FileMap = File => Option[File]
+
+ val basic: PathMap = f => Some(f.getPath)
+ def relativeTo(base: File): PathMap = IO.relativize(base, _)
+ def rebase(oldBase: File, newBase0: String): PathMap =
+ {
+ val newBase = normalizeBase(newBase0)
+ (file: File) =>
+ if(file == oldBase)
+ Some( if(newBase.isEmpty) "." else newBase )
+ else
+ IO.relativize(oldBase, file).map(newBase + _)
+ }
+ def fail: Any => Nothing = f => error("No mapping for " + f)
+ val flat: PathMap = f => Some(f.getName)
+ def flatRebase(newBase0: String): PathMap =
+ {
+ val newBase = normalizeBase(newBase0)
+ f => Some(newBase + f.getName)
+ }
+ def some[A,B](f: A => B): A => Some[B] = x => Some(f(x))
+
+ def normalizeBase(base: String) = if(!base.isEmpty && !base.endsWith("/")) base + "/" else base
+
+ def abs: FileMap = f => Some(f.getAbsoluteFile)
+ def resolve(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getPath))
+ def rebase(oldBase: File, newBase: File): FileMap =
+ file =>
+ if(file == oldBase)
+ Some(newBase)
+ else
+ IO.relativize(oldBase, file) map { r => new File(newBase, r) }
+
+ def flat(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getName))
}
-trait FileMapper extends NotNull
+trait Alternative[A,B] { def | (g: A => Option[B]): A => Option[B] }
+trait Alternatives
{
- def apply(file: File): File
- def apply(files: Set[File]): Iterable[(File,File)] = files.view.map(f => (f,apply(f)))
-}
-class FMapper(f: File => File) extends FileMapper
-{
- def apply(file: File) = f(file)
-}
-object FileMapper
-{
- def basic(newDirectory: File) = new FMapper(file => new File(newDirectory, file.getPath))
- def rebase(oldBase: File, newBase: File): FileMapper =
- {
- val paths = PathMapper.rebase(oldBase, newBase)
- new FMapper(file => new File(newBase, paths(file)))
- }
- def flat(newDirectory: File) = new FMapper(file => new File(newDirectory, file.getName))
- def apply(f: File => File) = new FMapper(f)
+ implicit def alternative[A,B](f:A => Option[B]): Alternative[A,B] =
+ new Alternative[A,B] { def | (g: A => Option[B]) =
+ (a: A) => f(a) orElse g(a)
+ }
}
\ No newline at end of file
diff --git a/util/io/Paths.scala b/util/io/Paths.scala
deleted file mode 100644
index 79ea148b4..000000000
--- a/util/io/Paths.scala
+++ /dev/null
@@ -1,51 +0,0 @@
-/* sbt -- Simple Build Tool
- * Copyright 2008, 2009, 2010 Mark Harrah
- */
-package sbt
-
-import java.io.File
-import java.net.URL
-
-object Paths
-{
- implicit def stringToPath(s: String): Path = new Path(new File(s))
- implicit def fileToPath(f: File): Path = new Path(f)
- implicit def pathToFile(p: Path): File = p.asFile
- implicit def filesToPaths(fs: Set[File]): Paths = new Paths(fs)
- implicit def filesToPaths(fs: Iterable[File]): Paths =
- fs match
- {
- case s: Set[File] => filesToPaths(s)
- case _ => new Paths(Set(fs.toSeq : _*))
- }
- def normalize(path: String): String = path.replace('/', File.separatorChar).replace('\\', File.separatorChar)
-}
-
-import Paths._
-trait PathBase extends NotNull
-{
- def files: Set[File]
- def urls: Array[URL] = files.toArray[File].map(_.toURI.toURL)
- def x(mapper: PathMapper): Iterable[(File,String)] = mapper(files)
- def x(mapper: FileMapper): Iterable[(File,File)] = mapper(files)
- def *(filter: java.io.FileFilter): Set[File] = files.flatMap(IO.listFiles(filter))
- def **(filter: java.io.FileFilter): Set[File] = files.filter(filter.accept) ++ files.flatMap(_ * AllPassFilter ** filter)
- def *** = **(AllPassFilter)
- def abs = files.map(_.getAbsoluteFile)
- def descendentsExcept(include: java.io.FileFilter, intermediateExclude: java.io.FileFilter): Set[File] =
- (this ** include) -- (this ** intermediateExclude ** include)
-}
-
-final class Paths(val files: Set[File]) extends PathBase
-{
- def \(subPath: String) = /(subPath)
- def /(subPath: String): Set[File] = files.flatMap { file => val f = file / subPath; if(f.exists) Seq(f) else Seq() }
-}
-final class Path(val asFile: File) extends PathBase
-{
- def files = Set(asFile)
- def \(subPath: String) = /(subPath)
- def /(subPath: String) = new File(asFile, normalize(subPath))
- def ++(files: Set[File]) = files + asFile
- def ++(file: File) = Set(file, asFile)
-}
\ No newline at end of file
diff --git a/util/io/Using.scala b/util/io/Using.scala
index be93e25f0..731c8ca8d 100644
--- a/util/io/Using.scala
+++ b/util/io/Using.scala
@@ -4,7 +4,7 @@
package sbt
import java.io.{Closeable, File, FileInputStream, FileOutputStream, InputStream, OutputStream}
-import java.io.{ByteArrayOutputStream, InputStreamReader, OutputStreamWriter}
+import java.io.{BufferedInputStream, BufferedOutputStream, ByteArrayOutputStream, InputStreamReader, OutputStreamWriter}
import java.io.{BufferedReader, BufferedWriter, FileReader, FileWriter, Reader, Writer}
import java.util.zip.{GZIPInputStream, GZIPOutputStream}
import java.net.{URL, URISyntaxException}
@@ -13,7 +13,7 @@ import java.nio.channels.FileChannel
import java.util.jar.{Attributes, JarEntry, JarFile, JarInputStream, JarOutputStream, Manifest}
import java.util.zip.{GZIPOutputStream, ZipEntry, ZipFile, ZipInputStream, ZipOutputStream}
-import xsbt.ErrorHandling.translate
+import ErrorHandling.translate
import Using._
abstract class Using[Source, T] extends NotNull
@@ -74,8 +74,8 @@ object Using
}
private def closeCloseable[T <: Closeable]: T => Unit = _.close()
- def fileOutputStream(append: Boolean = false) = file(f => new FileOutputStream(f, append))
- def fileInputStream = file(f => new FileInputStream(f))
+ def fileOutputStream(append: Boolean = false) = file(f => new BufferedOutputStream(new FileOutputStream(f, append)))
+ def fileInputStream = file(f => new BufferedInputStream(new FileInputStream(f)))
def urlInputStream = resource( (u: URL) => translate("Error opening " + u + ": ")(u.openStream))
def fileOutputChannel = file(f => new FileOutputStream(f).getChannel)
def fileInputChannel = file(f => new FileInputStream(f).getChannel)
diff --git a/sbt/src/test/scala/sbt/PathSpecification.scala b/util/io/src/test/scala/PathSpecification.scala
similarity index 81%
rename from sbt/src/test/scala/sbt/PathSpecification.scala
rename to util/io/src/test/scala/PathSpecification.scala
index be3123f0c..888e175dd 100644
--- a/sbt/src/test/scala/sbt/PathSpecification.scala
+++ b/util/io/src/test/scala/PathSpecification.scala
@@ -10,9 +10,6 @@ import java.io.File
object PathSpecification extends Properties("Path")
{
- val log = new ConsoleLogger
- log.setLevel(Level.Warn)
-
// certain operations require a real underlying file. We'd like to create them in a managed temporary directory so that junk isn't left over from the test.
// The arguments to several properties are functions that construct a Path or PathFinder given a base directory.
type ToPath = ProjectDirectory => Path
@@ -33,7 +30,7 @@ object PathSpecification extends Properties("Path")
}
property("Relative path") = forAll { (a: List[String], b: List[String]) =>
inTemp { dir =>
- pathForComponents(pathForComponents(dir, a) ##, b).relativePath == pathString(b) }
+ pathForComponents(pathForComponents(dir, a) ###, b).relativePath == pathString(b) }
}
property("Proper URL conversion") = forAll { (tp: ToPath) =>
withPath(tp) { path => path.asURL == path.asFile.toURI.toURL }
@@ -43,7 +40,7 @@ object PathSpecification extends Properties("Path")
}
property("Base path equality") = forAll { (a: List[String], b: List[String]) =>
inTemp { dir =>
- pathForComponents(pathForComponents(dir, a) ##, b) == pathForComponents(pathForComponents(dir, a) ##, b)
+ pathForComponents(pathForComponents(dir, a) ###, b) == pathForComponents(pathForComponents(dir, a) ###, b)
}
}
@@ -86,15 +83,15 @@ object PathSpecification extends Properties("Path")
inTemp { dir =>
val bases = repeat(baseDirs(dir).get)
val reallyDistinct: Set[String] = Set() ++ distinctNames -- dupNames.map(_._1)
- val dupList = dupNames.flatMap { case (name, repeat) => if(reallyDistinct(name)) Nil else List.make(repeat, name) }
+ val dupList = dupNames.flatMap { case (name, repeat) => if(reallyDistinct(name)) Nil else List.fill(repeat)(name) }
def create(names: List[String]): PathFinder =
{
val paths = (bases zip names ).map { case (a, b) => a / b }.filter(!_.exists)
- paths.foreach { f => xsbt.FileUtilities.touch(f asFile) }
+ paths.foreach { f => IO.touch(f asFile) }
Path.lazyPathFinder(paths)
}
- def names(s: scala.collection.Set[Path]) = s.map(_.name)
+ def names(s: Set[Path]) = s.map(_.name)
val distinctPaths = create(reallyDistinct.toList)
val dupPaths = create(dupList)
@@ -102,15 +99,22 @@ object PathSpecification extends Properties("Path")
val all = distinctPaths +++ dupPaths
val distinct = all.distinct.get
- val allNames = Set() ++ names(all.get)
+ val allNames = names(all.get)
- (Set() ++ names(distinct)) == allNames && // verify nothing lost
+ names(distinct) == allNames && // verify nothing lost
distinct.size == allNames.size // verify duplicates removed
} } catch { case e => e.printStackTrace; throw e}
}
- private def repeat[T](s: Iterable[T]): List[T] =
- List.make(100, ()).flatMap(_ => s) // should be an infinite Stream, but Stream isn't very lazy
+ def repeat[T](s: Iterable[T]): Stream[T] =
+ {
+ def toStr(l: List[T]): Stream[T] = l match {
+ case Nil => st
+ case x :: xs => Stream.cons(x, toStr(xs))
+ }
+ lazy val st = if(s.isEmpty) Stream.empty else toStr(s.toList)
+ st
+ }
private def withPath[T](tp: ToPath)(f: Path => T): T =
@@ -119,24 +123,12 @@ object PathSpecification extends Properties("Path")
inTemp { dir => f(ta(dir), tb(dir)) }
private def createFileAndDo(a: List[String], b: List[String])(f: Path => Boolean) =
- {
- val result =
- FileUtilities.doInTemporaryDirectory(log)( dir =>
- {
- FileUtilities.touch(fileForComponents(dir, a ::: b), log) match
- {
- case None => Right(Some( f(new ProjectDirectory(dir)) ))
- case Some(err) => Left(err)
- }
- })
- result match
- {
- case Left(err) => throw new RuntimeException(err)
- case Right(opt) => opt.isDefined ==> opt.get
+ IO.withTemporaryDirectory { dir =>
+ IO.touch(fileForComponents(dir, a ::: b))
+ f(new ProjectDirectory(dir))
}
- }
private def inTemp[T](f: ProjectDirectory => T): T =
- xsbt.FileUtilities.withTemporaryDirectory { dir => f(new ProjectDirectory(dir)) }
+ IO.withTemporaryDirectory { dir => f(new ProjectDirectory(dir)) }
private def pathString(components: List[String]): String = components.mkString(File.separator)
private def pathForComponents(base: Path, components: List[String]): Path =
@@ -148,7 +140,7 @@ object PathSpecification extends Properties("Path")
for(dir <- d; name <- s) yield {
(projectPath: ProjectDirectory) =>
val f = dir(projectPath) / name
- xsbt.FileUtilities.touch(f asFile)
+ IO.touch(f asFile)
f
}
@@ -161,7 +153,7 @@ object PathSpecification extends Properties("Path")
for(p <- genPath) yield {
(projectPath: ProjectDirectory) => {
val f = p(projectPath)
- xsbt.FileUtilities.createDirectory(f asFile)
+ IO.createDirectory(f asFile)
f
}
}
@@ -176,7 +168,7 @@ object PathSpecification extends Properties("Path")
b match
{
case None => base
- case Some(relative) => pathForComponents(base ##, relative)
+ case Some(relative) => pathForComponents(base ###, relative)
}
}
private implicit lazy val componentList: Gen[List[String]] = genList[String](MaxComponentCount)(pathComponent.arbitrary)
@@ -185,7 +177,7 @@ object PathSpecification extends Properties("Path")
for(size <- Gen.choose(0, maxSize); a <- Gen.listOfN(size, genA)) yield a
private def trim(components: List[String]): List[String] = components.take(MaxComponentCount)
- private def trim(component: String): String = component.substring(0, Math.min(component.length, MaxFilenameLength))
+ private def trim(component: String): String = component.substring(0, math.min(component.length, MaxFilenameLength))
final val MaxFilenameLength = 20
final val MaxComponentCount = 6
diff --git a/util/io/src/test/scala/StashSpec.scala b/util/io/src/test/scala/StashSpec.scala
index df76165d2..6f3fe2841 100644
--- a/util/io/src/test/scala/StashSpec.scala
+++ b/util/io/src/test/scala/StashSpec.scala
@@ -1,11 +1,11 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah */
-package xsbt
+package sbt
import org.specs._
-import FileUtilities._
+import IO._
import java.io.File
import Function.tupled
@@ -14,6 +14,7 @@ object CheckStash extends Specification
"stash" should {
"handle empty files" in {
stash(Set()) { }
+ true must beTrue
}
"move files during execution" in {
@@ -57,7 +58,7 @@ object CheckStash extends Specification
case _: TestError | _: TestException | _: TestRuntimeException => false
}
- def allCorrect(s: Seq[File]) = (s.toList zip TestFiles.toList).forall(tupled(correct))
+ def allCorrect(s: Seq[File]) = (s.toList zip TestFiles.toList).foreach((correct _).tupled)
def correct(check: File, ref: (File, String)) =
{
check.exists must beTrue
diff --git a/sbt/src/test/scala/sbt/LogWriterTest.scala b/util/log/src/test/scala/LogWriterTest.scala
similarity index 93%
rename from sbt/src/test/scala/sbt/LogWriterTest.scala
rename to util/log/src/test/scala/LogWriterTest.scala
index 0d4dac14d..6d01341a0 100644
--- a/sbt/src/test/scala/sbt/LogWriterTest.scala
+++ b/util/log/src/test/scala/LogWriterTest.scala
@@ -5,13 +5,16 @@ package sbt
import org.scalacheck._
import Arbitrary.{arbitrary => arb, _}
-import Gen.{oneOf, value}
+import Gen.{listOfN, oneOf}
import Prop._
import java.io.Writer
object LogWriterTest extends Properties("Log Writer")
{
+ final val MaxLines = 100
+ final val MaxSegments = 10
+
/* Tests that content written through a LoggerWriter is properly passed to the underlying Logger.
* Each line, determined by the specified newline separator, must be logged at the correct logging level. */
property("properly logged") = forAll { (output: Output, newLine: NewLine) =>
@@ -72,7 +75,7 @@ object LogWriterTest extends Properties("Log Writer")
implicit lazy val arbLevel : Arbitrary[Level.Value] = Arbitrary(genLevel)
implicit def genLine(implicit logG: Gen[ToLog]): Gen[List[ToLog]] =
- for(l <- arbList[ToLog].arbitrary; last <- logG) yield
+ for(l <- listOf[ToLog](MaxSegments); last <- logG) yield
(addNewline(last) :: l.filter(!_.content.isEmpty)).reverse
implicit def genLog(implicit content: Arbitrary[String], byChar: Arbitrary[Boolean]): Gen[ToLog] =
@@ -87,17 +90,18 @@ object LogWriterTest extends Properties("Log Writer")
new NewLine(str)
implicit lazy val genLevel: Gen[Level.Value] =
- oneOf(levelsGen : _*)
+ oneOf(Level.values.toSeq)
implicit lazy val genOutput: Gen[Output] =
- for(ls <- arbList[List[ToLog]].arbitrary; lv <- genLevel) yield
+ for(ls <- listOf[List[ToLog]](MaxLines); lv <- genLevel) yield
new Output(ls, lv)
- def levelsGen: Seq[Gen[Level.Value]] = Level.values.toList.map(x => value(x))
-
def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "")
def addNewline(l: ToLog): ToLog =
new ToLog(l.content + "\n", l.byCharacter) // \n will be replaced by a random line terminator for all lines
+
+ def listOf[T](max: Int)(implicit content: Arbitrary[T]): Gen[List[T]] =
+ Gen.choose(0, max) flatMap { sz => listOfN(sz, content.arbitrary) }
}
/* Helper classes*/