mirror of https://github.com/sbt/sbt.git
more 2.8 updates, launcher compiles and runs with 2.8
This commit is contained in:
parent
1585d805bd
commit
b2077ce60c
|
|
@ -22,7 +22,7 @@ class CompilerArguments(scalaInstance: ScalaInstance, cp: ClasspathOptions) exte
|
|||
def finishClasspath(classpath: Set[File]): Set[File] =
|
||||
classpath ++ include(cp.compiler, scalaInstance.compilerJar) ++ include(cp.extra, scalaInstance.extraJars : _*)
|
||||
private def include(flag: Boolean, jars: File*) = if(flag) jars else Nil
|
||||
protected def abs(files: Set[File]) = files.map(_.getAbsolutePath).toList.sort(_ < _)
|
||||
protected def abs(files: Set[File]) = files.map(_.getAbsolutePath).toList.sortWith(_ < _)
|
||||
protected def checkScalaHomeUnset()
|
||||
{
|
||||
val scalaHome = System.getProperty("scala.home")
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ object ComponentCompiler
|
|||
class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
|
||||
{
|
||||
import ComponentCompiler._
|
||||
import FileUtilities.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory}
|
||||
import sbt.IO.{copy, createDirectory, zip, jars, unzip, withTemporaryDirectory}
|
||||
def apply(id: String): File =
|
||||
try { getPrecompiled(id) }
|
||||
catch { case _: InvalidComponent => getLocallyCompiled(id) }
|
||||
|
|
@ -55,7 +55,6 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
|
|||
val isSource = (f: File) => isSourceName(f.getName)
|
||||
def keepIfSource(files: Set[File]): Set[File] = if(files.exists(isSource)) files else Set()
|
||||
|
||||
import Paths._
|
||||
withTemporaryDirectory { dir =>
|
||||
val extractedSources = (Set[File]() /: sourceJars) { (extracted, sourceJar)=> extracted ++ keepIfSource(unzip(sourceJar, dir)) }
|
||||
val (sourceFiles, resources) = extractedSources.partition(isSource)
|
||||
|
|
@ -69,8 +68,9 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
|
|||
manager.log.info(" Compilation completed in " + (System.currentTimeMillis - start) / 1000.0 + " s")
|
||||
}
|
||||
catch { case e: xsbti.CompileFailed => throw new CompileFailed(e.arguments, "Error compiling sbt component '" + id + "'") }
|
||||
copy(resources x (FileMapper.rebase(dir, outputDirectory)))
|
||||
zip((outputDirectory ***) x (PathMapper.relativeTo(outputDirectory)), targetJar)
|
||||
import sbt.Path._
|
||||
copy(resources x rebase(dir, outputDirectory))
|
||||
zip((outputDirectory ***) x relativeTo(outputDirectory), targetJar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: C
|
|||
log.debug("Plain interface to Scala compiler " + scalaInstance.actualVersion + " with arguments: " + arguments.mkString("\n\t", "\n\t", ""))
|
||||
val mainClass = Class.forName("scala.tools.nsc.Main", true, scalaInstance.loader)
|
||||
val process = mainClass.getMethod("process", classOf[Array[String]])
|
||||
process.invoke(null, toJavaArray(arguments))
|
||||
process.invoke(null, arguments.toArray)
|
||||
checkForFailure(mainClass, arguments.toArray)
|
||||
}
|
||||
def compilerArguments = new CompilerArguments(scalaInstance, cp)
|
||||
|
|
@ -29,12 +29,6 @@ class RawCompiler(val scalaInstance: ScalaInstance, cp: ClasspathOptions, log: C
|
|||
val failed = reporter.getClass.getMethod("hasErrors").invoke(reporter).asInstanceOf[Boolean]
|
||||
if(failed) throw new CompileFailed(args, "Plain compile failed")
|
||||
}
|
||||
protected def toJavaArray(arguments: Seq[String]): Array[String] =
|
||||
{
|
||||
val realArray: Array[String] = arguments.toArray
|
||||
assert(realArray.getClass eq classOf[Array[String]])
|
||||
realArray
|
||||
}
|
||||
}
|
||||
class CompileFailed(val arguments: Array[String], override val toString: String) extends xsbti.CompileFailed
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ object SameAPI
|
|||
}
|
||||
|
||||
def separateDefinitions(s: Seq[Definition]): (Seq[Definition], Seq[Definition]) =
|
||||
s.toArray.partition(isValueDefinition)
|
||||
s.partition(isValueDefinition)
|
||||
def isValueDefinition(d: Definition): Boolean =
|
||||
d match
|
||||
{
|
||||
|
|
@ -59,12 +59,12 @@ object SameAPI
|
|||
def isValue(d: DefinitionType): Boolean =
|
||||
d == DefinitionType.Module || d == DefinitionType.PackageModule
|
||||
/** Puts the given definitions in a map according to their names.*/
|
||||
def byName(s: Seq[Definition]): scala.collection.Map[String, List[Definition]] =
|
||||
def byName(s: Seq[Definition]): Map[String, List[Definition]] =
|
||||
{
|
||||
val map = new mutable.HashMap[String, List[Definition]]
|
||||
var map = Map[String, List[Definition]]()
|
||||
for(d <- s; name = d.name)
|
||||
map(name) = d :: map.getOrElse(name, Nil)
|
||||
map.readOnly
|
||||
map = map.updated(name, d :: map.getOrElse(name, Nil) )
|
||||
map
|
||||
}
|
||||
}
|
||||
/** Used to implement API equality. All comparisons must be done between constructs in source files `a` and `b`. For example, when doing:
|
||||
|
|
@ -358,7 +358,5 @@ private class SameAPI(a: Source, b: Source, includePrivate: Boolean)
|
|||
def sameStrings(a: scala.collection.Set[String], b: scala.collection.Set[String]): Boolean =
|
||||
a == b
|
||||
final def sameSeq[T](a: Seq[T], b: Seq[T])(eq: (T,T) => Boolean): Boolean =
|
||||
sameArray(a.toArray, b.toArray)(eq)
|
||||
final def sameArray[T](a: Array[T], b: Array[T])(eq: (T,T) => Boolean): Boolean =
|
||||
(a.length == b.length) && (a zip b).forall(tupled(eq))
|
||||
}
|
||||
|
|
@ -9,13 +9,16 @@ import io.{AbstractFile, PlainFile, ZipArchive}
|
|||
import plugins.{Plugin, PluginComponent}
|
||||
import symtab.Flags
|
||||
import scala.collection.mutable.{HashMap, HashSet, ListBuffer}
|
||||
//import xsbti.api.{ClassLike, DefinitionType, PathComponent, SimpleType}
|
||||
import xsbti.api.{ClassLike, DefinitionType, PathComponent, SimpleType}
|
||||
|
||||
object API
|
||||
{
|
||||
val name = "xsbt-api"
|
||||
// for 2.7 compatibility: this class was removed in 2.8
|
||||
type ImplicitMethodType = AnyRef
|
||||
}
|
||||
final class API(val global: Global, val callback: xsbti.AnalysisCallback) extends NotNull
|
||||
import API._ // imports ImplicitMethodType, which will preserve source compatibility in 2.7 for defDef
|
||||
final class API(val global: Global, val callback: xsbti.AnalysisCallback) extends Compat
|
||||
{
|
||||
import global._
|
||||
def error(msg: String) = throw new RuntimeException(msg)
|
||||
|
|
@ -35,7 +38,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
println("API phase took : " + ((stop - start)/1000.0) + " s")
|
||||
}
|
||||
}
|
||||
/*def processUnit(unit: CompilationUnit)
|
||||
def processUnit(unit: CompilationUnit)
|
||||
{
|
||||
val sourceFile = unit.source.file.file
|
||||
val traverser = new TopLevelHandler(sourceFile)
|
||||
|
|
@ -43,9 +46,9 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
val packages = traverser.packages.toArray[String].map(p => new xsbti.api.Package(p))
|
||||
val source = new xsbti.api.Source(packages, traverser.definitions.toArray[xsbti.api.Definition])
|
||||
callback.api(sourceFile, source)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
/*private def thisPath(sym: Symbol) = path(pathComponents(sym, Constants.thisPath :: Nil))
|
||||
private def thisPath(sym: Symbol) = path(pathComponents(sym, Constants.thisPath :: Nil))
|
||||
private def path(components: List[PathComponent]) = new xsbti.api.Path(components.toArray[PathComponent])
|
||||
private def pathComponents(sym: Symbol, postfix: List[PathComponent]): List[PathComponent] =
|
||||
{
|
||||
|
|
@ -64,7 +67,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
if(pre == NoPrefix)
|
||||
{
|
||||
if(sym.isLocalClass) Constants.emptyType
|
||||
else if(sym.isTypeParameterOrSkolem || sym.isExistential) new xsbti.api.ParameterRef(sym.id)
|
||||
else if(sym.isTypeParameterOrSkolem || isExistential(sym)) new xsbti.api.ParameterRef(sym.id)
|
||||
else error("Unknown prefixless type: " + sym)
|
||||
}
|
||||
else if(sym.isRoot || sym.isRootPackage) Constants.emptyType
|
||||
|
|
@ -178,7 +181,7 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
{
|
||||
if(sym.isClass) classLike(sym)
|
||||
else if(sym.isMethod) defDef(sym)
|
||||
else if(sym.isTypeMember) typeDef(sym)
|
||||
else if(isNonClassType(sym)) typeDef(sym)
|
||||
else if(sym.isVariable) fieldDef(sym, new xsbti.api.Var(_,_,_,_,_))
|
||||
else fieldDef(sym, new xsbti.api.Val(_,_,_,_,_))
|
||||
}
|
||||
|
|
@ -316,6 +319,6 @@ final class API(val global: Global, val callback: xsbti.AnalysisCallback) extend
|
|||
val annots = at.attributes
|
||||
if(annots.isEmpty) processType(at.underlying) else annotated(annots, at.underlying)
|
||||
}
|
||||
private def fullName(s: Symbol): String = s.fullNameString
|
||||
private def simpleName(s: Symbol): String = s.simpleName.toString.trim*/
|
||||
private def fullName(s: Symbol): String = nameString(s)
|
||||
private def simpleName(s: Symbol): String = s.simpleName.toString.trim
|
||||
}
|
||||
|
|
@ -17,10 +17,9 @@ object Analyzer
|
|||
{
|
||||
def name = "xsbt-analyzer"
|
||||
}
|
||||
final class Analyzer(val global: Global, val callback: AnalysisCallback) extends NotNull
|
||||
final class Analyzer(val global: Global, val callback: AnalysisCallback) extends Compat
|
||||
{
|
||||
import global._
|
||||
import Compat.{archive, hasAnnotation, linkedClass, nameString}
|
||||
|
||||
def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev)
|
||||
private class AnalyzerPhase(prev: Phase) extends Phase(prev)
|
||||
|
|
@ -216,35 +215,42 @@ final class Analyzer(val global: Global, val callback: AnalysisCallback) extends
|
|||
if(entry eq null) None else Some(entry.classFile)
|
||||
}
|
||||
}
|
||||
private object Compat
|
||||
}
|
||||
abstract class Compat
|
||||
{
|
||||
val global: Global
|
||||
import global._
|
||||
def archive(s: ZipArchive#Entry): ZipFile = s.getArchive
|
||||
def nameString(s: Symbol): String = s.fullNameString
|
||||
def nameString(s: Symbol, sep: Char): String = s.fullNameString(sep)
|
||||
def isExistential(s: Symbol): Boolean = s.isExistential
|
||||
def isNonClassType(s: Symbol): Boolean = s.isTypeMember
|
||||
|
||||
def linkedClass(s: Symbol): Symbol = s.linkedClassOfModule
|
||||
|
||||
/** After 2.8.0.Beta1, fullNameString was renamed fullName.
|
||||
* linkedClassOfModule was renamed companionClass. */
|
||||
private implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym)
|
||||
private final class SymCompat(s: Symbol)
|
||||
{
|
||||
def archive(s: ZipArchive#Entry): ZipFile = s.getArchive
|
||||
def nameString(s: Symbol): String = s.fullNameString
|
||||
def nameString(s: Symbol, sep: Char): String = s.fullNameString(sep)
|
||||
|
||||
def linkedClass(s: Symbol): Symbol = s.linkedClassOfModule
|
||||
|
||||
/** After 2.8.0.Beta1, fullNameString was renamed fullName.
|
||||
* linkedClassOfModule was renamed companionClass. */
|
||||
private implicit def symCompat(sym: Symbol): SymCompat = new SymCompat(sym)
|
||||
private final class SymCompat(s: Symbol)
|
||||
{
|
||||
def fullNameString = s.fullName; def fullName = sourceCompatibilityOnly
|
||||
def fullNameString(sep: Char) = s.fullName(sep); def fullName(sep: Char) = sourceCompatibilityOnly
|
||||
|
||||
def linkedClassOfModule = s.companionClass; def companionClass = sourceCompatibilityOnly
|
||||
// In 2.8, hasAttribute is renamed to hasAnnotation
|
||||
def hasAnnotation(a: Symbol) = s.hasAttribute(a); def hasAttribute(a: Symbol) = sourceCompatibilityOnly
|
||||
}
|
||||
|
||||
def hasAnnotation(s: Symbol)(ann: Symbol) = atPhase(currentRun.typerPhase) { s.hasAnnotation(ann) }
|
||||
|
||||
/** After 2.8.0.Beta1, getArchive was renamed archive.*/
|
||||
private implicit def zipCompat(z: ZipArchive#Entry): ZipCompat = new ZipCompat(z)
|
||||
private final class ZipCompat(z: ZipArchive#Entry)
|
||||
{
|
||||
def getArchive = z.archive; def archive = sourceCompatibilityOnly
|
||||
}
|
||||
private def sourceCompatibilityOnly = error("For source compatibility only: should not get here.")
|
||||
def fullNameString = s.fullName; def fullName = sourceCompatibilityOnly
|
||||
def fullNameString(sep: Char) = s.fullName(sep); def fullName(sep: Char) = sourceCompatibilityOnly
|
||||
|
||||
def isExistential: Boolean = s.isExistentiallyBound; def isExistentiallyBound = sourceCompatibilityOnly
|
||||
def isTypeMember: Boolean = s.isNonClassType; def isNonClassType = sourceCompatibilityOnly
|
||||
|
||||
def linkedClassOfModule = s.companionClass; def companionClass = sourceCompatibilityOnly
|
||||
// In 2.8, hasAttribute is renamed to hasAnnotation
|
||||
def hasAnnotation(a: Symbol) = s.hasAttribute(a); def hasAttribute(a: Symbol) = sourceCompatibilityOnly
|
||||
}
|
||||
|
||||
def hasAnnotation(s: Symbol)(ann: Symbol) = atPhase(currentRun.typerPhase) { s.hasAnnotation(ann) }
|
||||
|
||||
/** After 2.8.0.Beta1, getArchive was renamed archive.*/
|
||||
private implicit def zipCompat(z: ZipArchive#Entry): ZipCompat = new ZipCompat(z)
|
||||
private final class ZipCompat(z: ZipArchive#Entry)
|
||||
{
|
||||
def getArchive = z.archive; def archive = sourceCompatibilityOnly
|
||||
}
|
||||
private def sourceCompatibilityOnly = error("For source compatibility only: should not get here.")
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentPr
|
|||
try { update(id); getOrElse(createAndCache) }
|
||||
catch { case e: NotInCache => createAndCache }
|
||||
}
|
||||
def getOrElse(orElse: => Iterable[File]) =
|
||||
def getOrElse(orElse: => Iterable[File]): Iterable[File] =
|
||||
{
|
||||
val existing = provider.component(id)
|
||||
if(existing.isEmpty) orElse else existing
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ import plugins.repository.Resource
|
|||
import plugins.repository.url.URLResource
|
||||
|
||||
/** Subclasses the default Ivy file parser in order to provide access to protected methods.*/
|
||||
private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser with NotNull
|
||||
private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser
|
||||
{
|
||||
import XmlModuleDescriptorParser.Parser
|
||||
class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings) with NotNull
|
||||
class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings)
|
||||
{
|
||||
if(defaultConfig.isDefined) setDefaultConfMapping("*->default(compile)")
|
||||
|
||||
|
|
|
|||
|
|
@ -257,13 +257,7 @@ private object IvySbt
|
|||
javaMap(ea.extraAttributes)
|
||||
}
|
||||
private def javaMap(map: Map[String,String]) =
|
||||
if(map.isEmpty) null
|
||||
else
|
||||
{
|
||||
val wrap = scala.collection.jcl.Map(new java.util.HashMap[String,String])
|
||||
wrap ++= map
|
||||
wrap.underlying
|
||||
}
|
||||
if(map.isEmpty) null else scala.collection.JavaConversions.asMap(map)
|
||||
|
||||
private object javaMap
|
||||
{
|
||||
|
|
@ -337,7 +331,7 @@ private object IvySbt
|
|||
lazy val allConfigurations = moduleID.getPublicConfigurationsNames
|
||||
for(artifact <- artifacts)
|
||||
{
|
||||
val configurationStrings =
|
||||
val configurationStrings: Iterable[String] =
|
||||
{
|
||||
val artifactConfigurations = artifact.configurations
|
||||
if(artifactConfigurations.isEmpty)
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@ object IvyActions
|
|||
}
|
||||
|
||||
/** Creates a Maven pom from the given Ivy configuration*/
|
||||
@deprecated def makePom(module: IvySbt#Module, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], extra: NodeSeq, output: File): Unit =
|
||||
makePom(module, MakePomConfiguration(extraDependencies, configurations, extra), output)
|
||||
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, output: File)
|
||||
{
|
||||
import configuration.{configurations, extra, extraDependencies, filterRepositories, process}
|
||||
|
|
@ -127,7 +125,7 @@ object IvyActions
|
|||
resolveOptions.setLog(ivyLogLevel(logging))
|
||||
val resolveReport = ivy.resolve(module, resolveOptions)
|
||||
if(resolveReport.hasError)
|
||||
throw new ResolveException(resolveReport.getAllProblemMessages.toArray.map(_.toString).toList.removeDuplicates)
|
||||
throw new ResolveException(resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct)
|
||||
}
|
||||
|
||||
import UpdateLogging.{Quiet, Full, DownloadOnly}
|
||||
|
|
@ -140,4 +138,4 @@ object IvyActions
|
|||
case Full => LOG_DEFAULT
|
||||
}
|
||||
}
|
||||
final class ResolveException(messages: List[String]) extends RuntimeException(messages.mkString("\n"))
|
||||
final class ResolveException(messages: Seq[String]) extends RuntimeException(messages.mkString("\n"))
|
||||
|
|
@ -27,7 +27,7 @@ object Boot
|
|||
catch
|
||||
{
|
||||
case b: BootException => errorAndExit(b.toString)
|
||||
case r: xsbti.RetrieveException =>errorAndExit("Error: " + r.getMessage)
|
||||
case r: xsbti.RetrieveException => errorAndExit("Error: " + r.getMessage)
|
||||
case r: xsbti.FullReload => r.arguments
|
||||
case e =>
|
||||
e.printStackTrace
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package xsbt.boot
|
|||
import Pre._
|
||||
import java.io.{File, FileInputStream, InputStreamReader}
|
||||
import java.net.{MalformedURLException, URI, URL}
|
||||
import scala.collection.immutable.List
|
||||
|
||||
object Configuration
|
||||
{
|
||||
|
|
@ -21,7 +22,7 @@ object Configuration
|
|||
}
|
||||
def configurationOnClasspath: URL =
|
||||
{
|
||||
resourcePaths.elements.map(getClass.getResource).find(_ ne null) getOrElse
|
||||
resourcePaths.iterator.map(getClass.getResource).find(_ ne null) getOrElse
|
||||
( multiPartError("Could not finder sbt launch configuration. Searched classpath for:", resourcePaths))
|
||||
}
|
||||
def directConfiguration(path: String, baseDirectory: File): URL =
|
||||
|
|
@ -39,7 +40,7 @@ object Configuration
|
|||
}
|
||||
val against = resolveAgainst(baseDirectory)
|
||||
// use Iterators so that resolution occurs lazily, for performance
|
||||
val resolving = against.elements.flatMap(e => resolve(e).toList.elements)
|
||||
val resolving = against.iterator.flatMap(e => resolve(e).toList.iterator)
|
||||
if(!resolving.hasNext) multiPartError("Could not find configuration file '" + path + "'. Searched:", against)
|
||||
resolving.next()
|
||||
}
|
||||
|
|
@ -49,9 +50,9 @@ object Configuration
|
|||
val JarBasePath = "/sbt/"
|
||||
def userConfigurationPath = "/" + ConfigurationName
|
||||
def defaultConfigurationPath = JarBasePath + ConfigurationName
|
||||
def resourcePaths: List[String] = List(userConfigurationPath, defaultConfigurationPath)
|
||||
def resolveAgainst(baseDirectory: File): List[URI] = List(baseDirectory toURI, new File(System.getProperty("user.home")) toURI,
|
||||
toDirectory(classLocation(getClass).toURI))
|
||||
def resourcePaths: List[String] = userConfigurationPath :: defaultConfigurationPath :: Nil
|
||||
def resolveAgainst(baseDirectory: File): List[URI] = (baseDirectory toURI) :: (new File(System.getProperty("user.home")) toURI) ::
|
||||
toDirectory(classLocation(getClass).toURI) :: Nil
|
||||
|
||||
def classLocation(cl: Class[_]): URL =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import java.lang.Character.isWhitespace
|
|||
import java.io.{BufferedReader, File, FileInputStream, InputStreamReader, Reader, StringReader}
|
||||
import java.net.{MalformedURLException, URL}
|
||||
import java.util.regex.Pattern
|
||||
import scala.collection.immutable.List
|
||||
|
||||
class ConfigurationParser extends NotNull
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package xsbt.boot
|
|||
import Pre._
|
||||
import java.io.{File, FileInputStream, FileOutputStream}
|
||||
import java.util.Properties
|
||||
import scala.collection.immutable.List
|
||||
|
||||
object Initialize
|
||||
{
|
||||
|
|
@ -41,7 +42,7 @@ object Initialize
|
|||
if(!uninitialized.isEmpty)
|
||||
{
|
||||
file.getParentFile.mkdirs()
|
||||
Using(new FileOutputStream(file))( out => properties.save(out, "") )
|
||||
Using(new FileOutputStream(file))( out => properties.store(out, "") )
|
||||
}
|
||||
}
|
||||
def initialize(properties: Properties, name: String, init: PropertyInit)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package xsbt.boot
|
||||
|
||||
import Pre._
|
||||
import scala.collection.immutable.List
|
||||
|
||||
class Enumeration extends NotNull
|
||||
{
|
||||
|
|
@ -25,6 +26,5 @@ class Enumeration extends NotNull
|
|||
def value(s: String) = new Value(s, 0)
|
||||
def value(s: String, i: Int) = new Value(s, i)
|
||||
class Value(override val toString: String, val id: Int) extends NotNull
|
||||
|
||||
def toValue(s: String): Value = elements.find(_.toString == s).getOrElse(error("Expected one of " + elements.mkString(",") + " (got: " + s + ")"))
|
||||
}
|
||||
|
|
@ -4,10 +4,11 @@
|
|||
package xsbt.boot
|
||||
|
||||
import BootConfiguration.{IvyPackage, JLinePackagePath, SbtBootPackage, ScalaPackage}
|
||||
import scala.collection.immutable.Stream
|
||||
|
||||
/** A custom class loader to ensure the main part of sbt doesn't load any Scala or
|
||||
* Ivy classes from the jar containing the loader. */
|
||||
private[boot] final class BootFilteredLoader(parent: ClassLoader) extends ClassLoader(parent) with NotNull
|
||||
private[boot] final class BootFilteredLoader(parent: ClassLoader) extends ClassLoader(parent)
|
||||
{
|
||||
@throws(classOf[ClassNotFoundException])
|
||||
override final def loadClass(className: String, resolve: Boolean): Class[_] =
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package xsbt.boot
|
|||
import Pre._
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import scala.collection.immutable.List
|
||||
|
||||
object Find { def apply(config: LaunchConfiguration, currentDirectory: File) = (new Find(config))(currentDirectory) }
|
||||
class Find(config: LaunchConfiguration) extends NotNull
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Pre._
|
|||
import BootConfiguration.{CompilerModuleName, LibraryModuleName}
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import scala.collection.immutable.List
|
||||
|
||||
object Launch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package xsbt.boot
|
|||
import Pre._
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import scala.collection.immutable.List
|
||||
|
||||
final case class LaunchConfiguration(scalaVersion: Version, ivyConfiguration: IvyOptions, app: Application, boot: BootSetup, logging: Logging, appProperties: List[AppProperty]) extends NotNull
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
package xsbt.boot
|
||||
|
||||
import Pre._
|
||||
import scala.collection.{Iterable, Iterator}
|
||||
import scala.collection.immutable.List
|
||||
|
||||
// preserves iteration order
|
||||
sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Iterable[(K,V)] with NotNull
|
||||
sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Traversable[(K,V)] with NotNull
|
||||
{
|
||||
import ListMap.remove
|
||||
def update(k: K, v: V) = this.+( (k,v) )
|
||||
|
|
@ -16,7 +18,7 @@ sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Iterable[(K,V)]
|
|||
def keys: List[K] = backing.reverse.map(_._1)
|
||||
def apply(k: K): V = get(k).getOrElse(error("Key " + k + " not found"))
|
||||
def contains(k: K): Boolean = get(k).isDefined
|
||||
def elements: Iterator[(K,V)] = backing.reverse.elements
|
||||
def foreach[T](f: ((K,V)) => T) = backing.reverse.foreach(f)
|
||||
override def isEmpty: Boolean = backing.isEmpty
|
||||
override def toList = backing.reverse
|
||||
override def toSeq = toList
|
||||
|
|
@ -30,7 +32,7 @@ sealed class ListMap[K,V] private(backing: List[(K,V)]) extends Iterable[(K,V)]
|
|||
}
|
||||
object ListMap
|
||||
{
|
||||
def apply[K,V](pairs: (K,V)*) = new ListMap[K,V](pairs.toList.removeDuplicates)
|
||||
def apply[K,V](pairs: (K,V)*) = new ListMap[K,V](pairs.toList.distinct)
|
||||
def empty[K,V] = new ListMap[K,V](Nil)
|
||||
private def remove[K,V](backing: List[(K,V)], k: K) = backing.filter(_._1 != k)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package xsbt.boot
|
|||
import java.io.{File, FileOutputStream}
|
||||
import java.nio.channels.FileChannel
|
||||
import java.util.concurrent.Callable
|
||||
import scala.collection.immutable.List
|
||||
|
||||
object GetLocks
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright 2008, 2009, 2010 Mark Harrah
|
||||
*/
|
||||
package xsbt.boot
|
||||
import scala.collection.immutable.List
|
||||
|
||||
object Pre
|
||||
{
|
||||
|
|
@ -19,7 +20,7 @@ object Pre
|
|||
def declined(msg: String): Nothing = throw new BootException(msg)
|
||||
def prefixError(msg: String): String = "Error during sbt execution: " + msg
|
||||
def toBoolean(s: String) = java.lang.Boolean.parseBoolean(s)
|
||||
def toArray[T](list: List[T]) =
|
||||
def toArray[T : ClassManifest](list: List[T]) =
|
||||
{
|
||||
val arr = new Array[T](list.length)
|
||||
def copy(i: Int, rem: List[T]): Unit =
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ import SbtIvyLogger.{acceptError, acceptMessage}
|
|||
|
||||
/** A custom logger for Ivy to ignore the messages about not finding classes
|
||||
* intentionally filtered using proguard and about 'unknown resolver'. */
|
||||
private final class SbtIvyLogger(logWriter: PrintWriter) extends DefaultMessageLogger(Message.MSG_INFO) with NotNull
|
||||
private final class SbtIvyLogger(logWriter: PrintWriter) extends DefaultMessageLogger(Message.MSG_INFO)
|
||||
{
|
||||
override def log(msg: String, level: Int)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,5 +35,4 @@ object ListMapEmpty extends Properties("ListMap.empty")
|
|||
property("toSeq.isEmpty") = empty.toSeq.isEmpty
|
||||
property("toStream.isEmpty") = empty.toStream.isEmpty
|
||||
property("keys.isEmpty") = empty.keys.isEmpty
|
||||
property("elements.isEmpty") = !empty.elements.hasNext
|
||||
}
|
||||
|
|
@ -3,20 +3,21 @@ package xsbt.boot
|
|||
import org.scalacheck._
|
||||
import Prop._
|
||||
import java.io.File
|
||||
import sbt.IO.withTemporaryDirectory
|
||||
|
||||
/** These mainly test that things work in the uncontested case and that no OverlappingFileLockExceptions occur.
|
||||
* There is no real locking testing, just the coordination of locking.*/
|
||||
object LocksTest extends Properties("Locks")
|
||||
{
|
||||
property("Lock in nonexisting directory") = spec {
|
||||
FileUtilities.withTemporaryDirectory { dir =>
|
||||
withTemporaryDirectory { dir =>
|
||||
val lockFile = new File(dir, "doesntexist/lock")
|
||||
Locks(lockFile, callTrue)
|
||||
}
|
||||
}
|
||||
|
||||
property("Uncontested re-entrant lock") = spec {
|
||||
FileUtilities.withTemporaryDirectory { dir =>
|
||||
withTemporaryDirectory { dir =>
|
||||
val lockFile = new File(dir, "lock")
|
||||
Locks(lockFile, callLocked(lockFile)) &&
|
||||
Locks(lockFile, callLocked(lockFile))
|
||||
|
|
@ -24,7 +25,7 @@ object LocksTest extends Properties("Locks")
|
|||
}
|
||||
|
||||
property("Uncontested double lock") = spec {
|
||||
FileUtilities.withTemporaryDirectory { dir =>
|
||||
withTemporaryDirectory { dir =>
|
||||
val lockFileA = new File(dir, "lockA")
|
||||
val lockFileB = new File(dir, "lockB")
|
||||
Locks(lockFileA, callLocked(lockFileB)) &&
|
||||
|
|
@ -33,7 +34,7 @@ object LocksTest extends Properties("Locks")
|
|||
}
|
||||
|
||||
property("Contested single lock") = spec {
|
||||
FileUtilities.withTemporaryDirectory { dir =>
|
||||
withTemporaryDirectory { dir =>
|
||||
val lockFile = new File(dir, "lock")
|
||||
forkFold(2000){i => Locks(lockFile, callTrue) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.util.Properties
|
|||
import xsbti._
|
||||
import org.specs._
|
||||
import LaunchTest._
|
||||
import sbt.IO.{createDirectory, touch,withTemporaryDirectory}
|
||||
|
||||
object ScalaProviderTest extends Specification
|
||||
{
|
||||
|
|
@ -34,7 +35,7 @@ object ScalaProviderTest extends Specification
|
|||
def checkLoad(arguments: List[String], mainClassName: String): MainResult =
|
||||
checkLoad(arguments, mainClassName, _ => Array[File]())
|
||||
def checkLoad(arguments: List[String], mainClassName: String, extra: File => Array[File]): MainResult =
|
||||
FileUtilities.withTemporaryDirectory { currentDirectory =>
|
||||
withTemporaryDirectory { currentDirectory =>
|
||||
withLauncher { launcher =>
|
||||
Launch.run(launcher)(
|
||||
new RunConfiguration(mapScalaVersion(LaunchTest.getScalaVersion), LaunchTest.testApp(mainClassName, extra(currentDirectory)).toID, currentDirectory, arguments)
|
||||
|
|
@ -45,8 +46,8 @@ object ScalaProviderTest extends Specification
|
|||
private def createExtra(currentDirectory: File) =
|
||||
{
|
||||
val resourceDirectory = new File(currentDirectory, "resources")
|
||||
FileUtilities.createDirectory(resourceDirectory)
|
||||
testResources.foreach(resource => FileUtilities.touch(new File(resourceDirectory, resource.replace('/', File.separatorChar))))
|
||||
createDirectory(resourceDirectory)
|
||||
testResources.foreach(resource => touch(new File(resourceDirectory, resource.replace('/', File.separatorChar))))
|
||||
Array(resourceDirectory)
|
||||
}
|
||||
private def checkScalaLoader(version: String): Unit = withLauncher( checkLauncher(version, scalaVersionMap(version)) )
|
||||
|
|
@ -67,7 +68,7 @@ object LaunchTest
|
|||
import Repository.Predefined._
|
||||
def testRepositories = List(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined.apply)
|
||||
def withLauncher[T](f: xsbti.Launcher => T): T =
|
||||
FileUtilities.withTemporaryDirectory { bootDirectory =>
|
||||
withTemporaryDirectory { bootDirectory =>
|
||||
f(Launcher(bootDirectory, testRepositories))
|
||||
}
|
||||
|
||||
|
|
|
|||
10
notes
10
notes
|
|
@ -1,3 +1,13 @@
|
|||
Issues moving Launcher to 2.8:
|
||||
creating an Array requires a Manifest, which brings in 40k of classes in scala.reflect
|
||||
scala.package$ is 3k (import scala.collection.immutable.List) and brings in scala.xml
|
||||
RichInt 2k. scala.collection.mutable.StringBuilder.ensureCapacity uses it (max), which is needed for string concat
|
||||
scala.xml brings in 50k of classes
|
||||
scala.math brought in 30k, can't remove because RichInt apparently uses it
|
||||
100k additional size adds 50ms to startup time (on my faster machine)
|
||||
difference between classpaths a) just launcher jar b) current directory + launcher jar is that b) is 50 ms slower than a)
|
||||
was able to return to old size by enabling optimize/obfuscate phases of ProGuard
|
||||
|
||||
- script tasks (in 'scripts' branch). To use:
|
||||
1) add implementation of jsr223 to project/build/lib, declare in project/plugins, or add to sbt startup classpath
|
||||
2) Mix sbt.scripts.Scripts into your project definition
|
||||
|
|
|
|||
|
|
@ -3,20 +3,27 @@ import java.io.File
|
|||
|
||||
trait ProguardLaunch extends ProguardProject
|
||||
{
|
||||
override def optimize = 2
|
||||
override def basicOptions = super.basicOptions ++ Seq(keepJLine)
|
||||
def outputJar = rootProject.outputPath / ("sbt-launch-" + version + ".jar")
|
||||
override def keepClasses =
|
||||
override def keepFullClasses =
|
||||
"xsbti.**" ::
|
||||
"jline.**" ::
|
||||
Nil
|
||||
override def keepClasses =
|
||||
"org.apache.ivy.plugins.resolver.URLResolver" ::
|
||||
"org.apache.ivy.plugins.resolver.IBiblioResolver" ::
|
||||
"xsbti.**" ::
|
||||
Nil
|
||||
|
||||
override def mapInJars(inJars: Seq[File]) =
|
||||
{
|
||||
val inputJar = jarPath.asFile.getAbsolutePath
|
||||
val jlineJars = runClasspath.getFiles.filter(isJLineJar)
|
||||
// pull out Ivy in order to exclude resources inside
|
||||
val (ivyJars, notIvy) = inJars.filter(jar => !isJLineJar(jar)).partition(isIvyJar)
|
||||
val otherJars = notIvy.filter(jar => !isJarX(jar, "scala-compiler"))
|
||||
val (libraryJar, remaining) = notIvy.partition(isScalaJar)
|
||||
|
||||
val otherJars = remaining.filter(jar => !isJarX(jar, "scala-compiler"))
|
||||
|
||||
log.debug("proguard configuration:")
|
||||
log.debug("\tJLline jar location: " + jlineJars.mkString(", "))
|
||||
|
|
@ -24,8 +31,9 @@ trait ProguardLaunch extends ProguardProject
|
|||
log.debug("\tOther jars:\n\t" + otherJars.mkString("\n\t"))
|
||||
val excludeIvyResourcesString = excludeString(excludeIvyResources)
|
||||
((withJar(ivyJars.toSeq, "Ivy") + excludeIvyResourcesString) ::
|
||||
(withJar(jlineJars, "JLine") + "(!META-INF/**)" ) ::
|
||||
otherJars.map(jar => mkpath(jar) + "(!META-INF/**,!*.properties)").toList) map { "-injars " + _ }
|
||||
(withJar(jlineJars, "JLine") + jlineFilter ) ::
|
||||
(withJar(libraryJar, "Scala library") + libraryFilter) ::
|
||||
otherJars.map(jar => mkpath(jar) + generalFilter).toList) map { "-injars " + _ }
|
||||
}
|
||||
|
||||
private def excludeString(s: List[String]) = s.map("!" + _).mkString("(",",",")")
|
||||
|
|
@ -41,9 +49,14 @@ trait ProguardLaunch extends ProguardProject
|
|||
"org/apache/ivy/plugins/report/ivy-report-*" ::
|
||||
Nil
|
||||
|
||||
private def libraryFilter = "(!META-INF/**,!*.properties,!scala/actors/**.!scala/util/parsing/*.class,!scala/xml/**.class,!scala/package$.class,**.class)"
|
||||
private def jlineFilter = "(!META-INF/**)"
|
||||
private def generalFilter = "(!META-INF/**,!*.properties)"
|
||||
|
||||
private def withJar[T](files: Iterable[File], name: String) = mkpath(files.toSeq.firstOption.getOrElse(error(name + " not present (try running update)")))
|
||||
private def isJLineJar(file: File) = isJarX(file, "jline")
|
||||
private def isIvyJar(file: File) = isJarX(file, "ivy")
|
||||
private def isScalaJar(file: File) = isJarX(file, "scala-library")
|
||||
private def isJarX(file: File, x: String) =
|
||||
{
|
||||
val name = file.getName
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ trait ProguardProject extends BasicScalaProject
|
|||
def rootProjectDirectory = rootProject.info.projectPath
|
||||
|
||||
val toolsConfig = config("tools") hide
|
||||
val proguardJar = "net.sf.proguard" % "proguard" % "4.3" % "tools"
|
||||
val proguardJar = "net.sf.proguard" % "proguard" % "4.4" % "tools"
|
||||
|
||||
lazy val proguard = proguardAction
|
||||
def proguardAction = proguardTask dependsOn(writeProguardConfiguration) describedAs(ProguardDescription)
|
||||
|
|
@ -27,12 +27,17 @@ trait ProguardProject extends BasicScalaProject
|
|||
|
||||
def basicOptions: Seq[String] =
|
||||
Seq(
|
||||
"-dontoptimize",
|
||||
"-dontobfuscate",
|
||||
"-keep,allowoptimization,allowshrinking class * { *; }",
|
||||
"-keepattributes SourceFile,LineNumberTable",
|
||||
"-dontnote",
|
||||
"-dontwarn",
|
||||
"-ignorewarnings")
|
||||
"-ignorewarnings") ++
|
||||
optimizeOptions
|
||||
|
||||
def keepFullClasses: Seq[String] = Nil
|
||||
def keepClasses: Seq[String] = Nil
|
||||
def optimize: Int = 0
|
||||
def optimizeOptions = if(optimize <= 0) Seq("-dontoptimize") else Seq( "-optimizationpasses 2", "-optimizations !code/allocation/variable")
|
||||
|
||||
def mapInJars(inJars: Seq[File]): Seq[String] = inJars.map(f => "-injars " + mkpath(f))
|
||||
def mapLibraryJars(libraryJars: Seq[File]): Seq[String] = libraryJars.map(f => "-libraryjars " + mkpath(f))
|
||||
|
|
@ -47,7 +52,8 @@ trait ProguardProject extends BasicScalaProject
|
|||
|
||||
val lines =
|
||||
options ++
|
||||
keepClasses.map("-keep public class " + _ + " {\n public * ;\n}") ++
|
||||
keepFullClasses.map("-keep public class " + _ + " {\n public protected * ;\n}") ++
|
||||
keepClasses.map("-keep class " + _ + " {}") ++
|
||||
mapInJars(inJars) ++
|
||||
Seq("-injars " + mkpath(rawJarPath.asFile),
|
||||
mapOutJar(outJar)) ++
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
|
|||
{
|
||||
override def scratch = true
|
||||
override def consoleClasspath = testClasspath
|
||||
override def compileOptions = super.compileOptions ++ compileOptions("-Xelide-below", "3000")
|
||||
override def compileOptions = super.compileOptions ++ compileOptions("-Xelide-below", "0")
|
||||
}
|
||||
trait Licensed extends BasicScalaProject
|
||||
{
|
||||
|
|
@ -128,7 +128,6 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
|
|||
{
|
||||
override def testCompileAction = super.testCompileAction dependsOn(compileInterfaceSub.`package`, interfaceSub.`package`)
|
||||
override def testClasspath = super.testClasspath +++ compileInterfaceSub.packageSrcJar +++ interfaceSub.jarPath --- compilerInterfaceClasspath --- interfaceSub.mainCompilePath
|
||||
override def compileOptions = super.compileOptions ++ Seq(CompileOption("-Xno-varargs-conversion")) //needed for invoking nsc.scala.tools.Main.process(Array[String])
|
||||
}
|
||||
class IvyProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestWithLog with TestWithLaunch
|
||||
{
|
||||
|
|
@ -240,4 +239,4 @@ class XSbt(info: ProjectInfo) extends ParentProject(info) with NoCrossPaths
|
|||
override def testCompileAction = super.testCompileAction dependsOn((testWithTestClasspath.map(_.testCompile) ++ testWithCompileClasspath.map(_.compile)) : _*)
|
||||
override def testClasspath = (super.testClasspath /: (testWithTestClasspath.map(_.testClasspath) ++ testWithCompileClasspath.map(_.compileClasspath) ))(_ +++ _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ object IO
|
|||
(name, "")
|
||||
}
|
||||
|
||||
def touch(files: Iterable[File]): Unit = files.foreach(touch)
|
||||
def touch(files: Traversable[File]): Unit = files.foreach(touch)
|
||||
/** Creates a file at the given location.*/
|
||||
def touch(file: File)
|
||||
{
|
||||
|
|
@ -79,7 +79,7 @@ object IO
|
|||
else if(!file.setLastModified(System.currentTimeMillis))
|
||||
error("Could not update last modified time for file " + file)
|
||||
}
|
||||
def createDirectories(dirs: Iterable[File]): Unit =
|
||||
def createDirectories(dirs: Traversable[File]): Unit =
|
||||
dirs.foreach(createDirectory)
|
||||
def createDirectory(dir: File): Unit =
|
||||
{
|
||||
|
|
@ -262,12 +262,12 @@ object IO
|
|||
* @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: Iterable[(File,String)], outputJar: File, manifest: Manifest): Unit =
|
||||
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: Iterable[(File,String)], outputZip: File): Unit =
|
||||
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])
|
||||
|
|
@ -360,7 +360,7 @@ object IO
|
|||
else
|
||||
None
|
||||
}
|
||||
def copy(sources: Iterable[(File,File)], overwrite: Boolean = false, preserveLastModified: Boolean = false): Set[File] =
|
||||
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 =
|
||||
{
|
||||
|
|
@ -469,7 +469,7 @@ object IO
|
|||
for( (file, index) <- files.zipWithIndex) yield
|
||||
(file, new File(dir, index.toHexString))
|
||||
|
||||
def move(files: Iterable[(File, File)]): Unit =
|
||||
def move(files: Traversable[(File, File)]): Unit =
|
||||
files.foreach(Function.tupled(move))
|
||||
|
||||
def move(a: File, b: File): Unit =
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ object Path extends Alternatives with Mapper
|
|||
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 filesToFinder(cc: Traversable[File]): PathFinder = finder(cc)
|
||||
implicit def pathsToFinder(cc: Traversable[Path]): PathFinder = lazyPathFinder(cc)
|
||||
|
||||
def fileProperty(name: String) = Path.fromFile(System.getProperty(name))
|
||||
def userHome = fileProperty("user.home")
|
||||
|
|
@ -161,12 +163,12 @@ object Path extends Alternatives with Mapper
|
|||
}
|
||||
/** A <code>PathFinder</code> that selects the paths provided by the <code>paths</code> argument, which is
|
||||
* reevaluated on each call to the <code>PathFinder</code>'s <code>get</code> method. */
|
||||
def lazyPathFinder(paths: => Iterable[Path]): PathFinder =
|
||||
def lazyPathFinder(paths: => Traversable[Path]): PathFinder =
|
||||
new PathFinder
|
||||
{
|
||||
private[sbt] def addTo(pathSet: mutable.Set[Path]) = pathSet ++= paths
|
||||
}
|
||||
def finder(files: => Iterable[File]): PathFinder = lazyPathFinder { fromFiles(files) }
|
||||
def finder(files: => Traversable[File]): PathFinder = lazyPathFinder { fromFiles(files) }
|
||||
|
||||
/** The separator character of the platform.*/
|
||||
val sep = java.io.File.separatorChar
|
||||
|
|
@ -244,7 +246,7 @@ object Path extends Alternatives with Mapper
|
|||
}
|
||||
def fromFile(file: String): Path = fromFile(new File(file))
|
||||
def fromFile(file: File): Path = new FilePath(file)
|
||||
def fromFiles(files: Iterable[File]): Iterable[Path] = files.map(fromFile)
|
||||
def fromFiles(files: Traversable[File]): Traversable[Path] = 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue