You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@clerezza.apache.org by re...@apache.org on 2011/01/26 00:19:37 UTC
svn commit: r1063515 [1/2] - in /incubator/clerezza/trunk:
org.apache.clerezza.parent/
org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/
org.apache.clerezza.parent/org.apache.clerezza.platform.launcher.storageless.p...
Author: reto
Date: Tue Jan 25 23:19:36 2011
New Revision: 1063515
URL: http://svn.apache.org/viewvc?rev=1063515&view=rev
Log:
CLEREZZA-410: added sourcebundle service that updates a bundle based on changes in source files
Added:
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/
- copied from r1059916, incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.json.simple/
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/
- copied from r1059916, incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.shell/
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/sourcebundle/
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/sourcebundle/BundleRoot.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/ErrorHandling.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Hash.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IO.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IPC.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/NameFilter.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Pack.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Path.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/PathMapper.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Resources.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/SourceModificationWatch.scala
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Using.scala
Removed:
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/shell/
Modified:
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/pom.xml
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.launcher.storageless.parent/pom.xml
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/NOTICE.txt
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/pom.xml
incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/resources/OSGI-INF/serviceComponents.xml
incubator/clerezza/trunk/org.apache.clerezza.parent/pom.xml
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/CompilerService.scala
incubator/clerezza/trunk/scala-scripting/script-engine/src/main/scala/org/apache/clerezza/scala/scripting/TrackingCompiler.scala
Modified: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/pom.xml
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/pom.xml?rev=1063515&r1=1059916&r2=1063515&view=diff
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/pom.xml (original)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.ext.org.ops4j.pax.swissbox.tinybundles/pom.xml Tue Jan 25 23:19:36 2011
@@ -1,20 +1,27 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <artifactId>org.apache.clerezza.parent</artifactId>
- <groupId>org.apache.clerezza</groupId>
- <version>0.2-incubating-SNAPSHOT</version>
- </parent>
- <groupId>org.apache.clerezza.ext</groupId>
- <artifactId>org.json.simple</artifactId>
- <name>Clerezza Ext - Json.simple OSGi Bundle</name>
- <version>0.3-incubating-SNAPSHOT</version>
- <packaging>bundle</packaging>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>org.apache.clerezza.parent</artifactId>
+ <groupId>org.apache.clerezza</groupId>
+ <version>0.2-incubating-SNAPSHOT</version>
+ </parent>
+ <groupId>org.apache.clerezza.ext</groupId>
+ <artifactId>org.ops4j.pax.swissbox.tinybundles</artifactId>
+ <name>Clerezza Ext - SwissBox TinyBundles OSGi Bundle</name>
+ <version>0.1-incubating-SNAPSHOT</version>
+ <packaging>bundle</packaging>
<description>json.simple parses and serializes json</description>
- <dependencies>
+ <dependencies>
<dependency>
- <groupId>com.googlecode.json-simple</groupId>
- <artifactId>json-simple</artifactId>
+ <groupId>org.ops4j.pax.swissbox</groupId>
+ <artifactId>pax-swissbox-tinybundles</artifactId>
+ <exclusions>
+ <exclusion>
+ <artifactId>org.slf4j</artifactId>
+ <groupId>slf4j-api</groupId>
+ </exclusion>
+ </exclusions>
</dependency>
</dependencies>
<build>
@@ -25,7 +32,10 @@
<extensions>true</extensions>
<configuration>
<instructions>
- <Export-Package>org.json.simple.*</Export-Package>
+ <Embed-Transitive>true</Embed-Transitive>
+ <Export-Package>org.ops4j.pax.swissbox.tinybundles.core;version="1.3.0"</Export-Package>
+ <!-- <Private-Package>*</Private-Package> -->
+ <Embed-Dependency>*;artifactId=!slf4j-api;scope=compile;inline=true</Embed-Dependency>
</instructions>
</configuration>
</plugin>
Modified: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.launcher.storageless.parent/pom.xml
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.launcher.storageless.parent/pom.xml?rev=1063515&r1=1063514&r2=1063515&view=diff
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.launcher.storageless.parent/pom.xml (original)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.platform.launcher.storageless.parent/pom.xml Tue Jan 25 23:19:36 2011
@@ -66,6 +66,11 @@
</dependency>
<dependency>
<groupId>org.apache.clerezza.ext</groupId>
+ <artifactId>org.ops4j.pax.swissbox.tinybundles</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza.ext</groupId>
<artifactId>javax.mail</artifactId>
<scope>runtime</scope>
</dependency>
@@ -314,6 +319,11 @@
</dependency>
<dependency>
<groupId>org.apache.clerezza</groupId>
+ <artifactId>org.apache.clerezza.sourcebundle</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.clerezza</groupId>
<artifactId>org.apache.clerezza.sshshell</artifactId>
<scope>runtime</scope>
</dependency>
Modified: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/NOTICE.txt
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/NOTICE.txt?rev=1063515&r1=1059916&r2=1063515&view=diff
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/NOTICE.txt (original)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/NOTICE.txt Tue Jan 25 23:19:36 2011
@@ -1 +1 @@
-
+Uses code from: http://code.google.com/p/simple-build-tool/
\ No newline at end of file
Modified: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/pom.xml
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/pom.xml?rev=1063515&r1=1059916&r2=1063515&view=diff
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/pom.xml (original)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/pom.xml Tue Jan 25 23:19:36 2011
@@ -5,10 +5,10 @@
<artifactId>org.apache.clerezza.parent</artifactId>
<version>0.2-incubating-SNAPSHOT</version>
</parent>
- <artifactId>org.apache.clerezza.shell</artifactId>
+ <artifactId>org.apache.clerezza.sourcebundle</artifactId>
<version>0.1-incubating-SNAPSHOT</version>
<packaging>bundle</packaging>
- <name>Clerezza - Shell Service</name>
+ <name>Clerezza - Source-Bundle Service</name>
<dependencies>
<dependency>
<groupId>org.apache.clerezza.scala</groupId>
@@ -39,6 +39,11 @@
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.swissbox</groupId>
+ <artifactId>pax-swissbox-tinybundles</artifactId>
+ <version>1.3.0</version>
+ </dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
@@ -50,8 +55,9 @@
<configuration>
<instructions>
<Service-Component>OSGI-INF/serviceComponents.xml</Service-Component>
- <Export-Package>org.apache.clerezza.shell</Export-Package>
- <Bundle-SymbolicName>org.apache.clerezza.shell</Bundle-SymbolicName>
+ <Export-Package>org.apache.clerezza.sourcebundle</Export-Package>
+ <Private-Package>sbt,sbt.*</Private-Package>
+ <Bundle-SymbolicName>org.apache.clerezza.sourcebundle</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
Modified: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/resources/OSGI-INF/serviceComponents.xml
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/resources/OSGI-INF/serviceComponents.xml?rev=1063515&r1=1059916&r2=1063515&view=diff
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/resources/OSGI-INF/serviceComponents.xml (original)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/resources/OSGI-INF/serviceComponents.xml Tue Jan 25 23:19:36 2011
@@ -1,26 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
- <scr:component enabled="true" immediate="true" name="org.apache.clerezza.shell.ConsoleShell">
- <implementation class="org.apache.clerezza.shell.ConsoleShell"/>
- <property name="service.pid" value="org.apache.clerezza.shell.ConsoleShell"/>
- <reference name="shellFactory"
- interface="org.apache.clerezza.shell.ShellFactory"
- cardinality="1..1"
- bind="bindShellFactory" unbind="unbindShellFactory"/>
- </scr:component>
- <scr:component enabled="true" immediate="true" name="org.apache.clerezza.shell.ShellFactory">
- <implementation class="org.apache.clerezza.shell.ShellFactory"/>
+ <scr:component enabled="true" immediate="true" name="org.apache.clerezza.sourcebundle.BundleRoot">
+ <implementation class="org.apache.clerezza.sourcebundle.BundleRoot"/>
+ <property name="service.pid" value="org.apache.clerezza.sourcebundle.BundleRoot"/>
<service servicefactory="false">
- <provide interface="org.apache.clerezza.shell.ShellFactory"/>
+ <provide interface="org.apache.clerezza.sourcebundle.BundleRoot"/>
</service>
- <property name="service.pid" value="org.apache.clerezza.shell.ShellFactory"/>
- <reference name="interpreterFactory"
- interface="org.apache.clerezza.scala.scripting.InterpreterFactory"
+ <reference name="CompilerService"
+ interface="org.apache.clerezza.scala.scripting.CompilerService"
+ cardinality="1..1"
+ bind="bindCompilerService" unbind="unbindCompilerService"/>
+ <reference name="PackageAdmin"
+ interface="org.osgi.service.packageadmin.PackageAdmin"
cardinality="1..1"
- bind="bindInterpreterFactory" unbind="unbindInterpreterFactory"/>
- <reference name="commands"
- interface="org.apache.clerezza.shell.ShellCommand"
- cardinality="0..n"
- bind="bindCommand" unbind="unbindCommand"/>
+ bind="bindPackageAdmin" unbind="unbindPackageAdmin"/>
</scr:component>
</components>
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/sourcebundle/BundleRoot.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/sourcebundle/BundleRoot.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/sourcebundle/BundleRoot.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/org/apache/clerezza/sourcebundle/BundleRoot.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2011 reto.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * under the License.
+ */
+
+package org.apache.clerezza.sourcebundle
+
+import java.io._
+import scala.actors.DaemonActor
+import scala.io._
+import org.osgi.framework.Bundle
+import org.osgi.framework.BundleContext
+import sbt._
+import scala.actors.Actor
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles._
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundle
+import org.apache.clerezza.scala.scripting.CompilerService
+import org.osgi.framework.Constants
+import org.osgi.service.component.ComponentContext
+import org.slf4j.LoggerFactory
+import scala.tools.nsc.io.AbstractFile
+import scala.tools.nsc.io.VirtualDirectory
+import scala.collection.mutable
+import org.osgi.service.packageadmin.PackageAdmin
+
+class BundleRoot {
+
+ var compilerService: CompilerService = null
+ var packageAdmin: PackageAdmin = null
+
+ var bundleContext: BundleContext = null
+
+ val sourceBundles = mutable.ListBuffer[SourceBundle]()
+
+ protected def activate(c: ComponentContext) {
+ this.bundleContext = c.getBundleContext
+ sourceBundles.clear()
+ for (bundle <- bundleContext.getBundles) {
+ val location = bundle.getLocation
+ if (location.startsWith(BundleRoot.sourceBundleUriPrefix)) {
+ val dir = new File(location.substring(
+ BundleRoot.sourceBundleUriPrefix.length))
+ val sourceBundle = new SourceBundle(dir, bundle)
+ sourceBundle.start()
+ sourceBundles += sourceBundle
+ }
+ }
+ }
+
+ protected def deactivate(c: ComponentContext) {
+ for (sb <- sourceBundles) sb.stop()
+ }
+
+ def createSourceBundle(dir: File) = {
+ val sourceBundle = new SourceBundle(dir)
+ sourceBundle.start()
+ sourceBundles += sourceBundle
+ sourceBundle
+ }
+
+ def bindCompilerService(cs: CompilerService) {
+ compilerService = cs;
+ }
+
+ def unbindCompilerService(cs: CompilerService) {
+ compilerService = null;
+ }
+
+ def bindPackageAdmin(pa: PackageAdmin) {
+ packageAdmin = pa
+ }
+
+ def unbindPackageAdmin(pa: PackageAdmin) {
+ packageAdmin = null
+ }
+
+ class SourceBundle(dir: File, existingBundle: Bundle) extends DaemonActor {
+
+ def this(dir: File) {
+ this(dir, null)
+ }
+
+ var stopped = false
+ var logger = LoggerFactory.getLogger(classOf[SourceBundle])
+
+ val sourcePath = Path.fromFile(dir)
+ var watchState = WatchState.empty
+ var bundle: Bundle = existingBundle
+
+ def getFilesAsCharArrays(file: File): List[Array[Char]] = {
+ logger.debug("getting sources in "+file)
+ var result: List[Array[Char]] = Nil
+ if (file.isDirectory) {
+ val children = file.listFiles
+ import scala.collection.JavaConversions._
+ for(child <- children) {
+ if (!child.getName.startsWith(".")) {
+ result = getFilesAsCharArrays(child) ::: result
+ }
+ }
+ } else {
+ if (file.getName.endsWith(".scala")) {
+ val in = Source.fromFile(file, "utf-8")
+ val stream = in.toStream
+ result = stream.toArray :: result
+ }
+ }
+ result
+ }
+
+ private[this] def updateBundle() {
+ logger.info("updating source bundle with root "+dir)
+
+ val tinyBundle: TinyBundle = newBundle()
+
+ def compileDir(sourceDir: File) {
+
+ val charArrays = getFilesAsCharArrays(sourceDir)
+ logger.debug("compiling "+charArrays.size+" files")
+
+ val vdPathPrefix = "(memory)"
+ val virtualDirectory = new VirtualDirectory(vdPathPrefix, None)
+ //val wrappedDirectory = VirtualDirectoryWrapper.wrap(virtualDirectory, outputListener)
+
+ val writtenClasses = compilerService.compileToDir(charArrays, virtualDirectory)
+ logger.debug("virtualDirectory "+virtualDirectory.size)
+ for (writtenClass <- writtenClasses) {
+ val fullPath = writtenClass.path
+ val path = fullPath.substring(vdPathPrefix.length+1)
+ tinyBundle.add(path, new ByteArrayInputStream(writtenClass.toByteArray))
+ }
+ }
+
+ def copyResource(resourcesDir: File) {
+ def copyResource(resourcesDir: File, prefix: String) {
+ val children = resourcesDir.listFiles
+ import scala.collection.JavaConversions._
+ for(child <- children) {
+ val childName = child.getName
+ if (!childName.startsWith(".")) {
+ if (child.isDirectory) {
+ copyResource(child, prefix+childName+"/")
+ } else {
+ tinyBundle.add(prefix+childName, new FileInputStream(child))
+ }
+ }
+ }
+ }
+ copyResource(resourcesDir, "")
+ }
+
+ val symName = dir.getPath.substring(1).replace(File.separatorChar, '.')
+
+ tinyBundle.set("Bundle-SymbolicName", symName)
+
+ val scalaSourceDir = new File(dir, "src/main/scala")
+ if (scalaSourceDir.exists) {
+ compileDir(scalaSourceDir)
+ } else {
+ logger.debug("No source dir "+scalaSourceDir)
+ }
+ val resourcesDir = new File(dir, "src/main/resources")
+ if (resourcesDir.exists) {
+ copyResource(resourcesDir)
+ } else {
+ logger.debug("No resources dir "+resourcesDir)
+ }
+ val serviceComponentsFile = new File(resourcesDir, "OSGI-INF/serviceComponents.xml")
+ if (serviceComponentsFile.exists) {
+ tinyBundle.set("Service-Component", "OSGI-INF/serviceComponents.xml")
+ tinyBundle.set(Constants.EXPORT_PACKAGE, "!OSGI-INF, *" )
+ }
+ tinyBundle.set(Constants.IMPORT_PACKAGE, "*" );
+ val in = tinyBundle.build(
+ withBnd()
+ )
+
+
+ if (bundle == null) {
+ bundle = bundleContext.installBundle(BundleRoot.sourceBundleUriPrefix+dir.toString, in)
+ bundle.start()
+ } else {
+ bundle.update(in)
+ }
+
+ }
+
+ def act() {
+ while (!stopped) {
+ val (triggered, newWatchState) =
+ SourceModificationWatch.watch(sourcePath**(-HiddenFileFilter), 1, watchState)(stopped)
+ if (!stopped) {
+ updateBundle()
+ watchState = newWatchState
+ }
+ }
+ }
+
+ def stop() {
+ stopped = true
+ }
+ }
+}
+
+
+object BundleRoot {
+
+ val sourceBundleUriPrefix = "sourcebundle:"
+
+}
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/ErrorHandling.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/ErrorHandling.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/ErrorHandling.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/ErrorHandling.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,28 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
+
+object ErrorHandling
+{
+ def translate[T](msg: => String)(f: => T) =
+ try { f }
+ catch { case e: Exception => throw new TranslatedException(msg + e.toString, e) }
+
+ def wideConvert[T](f: => T): Either[Throwable, T] =
+ try { Right(f) }
+ catch
+ {
+ case ex @ (_: Exception | _: StackOverflowError) => Left(ex)
+ case err @ (_: ThreadDeath | _: VirtualMachineError) => throw err
+ case x => Left(x)
+ }
+
+ def convert[T](f: => T): Either[Exception, T] =
+ try { Right(f) }
+ catch { case e: Exception => Left(e) }
+}
+final class TranslatedException private[sbt](msg: String, cause: Throwable) extends RuntimeException(msg, cause)
+{
+ override def toString = msg
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Hash.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Hash.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Hash.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Hash.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,76 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
+
+import java.io.{ByteArrayInputStream, File, InputStream}
+
+object Hash
+{
+ private val BufferSize = 8192
+ def toHex(bytes: Array[Byte]): String =
+ {
+ val buffer = new StringBuilder(bytes.length * 2)
+ for(i <- 0 until bytes.length)
+ {
+ val b = bytes(i)
+ val bi: Int = if(b < 0) b + 256 else b
+ buffer append toHex((bi >>> 4).asInstanceOf[Byte])
+ buffer append toHex((bi & 0x0F).asInstanceOf[Byte])
+ }
+ buffer.toString
+ }
+ def fromHex(hex: String): Array[Byte] =
+ {
+ require((hex.length & 1) == 0, "Hex string must have length 2n.")
+ val array = new Array[Byte](hex.length >> 1)
+ for(i <- 0 until hex.length by 2)
+ {
+ val c1 = hex.charAt(i)
+ val c2 = hex.charAt(i+1)
+ array(i >> 1) = ((fromHex(c1) << 4) | fromHex(c2)).asInstanceOf[Byte]
+ }
+ array
+ }
+ /** Calculates the SHA-1 hash of the given String.*/
+ def apply(s: String): Array[Byte] = apply(new ByteArrayInputStream(s.getBytes("UTF-8")))
+ /** Calculates the SHA-1 hash of the given file.*/
+ def apply(file: File): Array[Byte] = Using.fileInputStream(file)(apply)
+ /** Calculates the SHA-1 hash of the given stream, closing it when finished.*/
+ def apply(stream: InputStream): Array[Byte] =
+ {
+ import java.security.{MessageDigest, DigestInputStream}
+ val digest = MessageDigest.getInstance("SHA")
+ try
+ {
+ val dis = new DigestInputStream(stream, digest)
+ val buffer = new Array[Byte](BufferSize)
+ while(dis.read(buffer) >= 0) {}
+ dis.close()
+ digest.digest
+ }
+ finally { stream.close() }
+ }
+
+ private def toHex(b: Byte): Char =
+ {
+ require(b >= 0 && b <= 15, "Byte " + b + " was not between 0 and 15")
+ if(b < 10)
+ ('0'.asInstanceOf[Int] + b).asInstanceOf[Char]
+ else
+ ('a'.asInstanceOf[Int] + (b-10)).asInstanceOf[Char]
+ }
+ private def fromHex(c: Char): Int =
+ {
+ val b =
+ if(c >= '0' && c <= '9')
+ (c - '0')
+ else if(c >= 'a' && c <= 'f')
+ (c - 'a') + 10
+ else if(c >= 'A' && c <= 'F')
+ (c - 'A') + 10
+ else
+ throw new RuntimeException("Invalid hex character: '" + c + "'.")
+ b
+ }
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IO.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IO.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IO.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IO.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,591 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009, 2010 Mark Harrah, Viktor Klang, Ross McDonald
+ */
+package sbt
+
+import Using._
+import ErrorHandling.translate
+
+import java.io.{BufferedReader, ByteArrayOutputStream, BufferedWriter, File, FileInputStream, InputStream, OutputStream}
+import java.net.{URI, URISyntaxException, URL}
+import java.nio.charset.Charset
+import java.util.Properties
+import java.util.jar.{Attributes, JarEntry, JarFile, JarInputStream, JarOutputStream, Manifest}
+import java.util.zip.{CRC32, GZIPOutputStream, ZipEntry, ZipFile, ZipInputStream, ZipOutputStream}
+import scala.collection.immutable.TreeSet
+import scala.collection.mutable.{HashMap,HashSet}
+import scala.reflect.{Manifest => SManifest}
+import Function.tupled
+
+object IO
+{
+ /** The maximum number of times a unique temporary filename is attempted to be created.*/
+ private val MaximumTries = 10
+ /** The producer of randomness for unique name generation.*/
+ private lazy val random = new java.util.Random
+ 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
+ val Newline = System.getProperty("line.separator")
+
+ val utf8 = Charset.forName("UTF-8")
+
+ def classLocation(cl: Class[_]): URL =
+ {
+ val codeSource = cl.getProtectionDomain.getCodeSource
+ if(codeSource == null) error("No class location for " + cl)
+ else codeSource.getLocation
+ }
+ def classLocationFile(cl: Class[_]): File = toFile(classLocation(cl))
+ def classLocation[T](implicit mf: SManifest[T]): URL = classLocation(mf.erasure)
+ def classLocationFile[T](implicit mf: SManifest[T]): File = classLocationFile(mf.erasure)
+
+ def toFile(url: URL) =
+ try { new File(url.toURI) }
+ catch { case _: URISyntaxException => new File(url.getPath) }
+
+ /** Converts the given URL to a File. If the URL is for an entry in a jar, the File for the jar is returned. */
+ def asFile(url: URL): File =
+ {
+ url.getProtocol match
+ {
+ case "file" => toFile(url)
+ case "jar" =>
+ val path = url.getPath
+ val end = path.indexOf('!')
+ new File(new URI(if(end == -1) path else path.substring(0, end)))
+ case _ => error("Invalid protocol " + url.getProtocol)
+ }
+ }
+ def assertDirectory(file: File) { assert(file.isDirectory, (if(file.exists) "Not a directory: " else "Directory not found: ") + file) }
+ def assertDirectories(file: File*) { file.foreach(assertDirectory) }
+
+ // "base.extension" -> (base, extension)
+ def split(name: String): (String, String) =
+ {
+ val lastDot = name.lastIndexOf('.')
+ if(lastDot >= 0)
+ (name.substring(0, lastDot), name.substring(lastDot+1))
+ else
+ (name, "")
+ }
+
+ def touch(files: Traversable[File]): Unit = files.foreach(touch)
+ /** Creates a file at the given location.*/
+ def touch(file: File)
+ {
+ createDirectory(file.getParentFile)
+ val created = translate("Could not create file " + file) { file.createNewFile() }
+ if(created || file.isDirectory)
+ ()
+ else if(!file.setLastModified(System.currentTimeMillis))
+ error("Could not update last modified time for file " + file)
+ }
+ def createDirectories(dirs: Traversable[File]): Unit =
+ dirs.foreach(createDirectory)
+ def createDirectory(dir: File): Unit =
+ {
+ def failBase = "Could not create directory " + dir
+ if(dir.isDirectory || dir.mkdirs())
+ ()
+ else if(dir.exists)
+ error(failBase + ": file exists and is not a directory.")
+ else
+ error(failBase)
+ }
+
+ /** 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) }
+ }
+ private def extract(from: ZipInputStream, toDirectory: File, filter: NameFilter) =
+ {
+ val set = new HashSet[File]
+ def next()
+ {
+ val entry = from.getNextEntry
+ if(entry == null)
+ ()
+ else
+ {
+ val name = entry.getName
+ if(filter.accept(name))
+ {
+ val target = new File(toDirectory, name)
+ //log.debug("Extracting zip entry '" + name + "' to '" + target + "'")
+ if(entry.isDirectory)
+ createDirectory(target)
+ else
+ {
+ set += target
+ translate("Error extracting zip entry '" + name + "' to '" + target + "': ") {
+ fileOutputStream(false)(target) { out => transfer(from, out) }
+ }
+ }
+ //target.setLastModified(entry.getTime)
+ }
+ else
+ {
+ //log.debug("Ignoring zip entry '" + name + "'")
+ }
+ from.closeEntry()
+ next()
+ }
+ }
+ next()
+ 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 =>
+ transfer(inputStream, to)
+ }
+
+ def transfer(in: File, out: File): Unit =
+ fileInputStream(in){ in => transfer(in, out) }
+
+ def transfer(in: File, out: OutputStream): Unit =
+ fileInputStream(in){ in => transfer(in, out) }
+
+ /** Copies all bytes from the given input stream to the given File.*/
+ def transfer(in: InputStream, to: File): Unit =
+ Using.fileOutputStream()(to) { outputStream =>
+ transfer(in, 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)
+ /** Copies all bytes from the given input stream to the given output stream. The
+ * input stream is closed after the method completes.*/
+ def transferAndClose(in: InputStream, out: OutputStream): Unit = transferImpl(in, out, true)
+ private def transferImpl(in: InputStream, out: OutputStream, close: Boolean)
+ {
+ try
+ {
+ val buffer = new Array[Byte](BufferSize)
+ def read()
+ {
+ val byteCount = in.read(buffer)
+ if(byteCount >= 0)
+ {
+ out.write(buffer, 0, byteCount)
+ read()
+ }
+ }
+ read()
+ }
+ finally { if(close) in.close }
+ }
+
+ /** Creates a temporary directory and provides its location to the given function. The directory
+ * is deleted after the function returns.*/
+ def withTemporaryDirectory[T](action: File => T): T =
+ {
+ val dir = createTemporaryDirectory
+ try { action(dir) }
+ finally { delete(dir) }
+ }
+ def createTemporaryDirectory: File =
+ {
+ def create(tries: Int): File =
+ {
+ if(tries > MaximumTries)
+ error("Could not create temporary directory.")
+ else
+ {
+ val randomName = "sbt_" + java.lang.Integer.toHexString(random.nextInt)
+ val f = new File(temporaryDirectory, randomName)
+
+ try { createDirectory(f); f }
+ catch { case e: Exception => create(tries + 1) }
+ }
+ }
+ 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"))
+
+ def deleteIfEmpty(dirs: collection.Set[File]): Unit =
+ {
+ val isEmpty = new HashMap[File, Boolean]
+ def visit(f: File): Boolean = isEmpty.getOrElseUpdate(f, dirs(f) && f.isDirectory && (f.listFiles forall visit) )
+
+ dirs foreach visit
+ for( (f, true) <- isEmpty) f.delete
+ }
+
+ def delete(files: Iterable[File]): Unit = files.foreach(delete)
+ def delete(file: File)
+ {
+ translate("Error deleting file " + file + ": ")
+ {
+ if(file.isDirectory)
+ {
+ delete(listFiles(file))
+ file.delete
+ }
+ else if(file.exists)
+ file.delete
+ }
+ }
+ 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[sbt] def wrapNull(a: Array[File]) =
+ {
+ if(a == null)
+ new Array[File](0)
+ else
+ a
+ }
+
+
+ /** Creates a jar file.
+ * @param sources The files to include in the jar file paired with the entry name in the jar.
+ * @param outputJar The file to write the jar to.
+ * @param manifest The manifest for the jar.*/
+ def jar(sources: Traversable[(File,String)], outputJar: File, manifest: Manifest): Unit =
+ 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: Traversable[(File,String)], outputZip: File): Unit =
+ archive(sources.toSeq, outputZip, None)
+
+ private def archive(sources: Seq[(File,String)], outputFile: File, manifest: Option[Manifest])
+ {
+ if(outputFile.isDirectory)
+ error("Specified output file " + outputFile + " is a directory.")
+ else
+ {
+ val outputDir = outputFile.getParentFile
+ createDirectory(outputDir)
+ withZipOutput(outputFile, manifest)
+ { output =>
+ val createEntry: (String => ZipEntry) = if(manifest.isDefined) new JarEntry(_) else new ZipEntry(_)
+ writeZip(sources, output)(createEntry)
+ }
+ }
+ }
+ private def writeZip(sources: Seq[(File,String)], output: ZipOutputStream)(createEntry: String => ZipEntry)
+ {
+ import Path.{lazyPathFinder => pf}
+ val files = sources.collect { case (file,name) if file.isFile => (file, normalizeName(name)) }
+ val now = System.currentTimeMillis
+ // The CRC32 for an empty value, needed to store directories in zip files
+ val emptyCRC = new CRC32().getValue()
+
+ def addDirectoryEntry(name: String)
+ {
+ output putNextEntry makeDirectoryEntry(name)
+ output.closeEntry()
+ }
+
+ def makeDirectoryEntry(name: String) =
+ {
+// log.debug("\tAdding directory " + relativePath + " ...")
+ val e = createEntry(name)
+ e setTime now
+ e setSize 0
+ e setMethod ZipEntry.STORED
+ e setCrc emptyCRC
+ e
+ }
+
+ def makeFileEntry(file: File, name: String) =
+ {
+// log.debug("\tAdding " + file + " as " + name + " ...")
+ val e = createEntry(name)
+ e setTime file.lastModified
+ e
+ }
+ def addFileEntry(file: File, name: String)
+ {
+ output putNextEntry makeFileEntry(file, name)
+ transfer(file, output)
+ output.closeEntry()
+ }
+
+ //Calculate directories and add them to the generated Zip
+ allDirectoryPaths(files) foreach addDirectoryEntry
+
+ //Add all files to the generated Zip
+ files foreach { case (file, name) => addFileEntry(file, name) }
+ }
+
+ // map a path a/b/c to List("a", "b")
+ private def relativeComponents(path: String): List[String] =
+ path.split("/").toList.dropRight(1)
+
+ // map components List("a", "b", "c") to List("a/b/c/", "a/b/", "a/", "")
+ private def directories(path: List[String]): List[String] =
+ path.foldLeft(List(""))( (e,l) => (e.head + l + "/") :: e )
+
+ // map a path a/b/c to List("a/b/", "a/")
+ private def directoryPaths(path: String): List[String] =
+ directories(relativeComponents(path)).filter(_.length > 1)
+
+ // produce a sorted list of all the subdirectories of all provided files
+ private def allDirectoryPaths(files: Iterable[(File,String)]) =
+ TreeSet[String]() ++ (files flatMap { case (file, name) => directoryPaths(name) })
+
+ private def normalizeDirName(name: String) =
+ {
+ val norm1 = normalizeName(name)
+ if(norm1.endsWith("/")) norm1 else (norm1 + "/")
+ }
+ private def normalizeName(name: String) =
+ {
+ val sep = File.separatorChar
+ if(sep == '/') name else name.replace(sep, '/')
+ }
+
+ private def withZipOutput(file: File, manifest: Option[Manifest])(f: ZipOutputStream => Unit)
+ {
+ fileOutputStream(false)(file) { fileOut =>
+ val (zipOut, ext) =
+ manifest match
+ {
+ case Some(mf) =>
+ {
+ import Attributes.Name.MANIFEST_VERSION
+ val main = mf.getMainAttributes
+ if(!main.containsKey(MANIFEST_VERSION))
+ main.put(MANIFEST_VERSION, "1.0")
+ (new JarOutputStream(fileOut, mf), "jar")
+ }
+ case None => (new ZipOutputStream(fileOut), "zip")
+ }
+ try { f(zipOut) }
+ catch { case e: Exception => "Error writing " + ext + ": " + e.toString }
+ finally { zipOut.close }
+ }
+ }
+ def relativize(base: File, file: File): Option[String] =
+ {
+ val pathString = file.getAbsolutePath
+ baseFileString(base) flatMap
+ {
+ baseString =>
+ {
+ if(pathString.startsWith(baseString))
+ Some(pathString.substring(baseString.length))
+ else
+ None
+ }
+ }
+ }
+ private def baseFileString(baseFile: File): Option[String] =
+ {
+ if(baseFile.isDirectory)
+ {
+ val cp = baseFile.getAbsolutePath
+ assert(cp.length > 0)
+ val normalized = if(cp.charAt(cp.length - 1) == File.separatorChar) cp else cp + File.separatorChar
+ Some(normalized)
+ }
+ else
+ None
+ }
+ def copy(sources: Traversable[(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(overwrite || !to.exists || from.lastModified > to.lastModified)
+ {
+ if(from.isDirectory)
+ createDirectory(to)
+ else
+ {
+ createDirectory(to.getParentFile)
+ copyFile(from, to, preserveLastModified)
+ }
+ }
+ to
+ }
+ 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.")
+ fileInputChannel(sourceFile) { in =>
+ fileOutputChannel(targetFile) { out =>
+ val copied = out.transferFrom(in, 0, in.size)
+ if(copied != in.size)
+ 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 =
+ writer(file, content, charset, append) { _.write(content) }
+
+ def writer[T](file: File, content: String, charset: Charset, append: Boolean = false)(f: BufferedWriter => T): T =
+ {
+ if(charset.newEncoder.canEncode(content))
+ fileWriter(charset, append)(file) { f }
+ else
+ error("String cannot be encoded by charset " + charset.name)
+ }
+
+ def reader[T](file: File, charset: Charset = defaultCharset)(f: BufferedReader => T): T =
+ fileReader(charset)(file) { f }
+
+ def read(file: File, charset: Charset = defaultCharset): String =
+ {
+ val out = new ByteArrayOutputStream(file.length.toInt)
+ transfer(file, out)
+ out.toString(charset.name)
+ }
+ /** doesn't close the InputStream */
+ def readStream(in: InputStream, charset: Charset = defaultCharset): String =
+ {
+ val out = new ByteArrayOutputStream
+ transfer(in, out)
+ out.toString(charset.name)
+ }
+ def readBytes(file: File): Array[Byte] = fileInputStream(file)(readBytes)
+ /** doesn't close the InputStream */
+ def readBytes(in: InputStream): Array[Byte] =
+ {
+ val out = new ByteArrayOutputStream
+ transfer(in, out)
+ out.toByteArray
+ }
+
+ def append(file: File, content: String, charset: Charset = defaultCharset): Unit =
+ write(file, content, charset, true)
+ def append(file: File, bytes: Array[Byte]): Unit =
+ writeBytes(file, bytes, true)
+
+ def write(file: File, bytes: Array[Byte]): Unit =
+ writeBytes(file, bytes, false)
+ private def writeBytes(file: File, bytes: Array[Byte], append: Boolean): Unit =
+ fileOutputStream(append)(file) { _.write(bytes) }
+
+
+ // Not optimized for large files
+ def readLines(file: File, charset: Charset = defaultCharset): List[String] =
+ fileReader(charset)(file)(readLines)
+
+ // Not optimized for large files
+ def readLines(in: BufferedReader): List[String] =
+ foldLines[List[String]](in, Nil)( (accum, line) => line :: accum ).reverse
+
+ def foreachLine(in: BufferedReader)(f: String => Unit): Unit =
+ foldLines(in, ())( (_, line) => f(line) )
+
+ def foldLines[T](in: BufferedReader, init: T)(f: (T, String) => T): T =
+ {
+ def readLine(accum: T): T =
+ {
+ val line = in.readLine()
+ if(line eq null) accum else readLine(f(accum, line))
+ }
+ readLine(init)
+ }
+
+ def writeLines(file: File, lines: Seq[String], charset: Charset = defaultCharset, append: Boolean = false): Unit =
+ writer(file, lines.headOption.getOrElse(""), charset, append) { w =>
+ lines.foreach { line => w.write(line); w.newLine() }
+ }
+
+ def write(properties: Properties, label: String, to: File) =
+ fileOutputStream()(to) { output => properties.store(output, label) }
+ def load(properties: Properties, from: File): Unit =
+ if(from.exists)
+ fileInputStream(from){ input => properties.load(input) }
+
+ /** A pattern used to split a String by path separator characters.*/
+ private val PathSeparatorPattern = java.util.regex.Pattern.compile(File.pathSeparator)
+
+ /** Splits a String around path separator characters. */
+ def pathSplit(s: String) = PathSeparatorPattern.split(s)
+
+ /** Move the provided files to a temporary location.
+ * If 'f' returns normally, delete the files.
+ * If 'f' throws an Exception, return the files to their original location.*/
+ def stash[T](files: Set[File])(f: => T): T =
+ withTemporaryDirectory { dir =>
+ val stashed = stashLocations(dir, files.toArray)
+ move(stashed)
+
+ try { f } catch { case e: Exception =>
+ try { move(stashed.map(_.swap)); throw e }
+ catch { case _: Exception => throw e }
+ }
+ }
+
+ private def stashLocations(dir: File, files: Array[File]) =
+ for( (file, index) <- files.zipWithIndex) yield
+ (file, new File(dir, index.toHexString))
+
+ def move(files: Traversable[(File, File)]): Unit =
+ files.foreach(Function.tupled(move))
+
+ def move(a: File, b: File): Unit =
+ {
+ if(b.exists)
+ delete(b)
+ if(!a.renameTo(b))
+ {
+ copyFile(a, b, true)
+ delete(a)
+ }
+ }
+
+ def gzipFileOut[T](file: File)(f: OutputStream => T): T =
+ Using.fileOutputStream()(file) { fout =>
+ Using.gzipOutputStream(fout) { outg =>
+ Using.bufferedOutputStream(outg)(f) }}
+
+ def gzipFileIn[T](file: File)(f: InputStream => T): T =
+ Using.fileInputStream(file) { fin =>
+ Using.gzipInputStream(fin) { ing =>
+ Using.bufferedInputStream(ing)(f) }}
+}
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IPC.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IPC.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IPC.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/IPC.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,72 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package xsbt
+
+import java.io.{BufferedReader, BufferedWriter, InputStream, InputStreamReader, OutputStreamWriter, OutputStream}
+import java.net.{InetAddress, ServerSocket, Socket}
+
+object IPC
+{
+ private val portMin = 1025
+ private val portMax = 65536
+ private val loopback = InetAddress.getByName(null) // loopback
+
+ def client[T](port: Int)(f: IPC => T): T =
+ ipc(new Socket(loopback, port))(f)
+
+ def pullServer[T](f: Server => T): T =
+ {
+ val server = makeServer
+ try { f(new Server(server)) }
+ finally { server.close() }
+ }
+ def makeServer: ServerSocket =
+ {
+ val random = new java.util.Random
+ def nextPort = random.nextInt(portMax - portMin + 1) + portMin
+ def createServer(attempts: Int): ServerSocket =
+ if(attempts > 0)
+ try { new ServerSocket(nextPort, 1, loopback) }
+ catch { case _: Exception => createServer(attempts - 1) }
+ else
+ error("Could not connect to socket: maximum attempts exceeded")
+ createServer(10)
+ }
+ def server[T](f: IPC => Option[T]): T = serverImpl(makeServer, f)
+ def server[T](port: Int)(f: IPC => Option[T]): T =
+ serverImpl(new ServerSocket(port, 1, loopback), f)
+ private def serverImpl[T](server: ServerSocket, f: IPC => Option[T]): T =
+ {
+ def listen(): T =
+ {
+ ipc(server.accept())(f) match
+ {
+ case Some(done) => done
+ case None => listen()
+ }
+ }
+
+ try { listen() }
+ finally { server.close() }
+ }
+ private def ipc[T](s: Socket)(f: IPC => T): T =
+ try { f(new IPC(s)) }
+ finally { s.close() }
+
+ final class Server private[IPC](s: ServerSocket) extends NotNull
+ {
+ def port = s.getLocalPort
+ def close() = s.close()
+ def connection[T](f: IPC => T): T = IPC.ipc(s.accept())(f)
+ }
+}
+final class IPC private(s: Socket) extends NotNull
+{
+ def port = s.getLocalPort
+ private val in = new BufferedReader(new InputStreamReader(s.getInputStream))
+ private val out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream))
+
+ def send(s: String) = { out.write(s); out.newLine(); out.flush() }
+ def receive: String = in.readLine()
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/NameFilter.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/NameFilter.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/NameFilter.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/NameFilter.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,72 @@
+/* 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
+{
+ implicit def apply(expression: String): NameFilter =
+ {
+ require(!expression.exists(java.lang.Character.isISOControl), "Control characters not allowed in filter expression.")
+ if(expression == "*")
+ AllPassFilter
+ else if(expression.indexOf('*') < 0) // includes case where expression is empty
+ new ExactFilter(expression)
+ else
+ new PatternFilter(Pattern.compile(expression.split("\\*", -1).map(quote).mkString(".*")))
+ }
+ private def quote(s: String) = if(s.isEmpty) "" else Pattern.quote(s.replaceAll("\n", """\n"""))
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Pack.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Pack.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Pack.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Pack.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,79 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2009 Mark Harrah
+ */
+package sbt
+
+import java.io.{File, FileOutputStream}
+import java.util.jar.{JarEntry, JarFile, JarOutputStream, Pack200}
+import IO._
+
+object Pack
+{
+ def pack(jarPath: File, out: File): Unit = pack(jarPath, out, defaultPackerOptions)
+ def pack(jarPath: File, out: File, options: Iterable[(String, String)])
+ {
+ val packer = Pack200.newPacker
+ import collection.JavaConversions._
+ packer.properties ++= options
+
+ Using.jarFile(false)(jarPath) { f =>
+ Using.fileOutputStream()(out) { stream =>
+ packer.pack(f, stream)
+ }
+ }
+ }
+ def unpack(packedPath: File, toJarPath: File)
+ {
+ val unpacker = Pack200.newUnpacker
+ Using.fileOutputStream()(toJarPath) { fileStream =>
+ Using.jarOutputStream(fileStream) { jarOut =>
+ unpacker.unpack(packedPath, jarOut)
+ }
+ }
+ }
+ def defaultPackerOptions = scala.collection.immutable.Map()
+}
+
+import java.net.URL
+/** This is somewhat of a mess and is not entirely correct. jarsigner doesn't work properly
+* on scalaz and it is difficult to determine whether a jar is both signed and valid. */
+object SignJar
+{
+ final class SignOption private[SignJar](val toList: List[String], val signOnly: Boolean)
+ {
+ override def toString = toList.mkString(" ")
+ }
+ def keyStore(url: URL) = new SignOption("-keystore" :: url.toExternalForm :: Nil, true)
+ def signedJar(p: Path) = new SignOption("-signedjar" :: p.asFile.getAbsolutePath :: Nil, true)
+ def verbose = new SignOption("-verbose" :: Nil, false)
+ def sigFile(name: String) = new SignOption("-sigfile" :: name :: Nil, true)
+ def storeType(t: String) = new SignOption("-storetype" :: t :: Nil, false)
+ def provider(p: String) = new SignOption("-provider" :: p :: Nil, false)
+ def providerName(p: String) = new SignOption("-providerName" :: p :: Nil, false)
+ def storePassword(p: String) = new SignOption("-storepass" :: p :: Nil, true)
+ def keyPassword(p: String) = new SignOption("-keypass" :: p :: Nil, true)
+
+ private def VerifyOption = "-verify"
+
+ /** Uses jarsigner to sign the given jar. */
+ def sign(jarPath: File, alias: String, options: Seq[SignOption])(fork: (String, List[String]) => Int)
+ {
+ require(!alias.trim.isEmpty, "Alias cannot be empty")
+ val arguments = options.toList.flatMap(_.toList) ::: jarPath.getAbsolutePath :: alias :: Nil
+ execute("signing", arguments)(fork)
+ }
+ /** Uses jarsigner to verify the given jar.*/
+ def verify(jarPath: File, options: Seq[SignOption])(fork: (String, List[String]) => Int)
+ {
+ val arguments = options.filter(!_.signOnly).toList.flatMap(_.toList) ::: VerifyOption :: jarPath.getAbsolutePath :: Nil
+ execute("verifying", arguments)(fork)
+ }
+ private def execute(action: String, arguments: List[String])(fork: (String, List[String]) => Int)
+ {
+ val exitCode = fork(CommandName, arguments)
+ if(exitCode != 0)
+ error("Error " + action + " jar (exit code was " + exitCode + ".)")
+ }
+
+ private val CommandName = "jarsigner"
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Path.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Path.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Path.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Path.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,420 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009, 2010 Mark Harrah
+ */
+package sbt
+
+import Path._
+import IO.{pathSplit, wrapNull}
+import java.io.File
+import java.net.URL
+import scala.collection.{generic, immutable, mutable, TraversableLike}
+
+/** A Path represents a file in a project.
+* @see sbt.PathFinder*/
+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>
+ *
+ * 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: mutable.Set[Path])
+ {
+ if(asFile.exists)
+ pathSet += this
+ }
+ override def / (component: String): Path = if(component == ".") this else new RelativePath(this, component)
+ /** True if and only if the file represented by this path exists.*/
+ def exists = asFile.exists
+ /** True if and only if the file represented by this path is a directory.*/
+ def isDirectory = asFile.isDirectory
+ /** The last modified time of the file represented by this path.*/
+ def lastModified = asFile.lastModified
+ /* True if and only if file that this path represents exists and the file represented by the path 'p'
+ * does not exist or was modified before the file for this path.*/
+ def newerThan(p: Path): Boolean = exists && (!p.exists || lastModified > p.lastModified)
+ /* True if and only if file that this path represents does not exist or the file represented by the path 'p'
+ * exists and was modified after the file for this path.*/
+ def olderThan(p: Path): Boolean = p newerThan this
+ /** The file represented by this path.*/
+ def asFile: File
+ /** 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.*/
+ lazy val relativePath: String = relativePathString(sep.toString)
+ def relativePathString(separator: String): String
+ final def projectRelativePath: String = projectRelativePathString(sep.toString)
+ def projectRelativePathString(separator: String): String
+ def absolutePath: String = asFile.getAbsolutePath
+ private[sbt] def prependTo(s: String): String
+
+ /** The last component of this path.*/
+ def name = asFile.getName
+ /** The extension part of the name of this path. This is the part of the name after the last period, or the empty string if there is no period.*/
+ def ext = baseAndExt._2
+ /** The base of the name of this path. This is the part of the name before the last period, or the full name if there is no period.*/
+ def base = baseAndExt._1
+ def baseAndExt: (String, String) =
+ {
+ val nme = name
+ val dot = nme.lastIndexOf('.')
+ if(dot < 0) (nme, "") else (nme.substring(0, dot), nme.substring(dot+1))
+ }
+
+ /** Equality of Paths is defined in terms of the underlying <code>File</code>.*/
+ override final def equals(other: Any) =
+ other match
+ {
+ case op: Path => asFile == op.asFile
+ case _ => false
+ }
+ /** The hash code of a Path is that of the underlying <code>File</code>.*/
+ override final def hashCode = asFile.hashCode
+}
+private final class BaseDirectory(private[sbt] val path: Path) extends Path
+{
+ override def ### : Path = this
+ override def toString = path.toString
+ def asFile = path.asFile
+ def relativePathString(separator: String) = ""
+ def projectRelativePathString(separator: String) = path.projectRelativePathString(separator)
+ private[sbt] def prependTo(s: String) = "." + sep + s
+}
+private[sbt] final class FilePath(file: File) extends Path
+{
+ lazy val asFile = absolute(file)
+ override def toString = absolutePath
+ def relativePathString(separator: String) = asFile.getName
+ def projectRelativePathString(separator: String) = relativePathString(separator)
+ private[sbt] def prependTo(s: String) = absolutePath + sep + s
+}
+// toRoot is the path between this and the root project path and is used for toString
+private[sbt] final class ProjectDirectory(file: File, toRoot: Option[Path]) extends Path
+{
+ def this(file: File) = this(file, None)
+ lazy val asFile = absolute(file)
+ override def toString = foldToRoot(_.toString, ".")
+ def relativePathString(separator: String) = ""
+ def projectRelativePathString(separator: String) = ""
+ private[sbt] def prependTo(s: String) = foldToRoot(_.prependTo(s), "." + sep + s)
+ private[sbt] def foldToRoot[T](f: Path => T, orElse: T) = toRoot.map(f).getOrElse(orElse)
+}
+private[sbt] final class RelativePath(val parentPath: Path, val component: String) extends Path
+{
+ checkComponent(component)
+ override def toString = parentPath prependTo component
+ lazy val asFile = new File(parentPath.asFile, component)
+ private[sbt] def prependTo(s: String) = parentPath prependTo (component + sep + s)
+ def relativePathString(separator: String) = relative(parentPath.relativePathString(separator), separator)
+ def projectRelativePathString(separator: String) = relative(parentPath.projectRelativePathString(separator), separator)
+ private def relative(parentRelative: String, separator: String) =
+ {
+ if(parentRelative.isEmpty)
+ component
+ else
+ parentRelative + separator + component
+ }
+}
+ import java.io.File
+ import File.pathSeparator
+trait PathExtra extends Alternatives with Mapper
+{
+ 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)
+ implicit def filesToPaths[CC[X] <: TraversableLike[X,CC[X]]](cc: CC[File])(implicit cb: generic.CanBuildFrom[CC[File], Path, CC[Path]]): CC[Path] =
+ cc.map(fileToPath)
+ implicit def filesToFinder(cc: Traversable[File]): PathFinder = finder(cc)
+ implicit def pathsToFinder(cc: Traversable[Path]): PathFinder = lazyPathFinder(cc)
+}
+object Path extends PathExtra
+{
+ def fileProperty(name: String) = Path.fromFile(System.getProperty(name))
+ def userHome = fileProperty("user.home")
+
+ def absolute(file: File) = new File(file.toURI.normalize).getAbsoluteFile
+ /** Constructs a String representation of <code>Path</code>s. The absolute path String of each <code>Path</code> is
+ * separated by the platform's path separator.*/
+ def makeString(paths: Iterable[Path]): String = makeString(paths, pathSeparator)
+ /** Constructs a String representation of <code>Path</code>s. The absolute path String of each <code>Path</code> is
+ * separated by the given separator String.*/
+ def makeString(paths: Iterable[Path], sep: String): String = paths.map(_.absolutePath).mkString(sep)
+
+ def makeString(paths: Seq[File]): String = makeString(paths, pathSeparator)
+ def makeString(paths: Seq[File], sep: String): String = paths.map(_.getAbsolutePath).mkString(sep)
+
+ /** Constructs a String representation of <code>Path</code>s. The relative path String of each <code>Path</code> is
+ * separated by the platform's path separator.*/
+ def makeRelativeString(paths: Iterable[Path]): String = paths.map(_.relativePathString(sep.toString)).mkString(pathSeparator)
+
+ def splitString(projectPath: Path, value: String): Iterable[Path] =
+ {
+ for(pathString <- pathSplit(value) if pathString.length > 0) yield
+ Path.fromString(projectPath, pathString)
+ }
+
+ /** A <code>PathFinder</code> that always produces the empty set of <code>Path</code>s.*/
+ def emptyPathFinder =
+ new PathFinder
+ {
+ 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: => Traversable[Path]): PathFinder =
+ new PathFinder
+ {
+ private[sbt] def addTo(pathSet: mutable.Set[Path]) = pathSet ++= paths
+ }
+ def finder(files: => Traversable[File]): PathFinder = lazyPathFinder { fromFiles(files) }
+
+ /** The separator character of the platform.*/
+ val sep = java.io.File.separatorChar
+
+ /** Checks the string to verify that it is a legal path component. The string must be non-empty,
+ * not a slash, and not '.' or '..'.*/
+ def checkComponent(c: String): String =
+ {
+ require(c.length > 0, "Path component must not be empty")
+ require(c.indexOf('/') == -1, "Path component '" + c + "' must not have forward slashes in it")
+ require(c.indexOf('\\') == -1, "Path component '" + c + "' must not have backslashes in it")
+ require(c != "..", "Path component cannot be '..'")
+ require(c != ".", "Path component cannot be '.'")
+ c
+ }
+ /** Converts a path string relative to the given base path to a <code>Path</code>. */
+ def fromString(basePath: Path, value: String): Path =
+ {
+ if(value.isEmpty)
+ basePath
+ else
+ {
+ val f = new File(value)
+ if(f.isAbsolute)
+ fromFile(f)
+ else
+ {
+ val components = value.split("""[/\\]""")
+ (basePath /: components)( (path, component) => path / component )
+ }
+ }
+ }
+ def baseAncestor(path: Path): Option[Path] =
+ path match
+ {
+ case pd: ProjectDirectory => None
+ case fp: FilePath => None
+ case rp: RelativePath => baseAncestor(rp.parentPath)
+ case b: BaseDirectory => Some(b.path)
+ }
+
+ def relativize(basePath: Path, path: Path): Option[Path] = relativize(basePath, path.asFile)
+ def relativize(basePath: Path, file: File): Option[Path] =
+ basePathString(basePath) flatMap { baseString => relativize(basePath, baseString, file) }
+ def relativize(basePath: Path, basePathString: String, file: File): Option[Path] =
+ {
+ val pathString = file.getAbsolutePath
+ if(pathString.startsWith(basePathString))
+ Some(fromString(basePath, pathString.substring(basePathString.length)))
+ else
+ None
+ }
+ def relativizeFile(baseFile: File, file: File): Option[File] = relativize(baseFile, file).map { path => new File(path) }
+ private[sbt] def relativize(baseFile: File, file: File): Option[String] =
+ {
+ val pathString = file.getAbsolutePath
+ baseFileString(baseFile) flatMap
+ {
+ baseString =>
+ {
+ if(pathString.startsWith(baseString))
+ Some(pathString.substring(baseString.length))
+ else
+ None
+ }
+ }
+ }
+ private[sbt] def basePathString(basePath: Path): Option[String] = baseFileString(basePath.asFile)
+ private def baseFileString(baseFile: File): Option[String] =
+ {
+ if(baseFile.isDirectory)
+ {
+ val cp = baseFile.getAbsolutePath
+ assert(cp.length > 0)
+ if(cp.charAt(cp.length - 1) == File.separatorChar)
+ Some(cp)
+ else
+ Some(cp + File.separatorChar)
+ }
+ else
+ None
+ }
+ def fromFile(file: String): Path = fromFile(new File(file))
+ def fromFile(file: File): Path = new FilePath(file)
+ import collection.generic.{CanBuildFrom, FilterMonadic}
+ def fromFiles[Repr, That](files: FilterMonadic[File, Repr])(implicit bf: CanBuildFrom[Repr, Path, That]): That = files.map(fromFile)
+
+ def getFiles(files: Traversable[Path]): immutable.Set[File] = files.map(_.asFile).toSet
+ def getURLs(files: Traversable[Path]): Array[URL] = files.map(_.asURL).toArray
+
+ def toURLs(files: Seq[File]): Array[URL] = files.map(_.toURI.toURL).toArray
+}
+
+/** A path finder constructs a set of paths. The set is evaluated by a call to the <code>get</code>
+* method. The set will be different for different calls to <code>get</code> if the underlying filesystem
+* has changed.*/
+sealed abstract class PathFinder extends NotNull
+{
+ /** The union of the paths found by this <code>PathFinder</code> with the paths found by 'paths'.*/
+ def +++(paths: PathFinder): PathFinder = new Paths(this, paths)
+ /** Excludes all paths from <code>excludePaths</code> from the paths selected by this <code>PathFinder</code>.*/
+ def ---(excludePaths: PathFinder): PathFinder = new ExcludePaths(this, excludePaths)
+ /** Constructs a new finder that selects all paths with a name that matches <code>filter</code> and are
+ * descendents of paths selected by this finder.*/
+ def **(filter: FileFilter): PathFinder = new DescendentOrSelfPathFinder(this, filter)
+ def *** : PathFinder = **(AllPassFilter)
+ /** Constructs a new finder that selects all paths with a name that matches <code>filter</code> and are
+ * immediate children of paths selected by this finder.*/
+ def *(filter: FileFilter): PathFinder = new ChildPathFinder(this, filter)
+ /** Constructs a new finder that selects all paths with name <code>literal</code> that are immediate children
+ * of paths selected by this finder.*/
+ def / (literal: String): PathFinder = new ChildPathFinder(this, new ExactFilter(literal))
+ /** Constructs a new finder that selects all paths with name <code>literal</code> that are immediate children
+ * of paths selected by this finder.*/
+ final def \ (literal: String): PathFinder = this / literal
+
+ /** Makes the paths selected by this finder into base directories.
+ * @see Path.###
+ */
+ def ### : PathFinder = new BasePathFinder(this)
+
+ def x_![T](mapper: File => Option[T]): Traversable[(File,T)] = x(mapper, false)
+ /** 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:
+ *
+ * <code>descendentsExcept("*.jar", ".svn")</code>*/
+ def descendentsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
+ (this ** include) --- (this ** intermediateExclude ** include)
+
+ /** 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: immutable.Set[Path] =
+ {
+ val pathSet = new mutable.HashSet[Path]
+ addTo(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))
+ /* Non-strict flatMap: no evaluation occurs until the returned finder is evaluated.*/
+ final def flatMap(f: Path => PathFinder): PathFinder = Path.lazyPathFinder(get.flatMap(p => f(p).get))
+ /** Evaluates this finder and converts the results to an `Array` of `URL`s..*/
+ final def getURLs: Array[URL] = Path.getURLs(get)
+ /** Evaluates this finder and converts the results to a `Set` of `File`s.*/
+ final def getFiles: immutable.Set[File] = Path.getFiles(get)
+ /** Evaluates this finder and converts the results to a `Set` of absolute path strings.*/
+ 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] = 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.*/
+ def distinct: PathFinder = Path.lazyPathFinder((Map() ++ get.map(p => (p.asFile.getName, p))) .values.toList )
+
+ /** Constructs a string by evaluating this finder, converting the resulting Paths to absolute path strings, and joining them with the platform path separator.*/
+ final def absString = Path.makeString(get)
+ /** Constructs a string by evaluating this finder, converting the resulting Paths to relative path strings, and joining them with the platform path separator.*/
+ final def relativeString = Path.makeRelativeString(get)
+ /** Constructs a debugging string for this finder by evaluating it and separating paths by newlines.*/
+ override def toString = get.mkString("\n ", "\n ","")
+}
+private class BasePathFinder(base: PathFinder) extends PathFinder
+{
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
+ {
+ for(path <- base.get)
+ pathSet += (path ###)
+ }
+}
+private abstract class FilterPath extends PathFinder with FileFilter
+{
+ def parent: PathFinder
+ def filter: FileFilter
+ final def accept(file: File) = filter.accept(file)
+
+ protected def handlePath(path: Path, pathSet: mutable.Set[Path])
+ {
+ for(matchedFile <- wrapNull(path.asFile.listFiles(this)))
+ pathSet += path / matchedFile.getName
+ }
+}
+private class DescendentOrSelfPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterPath
+{
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
+ {
+ for(path <- parent.get)
+ {
+ if(accept(path.asFile))
+ pathSet += path
+ handlePathDescendent(path, pathSet)
+ }
+ }
+ private def handlePathDescendent(path: Path, pathSet: mutable.Set[Path])
+ {
+ handlePath(path, pathSet)
+ for(childDirectory <- wrapNull(path.asFile.listFiles(DirectoryFilter)))
+ handlePathDescendent(path / childDirectory.getName, pathSet)
+ }
+}
+private class ChildPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterPath
+{
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
+ {
+ for(path <- parent.get)
+ handlePath(path, pathSet)
+ }
+}
+private class Paths(a: PathFinder, b: PathFinder) extends PathFinder
+{
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
+ {
+ a.addTo(pathSet)
+ b.addTo(pathSet)
+ }
+}
+private class ExcludePaths(include: PathFinder, exclude: PathFinder) extends PathFinder
+{
+ private[sbt] def addTo(pathSet: mutable.Set[Path])
+ {
+ val includeSet = new mutable.HashSet[Path]
+ include.addTo(includeSet)
+
+ val excludeSet = new mutable.HashSet[Path]
+ exclude.addTo(excludeSet)
+
+ includeSet --= excludeSet
+ pathSet ++= includeSet
+ }
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/PathMapper.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/PathMapper.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/PathMapper.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/PathMapper.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,60 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009 Mark Harrah
+ */
+package sbt
+
+ import java.io.File
+
+trait Mapper
+{
+ 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 Alternative[A,B] { def | (g: A => Option[B]): A => Option[B] }
+trait Alternatives
+{
+ 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)
+ }
+ final def alternatives[A,B](alts: Seq[A => Option[B]]): A => Option[B] =
+ alts match
+ {
+ case Seq(f, fs @ _*) => f | alternatives(fs)
+ case Seq() => a => None
+ }
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Resources.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Resources.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Resources.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Resources.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,67 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009 Mark Harrah
+ */
+package sbt
+
+import java.io.File
+import IO._
+import Resources.error
+
+object Resources
+{
+ def apply(basePath: String) =
+ {
+ require(basePath.startsWith("/"))
+ val resource = getClass.getResource(basePath)
+ if(resource == null)
+ error("Resource base directory '" + basePath + "' not on classpath.")
+ else
+ {
+ val file = toFile(resource)
+ if(file.exists)
+ new Resources(file)
+ else
+ error("Resource base directory '" + basePath + "' does not exist.")
+ }
+ }
+ def error(msg: String) = throw new ResourcesException(msg)
+ private val LoadErrorPrefix = "Error loading initial project: "
+}
+class ResourcesException(msg: String) extends Exception(msg)
+
+class Resources(val baseDirectory: File)
+{
+ import Resources._
+ // The returned directory is not actually read-only, but it should be treated that way
+ def readOnlyResourceDirectory(group: String, name: String): File =
+ {
+ val groupDirectory = new File(baseDirectory, group)
+ if(groupDirectory.isDirectory)
+ {
+ val resourceDirectory = new File(groupDirectory, name)
+ if(resourceDirectory.isDirectory)
+ resourceDirectory
+ else
+ error("Resource directory '" + name + "' in group '" + group + "' not found.")
+ }
+ else
+ error("Group '" + group + "' not found.")
+ }
+ def readWriteResourceDirectory[T](group: String, name: String)(withDirectory: File => T): T =
+ {
+ val file = readOnlyResourceDirectory(group, name)
+ readWriteResourceDirectory(file)(withDirectory)
+ }
+
+ def readWriteResourceDirectory[T](readOnly: File)(withDirectory: File => T): T =
+ {
+ require(readOnly.isDirectory)
+ def readWrite(readOnly: File)(temporary: File): T =
+ {
+ val readWriteDirectory = new File(temporary, readOnly.getName)
+ copyDirectory(readOnly, readWriteDirectory)
+ withDirectory(readWriteDirectory)
+ }
+ withTemporaryDirectory(readWrite(readOnly))
+ }
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/SourceModificationWatch.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/SourceModificationWatch.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/SourceModificationWatch.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/SourceModificationWatch.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,48 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2009, 2010 Mikko Peltonen, Stuart Roebuck, Mark Harrah
+ */
+package sbt
+
+ import annotation.tailrec
+
+object SourceModificationWatch
+{
+ @tailrec def watch(sourcesFinder: PathFinder, pollDelaySec: Int, state: WatchState)(terminationCondition: => Boolean): (Boolean, WatchState) =
+ {
+ import state._
+
+ def sourceFiles: Iterable[java.io.File] = sourcesFinder.getFiles
+ val (lastModifiedTime, fileCount) =
+ ( (0L, 0) /: sourceFiles) {(acc, file) => /*println("processing "+file);*/ (math.max(acc._1, file.lastModified), acc._2 + 1)}
+
+ //println("lastModifiedTime:"+new java.util.Date(lastModifiedTime))
+ //println("lastModifiedTime - lastCallbackCallTime"+(lastModifiedTime - lastCallbackCallTime))
+ val sourcesModified =
+ lastModifiedTime > lastCallbackCallTime ||
+ previousFileCount != fileCount
+
+ val (triggered, newCallbackCallTime) =
+ if (sourcesModified) {
+ (false, System.currentTimeMillis)
+ }
+ else
+ (awaitingQuietPeriod, lastCallbackCallTime)
+
+ val newState = new WatchState(newCallbackCallTime, fileCount, sourcesModified, if(triggered) count + 1 else count)
+ if(triggered)
+ (true, newState)
+ else
+ {
+ Thread.sleep(pollDelaySec * 1000)
+ if(terminationCondition)
+ (false, newState)
+ else
+ watch(sourcesFinder, pollDelaySec, newState)(terminationCondition)
+ }
+ }
+}
+final class WatchState(val lastCallbackCallTime: Long, val previousFileCount: Int, val awaitingQuietPeriod:Boolean, val count: Int)
+object WatchState
+{
+ def empty = new WatchState(0L, 0, false, 0)
+}
\ No newline at end of file
Added: incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Using.scala
URL: http://svn.apache.org/viewvc/incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Using.scala?rev=1063515&view=auto
==============================================================================
--- incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Using.scala (added)
+++ incubator/clerezza/trunk/org.apache.clerezza.parent/org.apache.clerezza.sourcebundle/src/main/scala/sbt/io/Using.scala Tue Jan 25 23:19:36 2011
@@ -0,0 +1,98 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009 Mark Harrah
+ */
+package sbt
+
+import java.io.{Closeable, File, FileInputStream, FileOutputStream, InputStream, OutputStream}
+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}
+import java.nio.charset.{Charset, CharsetDecoder, CharsetEncoder}
+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 ErrorHandling.translate
+import Using._
+
+abstract class Using[Source, T]
+{
+ protected def open(src: Source): T
+ def apply[R](src: Source)(f: T => R): R =
+ {
+ val resource = open(src)
+ try { f(resource) }
+ finally { close(resource) }
+ }
+ protected def close(out: T): Unit
+}
+import scala.reflect.{Manifest => SManifest}
+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 openImpl(source: Source): T
+ protected final def open(source: Source): T =
+ translate("Error wrapping " + label(srcMf) + " in " + label(targetMf) + ": ") { openImpl(source) }
+}
+trait OpenFile[T] extends Using[File, T]
+{
+ protected def openImpl(file: File): T
+ protected final def open(file: File): T =
+ {
+ val parent = file.getParentFile
+ if(parent != null)
+ IO.createDirectory(parent)
+ openImpl(file)
+ }
+}
+object Using
+{
+ def wrap[Source, T<: Closeable](openF: Source => T)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): Using[Source,T] =
+ wrap(openF, closeCloseable)
+ def wrap[Source, T](openF: Source => T, closeF: T => Unit)(implicit srcMf: SManifest[Source], targetMf: SManifest[T]): Using[Source,T] =
+ new WrapUsing[Source, T]
+ {
+ def openImpl(source: Source) = openF(source)
+ def close(t: T) = closeF(t)
+ }
+
+ def resource[Source, T <: Closeable](openF: Source => T): Using[Source,T] =
+ resource(openF, closeCloseable)
+ def resource[Source, T](openF: Source => T, closeF: T => Unit): Using[Source,T] =
+ new Using[Source,T]
+ {
+ def open(s: Source) = openF(s)
+ def close(s: T) = closeF(s)
+ }
+ def file[T <: Closeable](openF: File => T): OpenFile[T] = file(openF, closeCloseable)
+ def file[T](openF: File => T, closeF: T => Unit): OpenFile[T] =
+ new OpenFile[T]
+ {
+ def openImpl(file: File) = openF(file)
+ def close(t: T) = closeF(t)
+ }
+ private def closeCloseable[T <: Closeable]: T => Unit = _.close()
+
+ def bufferedOutputStream = wrap( (out: OutputStream) => new BufferedOutputStream(out) )
+ def bufferedInputStream = wrap( (in: InputStream) => new BufferedInputStream(in) )
+ 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)
+ def fileWriter(charset: Charset = IO.utf8, append: Boolean = false) =
+ 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 jarFile(verify: Boolean) = file(f => new JarFile(f, verify), (_: JarFile).close())
+ def zipFile = file(f => new ZipFile(f), (_: ZipFile).close())
+ def streamReader = wrap{ (_: (InputStream, Charset)) match { case (in, charset) => new InputStreamReader(in, charset) } }
+ def gzipInputStream = wrap( (in: InputStream) => new GZIPInputStream(in, 8192) )
+ def zipInputStream = wrap( (in: InputStream) => new ZipInputStream(in))
+ def zipOutputStream = wrap( (out: OutputStream) => new ZipOutputStream(out))
+ def gzipOutputStream = wrap((out: OutputStream) => new GZIPOutputStream(out, 8192), (_: GZIPOutputStream).finish())
+ def jarOutputStream = wrap( (out: OutputStream) => new JarOutputStream(out))
+ def jarInputStream = wrap( (in: InputStream) => new JarInputStream(in))
+ def zipEntry(zip: ZipFile) = resource( (entry: ZipEntry) =>
+ translate("Error opening " + entry.getName + " in " + zip + ": ") { zip.getInputStream(entry) } )
+}
\ No newline at end of file