mirror of https://github.com/sbt/sbt.git
more reorganization, mostly IO. Also, move class file analyzer and history code to separate projects
This commit is contained in:
parent
d73762e203
commit
1585d805bd
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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] =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
package xsbt
|
||||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2009 Mark Harrah
|
||||
*/
|
||||
package sbt
|
||||
|
||||
import java.io.{InputStream,OutputStream}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
package sbt
|
||||
|
||||
object ChangeReport
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ public interface AnalysisCallback
|
|||
/** Called to indicate that the source file <code>source</code> depends on the class file
|
||||
* <code>clazz</code>.*/
|
||||
public void classDependency(File clazz, File source);
|
||||
/** Called to indicate that the source file <code>sourcePath</code> depends on the class file
|
||||
* <code>classFile</code> that is a product of some source. This differs from classDependency
|
||||
* because it is really a sourceDependency. The source corresponding to <code>classFile</code>
|
||||
* 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 <code>source</code> produces a class file at
|
||||
* <code>module</code>.*/
|
||||
public void generatedClass(File source, File module);
|
||||
|
|
|
|||
|
|
@ -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)) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*/ )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* <code>(basePath ##) / x / y</code> is <code>x / y</code>.
|
||||
* <code>(basePath ###) / x / y</code> is <code>x / y</code>.
|
||||
* @param outputJar The file to write the jar to.
|
||||
* @param manifest The manifest for the jar.
|
||||
* @param recursive If true, any directories in <code>sources</code> 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
|
||||
* <code>(basePath ##) / x / y</code> is <code>x / y</code>.
|
||||
* <code>(basePath ###) / x / y</code> is <code>x / y</code>.
|
||||
* @param outputZip The file to write the zip to.
|
||||
* @param recursive If true, any directories in <code>sources</code> 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 <code>(basePath ##) / x / y</code> is copied to <code>destinationDirectory / x / y</code>.
|
||||
* A source <code>(basePath ###) / x / y</code> is copied to <code>destinationDirectory / x / y</code>.
|
||||
*
|
||||
* @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 <code>sourceDirectory</code> directory to the
|
||||
* <code>targetDirectory</code> 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
|
||||
|
|
|
|||
|
|
@ -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"""))
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
@ -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) }
|
||||
|
|
@ -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 !!
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
*
|
||||
* <code>((a / b) ##) / x / y</code>
|
||||
* <code>((a / b) ###) / x / y</code>
|
||||
*
|
||||
* the copied path would be
|
||||
*
|
||||
* <code>d / x / y</code>
|
||||
*
|
||||
* The <code>relativePath</code> 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 <code>URL</code>.*/
|
||||
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 <code>##</code> operator.*/
|
||||
* default base directory if one is not specified explicitly using the <code>###</code> 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 <code>PathFinder</code> that selects the paths provided by the <code>paths</code> argument, which is
|
||||
* reevaluated on each call to the <code>PathFinder</code>'s <code>get</code> 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 <code>get</code>
|
||||
|
|
@ -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 <code>include</code> and do not have an intermediate
|
||||
* path with a name that matches <code>intermediateExclude</code>. 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
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
Loading…
Reference in New Issue