first update of io for 2.8

This commit is contained in:
Mark Harrah 2010-06-09 00:56:07 -04:00
parent 5eed8ccbef
commit d1260eebd1
9 changed files with 75 additions and 81 deletions

View File

@ -82,8 +82,9 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
} }
trait TestDependencies extends Project trait TestDependencies extends Project
{ {
val sc = "org.scala-tools.testing" %% "scalacheck" % "1.6" % "test" val sc = "org.scala-tools.testing" %% "scalacheck" % "1.7" % "test"
val sp = "org.scala-tools.testing" % "specs" % "1.6.0" % "test" val sp = "org.scala-tools.testing" %% "specs" % "1.6.5-SNAPSHOT" % "test"
val snaps = ScalaToolsSnapshots
} }
class StandardTaskProject(info: ProjectInfo) extends Base(info) class StandardTaskProject(info: ProjectInfo) extends Base(info)
{ {

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah * Copyright 2009 Mark Harrah
*/ */
package xsbt package sbt
import java.io.{ByteArrayInputStream, File, InputStream} import java.io.{ByteArrayInputStream, File, InputStream}
@ -35,7 +35,7 @@ object Hash
/** Calculates the SHA-1 hash of the given String.*/ /** Calculates the SHA-1 hash of the given String.*/
def apply(s: String): Array[Byte] = apply(new ByteArrayInputStream(s.getBytes("UTF-8"))) def apply(s: String): Array[Byte] = apply(new ByteArrayInputStream(s.getBytes("UTF-8")))
/** Calculates the SHA-1 hash of the given file.*/ /** Calculates the SHA-1 hash of the given file.*/
def apply(file: File): Array[Byte] = OpenResource.fileInputStream(file)(apply) def apply(file: File): Array[Byte] = Using.fileInputStream(file)(apply)
/** Calculates the SHA-1 hash of the given stream, closing it when finished.*/ /** Calculates the SHA-1 hash of the given stream, closing it when finished.*/
def apply(stream: InputStream): Array[Byte] = def apply(stream: InputStream): Array[Byte] =
{ {

View File

@ -1,10 +1,10 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009, 2010 Mark Harrah
*/ */
package xsbt package sbt
import OpenResource._ import Using._
import ErrorHandling.translate import xsbt.ErrorHandling.translate
import java.io.{ByteArrayOutputStream, BufferedWriter, File, FileInputStream, InputStream, OutputStream} import java.io.{ByteArrayOutputStream, BufferedWriter, File, FileInputStream, InputStream, OutputStream}
import java.net.{URI, URISyntaxException, URL} import java.net.{URI, URISyntaxException, URL}
@ -15,7 +15,7 @@ import scala.collection.mutable.HashSet
import scala.reflect.{Manifest => SManifest} import scala.reflect.{Manifest => SManifest}
import Function.tupled import Function.tupled
object FileUtilities object IO
{ {
/** The maximum number of times a unique temporary filename is attempted to be created.*/ /** The maximum number of times a unique temporary filename is attempted to be created.*/
private val MaximumTries = 10 private val MaximumTries = 10
@ -26,7 +26,7 @@ object FileUtilities
private val BufferSize = 8192 private val BufferSize = 8192
private val Newline = System.getProperty("line.separator") private val Newline = System.getProperty("line.separator")
def utf8 = Charset.forName("UTF-8") val utf8 = Charset.forName("UTF-8")
def classLocation(cl: Class[_]): URL = def classLocation(cl: Class[_]): URL =
{ {
@ -91,8 +91,7 @@ object FileUtilities
else else
error(failBase) error(failBase)
} }
def unzip(from: File, toDirectory: File): Set[File] = unzip(from, toDirectory, AllPassFilter) def unzip(from: File, toDirectory: File, filter: NameFilter = AllPassFilter): Set[File] = fileInputStream(from)(in => unzip(in, toDirectory, filter))
def unzip(from: File, toDirectory: File, filter: NameFilter): Set[File] = fileInputStream(from)(in => unzip(in, toDirectory, filter))
def unzip(from: InputStream, toDirectory: File, filter: NameFilter): Set[File] = def unzip(from: InputStream, toDirectory: File, filter: NameFilter): Set[File] =
{ {
createDirectory(toDirectory) createDirectory(toDirectory)
@ -187,7 +186,7 @@ object FileUtilities
create(0) create(0)
} }
private[xsbt] def jars(dir: File): Iterable[File] = listFiles(dir, GlobFilter("*.jar")) private[sbt] def jars(dir: File): Iterable[File] = listFiles(dir, GlobFilter("*.jar"))
def delete(files: Iterable[File]): Unit = files.foreach(delete) def delete(files: Iterable[File]): Unit = files.foreach(delete)
def delete(file: File) def delete(file: File)
@ -246,21 +245,24 @@ object FileUtilities
{ {
def add(sourceFile: File, name: String) def add(sourceFile: File, name: String)
{ {
if(sourceFile.isDirectory) if(!sourceFile.exists)
()
else if(sourceFile.exists)
{
val nextEntry = createEntry(normalizeName(name))
nextEntry.setTime(sourceFile.lastModified)
output.putNextEntry(nextEntry)
transferAndClose(new FileInputStream(sourceFile), output)
}
else
error("Source " + sourceFile + " does not exist.") error("Source " + sourceFile + " does not exist.")
val isDirectory = sourceFile.isDirectory
val relName = if(isDirectory) normalizeDirName(name) else normalizeName(name)
val nextEntry = createEntry(relName)
nextEntry.setTime(sourceFile.lastModified)
output.putNextEntry(nextEntry)
if(!isDirectory)
transfer(new FileInputStream(sourceFile), output)
} }
sources.foreach(tupled(add)) sources.foreach((add _).tupled)
output.closeEntry() output.closeEntry()
} }
private def normalizeDirName(name: String) =
{
val norm1 = normalizeName(name)
if(norm1.endsWith("/")) norm1 else (norm1 + "/")
}
private def normalizeName(name: String) = private def normalizeName(name: String) =
{ {
val sep = File.separatorChar val sep = File.separatorChar
@ -308,10 +310,8 @@ object FileUtilities
{ {
val cp = baseFile.getAbsolutePath val cp = baseFile.getAbsolutePath
assert(cp.length > 0) assert(cp.length > 0)
if(cp.charAt(cp.length - 1) == File.separatorChar) val normalized = if(cp.charAt(cp.length - 1) == File.separatorChar) cp else cp + File.separatorChar
Some(cp) Some(normalized)
else
Some(cp + File.separatorChar)
} }
else else
None None
@ -344,9 +344,7 @@ object FileUtilities
} }
} }
def defaultCharset = utf8 def defaultCharset = utf8
def write(toFile: File, content: String): Unit = write(toFile, content, defaultCharset) def write(file: File, content: String, charset: Charset = defaultCharset, append: Boolean = false): Unit =
def write(toFile: File, content: String, charset: Charset): Unit = write(toFile, content, charset, false)
def write(file: File, content: String, charset: Charset, append: Boolean): Unit =
writeCharset(file, content, charset, append) { _.write(content) } writeCharset(file, content, charset, append) { _.write(content) }
def writeCharset[T](file: File, content: String, charset: Charset, append: Boolean)(f: BufferedWriter => T): T = def writeCharset[T](file: File, content: String, charset: Charset, append: Boolean)(f: BufferedWriter => T): T =
@ -357,17 +355,14 @@ object FileUtilities
error("String cannot be encoded by charset " + charset.name) error("String cannot be encoded by charset " + charset.name)
} }
def read(file: File): String = read(file, defaultCharset) def read(file: File, charset: Charset = defaultCharset): String =
def read(file: File, charset: Charset): String =
{ {
val out = new ByteArrayOutputStream(file.length.toInt) val out = new ByteArrayOutputStream(file.length.toInt)
fileInputStream(file){ in => transfer(in, out) } fileInputStream(file){ in => transfer(in, out) }
out.toString(charset.name) out.toString(charset.name)
} }
/** doesn't close the InputStream */ /** doesn't close the InputStream */
def read(in: InputStream): String = read(in, defaultCharset) def readStream(in: InputStream, charset: Charset = defaultCharset): String =
/** doesn't close the InputStream */
def read(in: InputStream, charset: Charset): String =
{ {
val out = new ByteArrayOutputStream val out = new ByteArrayOutputStream
transfer(in, out) transfer(in, out)
@ -383,8 +378,7 @@ object FileUtilities
} }
// Not optimized for large files // Not optimized for large files
def readLines(file: File): List[String] = readLines(file, defaultCharset) def readLines(file: File, charset: Charset = defaultCharset): List[String] =
def readLines(file: File, charset: Charset): List[String] =
{ {
fileReader(charset)(file){ in => fileReader(charset)(file){ in =>
def readLine(accum: List[String]): List[String] = def readLine(accum: List[String]): List[String] =
@ -395,9 +389,7 @@ object FileUtilities
readLine(Nil) readLine(Nil)
} }
} }
def writeLines(file: File, lines: Seq[String]): Unit = writeLines(file, lines, defaultCharset) def writeLines(file: File, lines: Seq[String], charset: Charset = defaultCharset, append: Boolean = false): Unit =
def writeLines(file: File, lines: Seq[String], charset: Charset): Unit = writeLines(file, lines, charset, false)
def writeLines(file: File, lines: Seq[String], charset: Charset, append: Boolean): Unit =
writeCharset(file, lines.headOption.getOrElse(""), charset, append) { w => writeCharset(file, lines.headOption.getOrElse(""), charset, append) { w =>
lines.foreach { line => w.write(line); w.newLine() } lines.foreach { line => w.write(line); w.newLine() }
} }

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009 Mark Harrah
*/ */
package xsbt package sbt
import java.io.File import java.io.File
import java.util.regex.Pattern import java.util.regex.Pattern

View File

@ -1,16 +1,16 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009 Mark Harrah
*/ */
package xsbt package sbt
import java.io.File import java.io.File
trait PathMapper extends NotNull trait PathMapper extends NotNull
{ {
def apply(file: File): String def apply(file: File): String
def apply(files: Set[File]): Iterable[(File,String)] = files.projection.map(f => (f,apply(f))) def apply(files: Set[File]): Iterable[(File,String)] = files.view.map(f => (f,apply(f)))
} }
final case class RelativePathMapper(base: File) extends PMapper(file => FileUtilities.relativize(base, file).getOrElse(file.getPath)) 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 BasicPathMapper extends PMapper(_.getPath)
final case object FlatPathMapper extends PMapper(_.getName) final case object FlatPathMapper extends PMapper(_.getName)
class PMapper(val f: File => String) extends PathMapper class PMapper(val f: File => String) extends PathMapper
@ -22,7 +22,7 @@ object PathMapper
val basic: PathMapper = BasicPathMapper val basic: PathMapper = BasicPathMapper
def relativeTo(base: File): PathMapper = RelativePathMapper(base) def relativeTo(base: File): PathMapper = RelativePathMapper(base)
def rebase(oldBase: File, newBase: File): PathMapper = def rebase(oldBase: File, newBase: File): PathMapper =
new PMapper(file => if(file == oldBase) "." else FileUtilities.relativize(oldBase, file).getOrElse(error(file + " not a descendent of " + oldBase))) new PMapper(file => if(file == oldBase) "." else IO.relativize(oldBase, file).getOrElse(error(file + " not a descendent of " + oldBase)))
val flat = FlatPathMapper val flat = FlatPathMapper
def apply(f: File => String): PathMapper = new PMapper(f) def apply(f: File => String): PathMapper = new PMapper(f)
} }
@ -30,7 +30,7 @@ object PathMapper
trait FileMapper extends NotNull trait FileMapper extends NotNull
{ {
def apply(file: File): File def apply(file: File): File
def apply(files: Set[File]): Iterable[(File,File)] = files.projection.map(f => (f,apply(f))) def apply(files: Set[File]): Iterable[(File,File)] = files.view.map(f => (f,apply(f)))
} }
class FMapper(f: File => File) extends FileMapper class FMapper(f: File => File) extends FileMapper
{ {

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009, 2010 Mark Harrah * Copyright 2008, 2009, 2010 Mark Harrah
*/ */
package xsbt package sbt
import java.io.File import java.io.File
import java.net.URL import java.net.URL
@ -28,7 +28,7 @@ trait PathBase extends NotNull
def urls: Array[URL] = files.toArray[File].map(_.toURI.toURL) def urls: Array[URL] = files.toArray[File].map(_.toURI.toURL)
def x(mapper: PathMapper): Iterable[(File,String)] = mapper(files) def x(mapper: PathMapper): Iterable[(File,String)] = mapper(files)
def x(mapper: FileMapper): Iterable[(File,File)] = mapper(files) def x(mapper: FileMapper): Iterable[(File,File)] = mapper(files)
def *(filter: java.io.FileFilter): Set[File] = files.flatMap(FileUtilities.listFiles(filter)) 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 **(filter: java.io.FileFilter): Set[File] = files.filter(filter.accept) ++ files.flatMap(_ * AllPassFilter ** filter)
def *** = **(AllPassFilter) def *** = **(AllPassFilter)
def abs = files.map(_.getAbsoluteFile) def abs = files.map(_.getAbsoluteFile)

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah * Copyright 2008, 2009 Mark Harrah
*/ */
package xsbt package sbt
import java.io.{Closeable, File, FileInputStream, FileOutputStream, InputStream, OutputStream} import java.io.{Closeable, File, FileInputStream, FileOutputStream, InputStream, OutputStream}
import java.io.{ByteArrayOutputStream, InputStreamReader, OutputStreamWriter} import java.io.{ByteArrayOutputStream, InputStreamReader, OutputStreamWriter}
@ -13,10 +13,10 @@ import java.nio.channels.FileChannel
import java.util.jar.{Attributes, JarEntry, JarFile, JarInputStream, JarOutputStream, Manifest} import java.util.jar.{Attributes, JarEntry, JarFile, JarInputStream, JarOutputStream, Manifest}
import java.util.zip.{GZIPOutputStream, ZipEntry, ZipFile, ZipInputStream, ZipOutputStream} import java.util.zip.{GZIPOutputStream, ZipEntry, ZipFile, ZipInputStream, ZipOutputStream}
import ErrorHandling.translate import xsbt.ErrorHandling.translate
import OpenResource._ import Using._
abstract class OpenResource[Source, T] extends NotNull abstract class Using[Source, T] extends NotNull
{ {
protected def open(src: Source): T protected def open(src: Source): T
def apply[R](src: Source)(f: T => R): R = def apply[R](src: Source)(f: T => R): R =
@ -28,57 +28,58 @@ abstract class OpenResource[Source, T] extends NotNull
protected def close(out: T): Unit protected def close(out: T): Unit
} }
import scala.reflect.{Manifest => SManifest} import scala.reflect.{Manifest => SManifest}
abstract class WrapOpenResource[Source, T](implicit srcMf: SManifest[Source], targetMf: SManifest[T]) extends OpenResource[Source, T] abstract class WrapUsing[Source, T](implicit srcMf: SManifest[Source], targetMf: SManifest[T]) extends Using[Source, T]
{ {
protected def label[S](m: SManifest[S]) = m.erasure.getSimpleName protected def label[S](m: SManifest[S]) = m.erasure.getSimpleName
protected def openImpl(source: Source): T protected def openImpl(source: Source): T
protected final def open(source: Source): T = protected final def open(source: Source): T =
translate("Error wrapping " + label(srcMf) + " in " + label(targetMf) + ": ") { openImpl(source) } translate("Error wrapping " + label(srcMf) + " in " + label(targetMf) + ": ") { openImpl(source) }
} }
trait OpenFile[T] extends OpenResource[File, T] trait OpenFile[T] extends Using[File, T]
{ {
protected def openImpl(file: File): T protected def openImpl(file: File): T
protected final def open(file: File): T = protected final def open(file: File): T =
{ {
val parent = file.getParentFile val parent = file.getParentFile
if(parent != null) if(parent != null)
FileUtilities.createDirectory(parent) IO.createDirectory(parent)
openImpl(file) openImpl(file)
} }
} }
object OpenResource object Using
{ {
def wrap[Source, T<: Closeable](openF: Source => T)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): OpenResource[Source,T] = def wrap[Source, T<: Closeable](openF: Source => T)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): Using[Source,T] =
wrap(openF, _.close) wrap(openF, closeCloseable)
def wrap[Source, T](openF: Source => T, closeF: T => Unit)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): OpenResource[Source,T] = def wrap[Source, T](openF: Source => T, closeF: T => Unit)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): Using[Source,T] =
new WrapOpenResource[Source, T] new WrapUsing[Source, T]
{ {
def openImpl(source: Source) = openF(source) def openImpl(source: Source) = openF(source)
def close(t: T) = closeF(t) def close(t: T) = closeF(t)
} }
def resource[Source, T <: Closeable](openF: Source => T): OpenResource[Source,T] = def resource[Source, T <: Closeable](openF: Source => T): Using[Source,T] =
resource(openF, _.close) resource(openF, closeCloseable)
def resource[Source, T](openF: Source => T, closeF: T => Unit): OpenResource[Source,T] = def resource[Source, T](openF: Source => T, closeF: T => Unit): Using[Source,T] =
new OpenResource[Source,T] new Using[Source,T]
{ {
def open(s: Source) = openF(s) def open(s: Source) = openF(s)
def close(s: T) = closeF(s) def close(s: T) = closeF(s)
} }
def file[T <: Closeable](openF: File => T): OpenFile[T] = file(openF, _.close()) def file[T <: Closeable](openF: File => T): OpenFile[T] = file(openF, closeCloseable)
def file[T](openF: File => T, closeF: T => Unit): OpenFile[T] = def file[T](openF: File => T, closeF: T => Unit): OpenFile[T] =
new OpenFile[T] new OpenFile[T]
{ {
def openImpl(file: File) = openF(file) def openImpl(file: File) = openF(file)
def close(t: T) = closeF(t) def close(t: T) = closeF(t)
} }
private def closeCloseable[T <: Closeable]: T => Unit = _.close()
def fileOutputStream(append: Boolean) = file(f => new FileOutputStream(f, append)) def fileOutputStream(append: Boolean = false) = file(f => new FileOutputStream(f, append))
def fileInputStream = file(f => new FileInputStream(f)) def fileInputStream = file(f => new FileInputStream(f))
def urlInputStream = resource( (u: URL) => translate("Error opening " + u + ": ")(u.openStream)) def urlInputStream = resource( (u: URL) => translate("Error opening " + u + ": ")(u.openStream))
def fileOutputChannel = file(f => new FileOutputStream(f).getChannel) def fileOutputChannel = file(f => new FileOutputStream(f).getChannel)
def fileInputChannel = file(f => new FileInputStream(f).getChannel) def fileInputChannel = file(f => new FileInputStream(f).getChannel)
def fileWriter(charset: Charset, append: Boolean) = def fileWriter(charset: Charset = IO.utf8, append: Boolean = false) =
file(f => new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, append), charset)) ) file(f => new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, append), charset)) )
def fileReader(charset: Charset) = file(f => new BufferedReader(new InputStreamReader(new FileInputStream(f), charset)) ) def fileReader(charset: Charset) = file(f => new BufferedReader(new InputStreamReader(new FileInputStream(f), charset)) )
def jarFile(verify: Boolean) = file(f => new JarFile(f, verify), (_: JarFile).close()) def jarFile(verify: Boolean) = file(f => new JarFile(f, verify), (_: JarFile).close())

View File

@ -1,37 +1,37 @@
/* sbt -- Simple Build Tool /* sbt -- Simple Build Tool
* Copyright 2008 Mark Harrah */ * Copyright 2008 Mark Harrah */
package xsbt package sbt
import org.scalacheck._ import org.scalacheck._
import Prop._ import Prop._
object NameFilterSpecification extends Properties("NameFilter") object NameFilterSpecification extends Properties("NameFilter")
{ {
specify("All pass accepts everything", (s: String) => AllPassFilter.accept(s)) property("All pass accepts everything") = forAll{ (s: String) => AllPassFilter.accept(s) }
specify("Exact filter matches provided string", property("Exact filter matches provided string") = forAll {
(s1: String, s2: String) => (new ExactFilter(s1)).accept(s2) == (s1 == s2) ) (s1: String, s2: String) => (new ExactFilter(s1)).accept(s2) == (s1 == s2) }
specify("Exact filter matches valid string", (s: String) => (new ExactFilter(s)).accept(s) ) property("Exact filter matches valid string") = forAll{ (s: String) => (new ExactFilter(s)).accept(s) }
specify("Glob filter matches provided string if no *s", property("Glob filter matches provided string if no *s") = forAll {
(s1: String, s2: String) => (s1: String, s2: String) =>
{ {
val stripped = stripAsterisksAndControl(s1) val stripped = stripAsterisksAndControl(s1)
(GlobFilter(stripped).accept(s2) == (stripped == s2)) (GlobFilter(stripped).accept(s2) == (stripped == s2))
}) } }
specify("Glob filter matches valid string if no *s", property("Glob filter matches valid string if no *s") = forAll {
(s: String) => (s: String) =>
{ {
val stripped = stripAsterisksAndControl(s) val stripped = stripAsterisksAndControl(s)
GlobFilter(stripped).accept(stripped) GlobFilter(stripped).accept(stripped)
}) }}
specify("Glob filter matches valid", property("Glob filter matches valid") = forAll {
(list: List[String]) => (list: List[String]) =>
{ {
val stripped = list.map(stripAsterisksAndControl) val stripped = list.map(stripAsterisksAndControl)
GlobFilter(stripped.mkString("*")).accept(stripped.mkString) GlobFilter(stripped.mkString("*")).accept(stripped.mkString)
}) }}
/** Raw control characters are stripped because they are not allowed in expressions. /** Raw control characters are stripped because they are not allowed in expressions.
* Asterisks are stripped because they are added under the control of the tests.*/ * Asterisks are stripped because they are added under the control of the tests.*/

View File

@ -1,7 +1,7 @@
package xsbt package sbt
import java.io.File import java.io.File
import FileUtilities.{withTemporaryDirectory, write} import IO.{withTemporaryDirectory, write}
object WithFiles object WithFiles
{ {