mirror of https://github.com/sbt/sbt.git
replace Path with RichFile
This commit is contained in:
parent
aa0824584c
commit
2343a55bb9
|
|
@ -220,17 +220,17 @@ object BuildPaths
|
|||
def defaultStaging = Path.userHome / ConfigDirectoryName / "staging"
|
||||
def defaultGlobalPlugins = Path.userHome / ConfigDirectoryName / PluginsDirectoryName
|
||||
|
||||
def definitionSources(base: File): Seq[File] = (base * "*.scala").getFiles
|
||||
def configurationSources(base: File): Seq[File] = (base * "*.sbt").getFiles
|
||||
def pluginDirectory(definitionBase: Path) = definitionBase / PluginsDirectoryName
|
||||
def definitionSources(base: File): Seq[File] = (base * "*.scala").get
|
||||
def configurationSources(base: File): Seq[File] = (base * "*.sbt").get
|
||||
def pluginDirectory(definitionBase: File) = definitionBase / PluginsDirectoryName
|
||||
|
||||
def evalOutputDirectory(base: Path) = outputDirectory(base) / "config-classes"
|
||||
def outputDirectory(base: Path) = base / DefaultTargetName
|
||||
def buildOutputDirectory(base: Path, compilers: Compilers) = crossPath(outputDirectory(base), compilers.scalac.scalaInstance)
|
||||
def evalOutputDirectory(base: File) = outputDirectory(base) / "config-classes"
|
||||
def outputDirectory(base: File) = base / DefaultTargetName
|
||||
def buildOutputDirectory(base: File, compilers: Compilers) = crossPath(outputDirectory(base), compilers.scalac.scalaInstance)
|
||||
|
||||
def projectStandard(base: Path) = base / "project"
|
||||
def projectHidden(base: Path) = base / ConfigDirectoryName
|
||||
def selectProjectDir(base: Path) =
|
||||
def projectStandard(base: File) = base / "project"
|
||||
def projectHidden(base: File) = base / ConfigDirectoryName
|
||||
def selectProjectDir(base: File) =
|
||||
{
|
||||
val a = projectHidden(base)
|
||||
val b = projectStandard(base)
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ object Defaults extends BuildCommon
|
|||
)
|
||||
def addBaseSources = Seq(
|
||||
unmanagedSources <<= (unmanagedSources, baseDirectory, sourceFilter, defaultExcludes in unmanagedSources) map {
|
||||
(srcs,b,f,excl) => (srcs +++ b * (f -- excl)).getFiles
|
||||
(srcs,b,f,excl) => (srcs +++ b * (f -- excl)).get
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ object Defaults extends BuildCommon
|
|||
}
|
||||
}
|
||||
def unmanagedResourcesTask(dirs: Seq[File], excl: FileFilter) =
|
||||
dirs.descendentsExcept("*",excl).getFiles
|
||||
dirs.descendentsExcept("*",excl).get
|
||||
|
||||
lazy val testTasks = testTaskOptions(test) ++ testTaskOptions(testOnly) ++ Seq(
|
||||
testLoader <<= (fullClasspath, scalaInstance) map { (cp, si) => TestFramework.createTestLoader(data(cp), si) },
|
||||
|
|
@ -294,7 +294,7 @@ object Defaults extends BuildCommon
|
|||
}
|
||||
|
||||
def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] =
|
||||
(dirs, filter, excludes) map { (d,f,excl) => d.descendentsExcept(f,excl).getFiles }
|
||||
(dirs, filter, excludes) map { (d,f,excl) => d.descendentsExcept(f,excl).get }
|
||||
|
||||
def artifactPathSetting(art: ScopedSetting[Artifact]) = (crossTarget, projectID, art, scalaVersion, artifactName) { (t, module, a, sv, toString) => t / toString(sv, module, a) asFile }
|
||||
|
||||
|
|
@ -500,7 +500,7 @@ object Classpaths
|
|||
classpathConfiguration <<= (internalConfigurationMap, configuration)( _ apply _ ),
|
||||
managedClasspath <<= (classpathConfiguration, classpathTypes, update) map managedJars,
|
||||
unmanagedJars <<= (configuration, unmanagedBase, classpathFilter, defaultExcludes in unmanagedJars) map { (config, base, filter, excl) =>
|
||||
(base * (filter -- excl) +++ (base / config.name).descendentsExcept(filter, excl)).getFiles
|
||||
(base * (filter -- excl) +++ (base / config.name).descendentsExcept(filter, excl)).get
|
||||
}
|
||||
)
|
||||
def defaultPackageKeys = Seq(packageBin, packageSrc, packageDoc)
|
||||
|
|
@ -665,7 +665,7 @@ object Classpaths
|
|||
def publishConfig(artifacts: Map[Artifact, File], ivyFile: Option[File], resolverName: String = "local", logging: UpdateLogging.Value = UpdateLogging.DownloadOnly) =
|
||||
new PublishConfiguration(ivyFile, resolverName, artifacts, logging)
|
||||
|
||||
def deliverPattern(outputPath: Path): String = (outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
|
||||
def deliverPattern(outputPath: File): String = (outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
|
||||
|
||||
def projectDependenciesTask =
|
||||
(thisProject, settings) map { (p, data) =>
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ object Scoped
|
|||
def **(filter: FileFilter): Initialize[Seq[File]] = map0 { _ ** filter }
|
||||
protected[this] def map0(f: PathFinder => PathFinder): Initialize[Seq[File]]
|
||||
protected[this] def finder(f: PathFinder => PathFinder): Seq[File] => Seq[File] =
|
||||
in => f(in).getFiles
|
||||
in => f(in).get
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ object Watched
|
|||
def executeContinuously(watched: Watched, s: State, next: String, repeat: String): State =
|
||||
{
|
||||
@tailrec def shouldTerminate: Boolean = (System.in.available > 0) && (watched.terminateWatch(System.in.read()) || shouldTerminate)
|
||||
val sourcesFinder = Path.finder { watched watchPaths s }
|
||||
val sourcesFinder = PathFinder { watched watchPaths s }
|
||||
val watchState = s get ContinuousState getOrElse WatchState.empty
|
||||
|
||||
if(watchState.count > 0)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,6 @@ final class Scaladoc(maximumErrors: Int, compiler: AnalyzingCompiler)
|
|||
}
|
||||
}
|
||||
|
||||
cachedDoc(inputs)(() => exists(outputDirectory.***.get))
|
||||
cachedDoc(inputs)(() => exists(outputDirectory.***.get.toSet))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler
|
|||
def scriptError(message: String): Some[String] = error("Test script error: " + message)
|
||||
def spaced[T](l: Seq[T]) = l.mkString(" ")
|
||||
def fromStrings(paths: List[String]) = paths.map(fromString)
|
||||
def fromString(path: String) = Path.fromString(baseDirectory, path)
|
||||
def fromString(path: String) = new File(baseDirectory, path)
|
||||
def touch(paths: List[String]) = IO.touch(fromStrings(paths))
|
||||
def delete(paths: List[String]): Unit = IO.delete(fromStrings(paths))
|
||||
/*def sync(from: String, to: String) =
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ object ScriptedPlugin extends Plugin {
|
|||
sbtLauncher <<= (appConfiguration)(app => IO.classLocationFile(app.provider.scalaProvider.launcher.getClass)),
|
||||
sbtTestDirectory <<= sourceDirectory / "sbt-test",
|
||||
scriptedBufferLog := true,
|
||||
scriptedClasspath <<= (classpathTypes, update) map { (ct, report) => Path.finder(Classpaths.managedJars(scriptedConf, ct, report).map(_.data)) },
|
||||
scriptedClasspath <<= (classpathTypes, update) map { (ct, report) => PathFinder(Classpaths.managedJars(scriptedConf, ct, report).map(_.data)) },
|
||||
scriptedTests <<= scriptedTestsTask,
|
||||
scriptedRun <<= scriptedRunTask,
|
||||
scriptedDependencies <<= (compile in Test, publishLocal) map { (analysis, pub) => Unit },
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ import java.lang.reflect.Modifier.{STATIC, PUBLIC, ABSTRACT}
|
|||
|
||||
private[sbt] object Analyze
|
||||
{
|
||||
def apply[T](outputDirectory: Path, sources: Seq[File], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File,Seq[Class[_]]) => Unit)(compile: => Unit)
|
||||
def apply[T](outputDirectory: File, sources: Seq[File], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File,Seq[Class[_]]) => Unit)(compile: => Unit)
|
||||
{
|
||||
val sourceMap = sources.groupBy(_.getName)
|
||||
val classesFinder = outputDirectory ** GlobFilter("*.class")
|
||||
val classesFinder = PathFinder(outputDirectory) ** "*.class"
|
||||
val existingClasses = classesFinder.get
|
||||
|
||||
def load(tpe: String, errMsg: => Option[String]): Option[Class[_]] =
|
||||
|
|
@ -26,23 +26,22 @@ private[sbt] object Analyze
|
|||
// runs after compilation
|
||||
def analyze()
|
||||
{
|
||||
val allClasses = Set(classesFinder.get.toSeq : _*)
|
||||
val allClasses = Set(classesFinder.get: _*)
|
||||
val newClasses = allClasses -- existingClasses
|
||||
|
||||
val productToSource = new mutable.HashMap[Path, Path]
|
||||
val sourceToClassFiles = new mutable.HashMap[Path, Buffer[ClassFile]]
|
||||
val productToSource = new mutable.HashMap[File, File]
|
||||
val sourceToClassFiles = new mutable.HashMap[File, Buffer[ClassFile]]
|
||||
|
||||
// parse class files and assign classes to sources. This must be done before dependencies, since the information comes
|
||||
// as class->class dependencies that must be mapped back to source->class dependencies using the source+class assignment
|
||||
for(newClass <- newClasses;
|
||||
path <- Path.relativize(outputDirectory, newClass);
|
||||
classFile = Parser(newClass.asFile);
|
||||
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.asFile.getName);
|
||||
classFile = Parser(newClass);
|
||||
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.getName);
|
||||
source <- guessSourcePath(sourceMap, classFile, log))
|
||||
{
|
||||
analysis.beginSource(source)
|
||||
analysis.generatedClass(source, path)
|
||||
productToSource(path) = source
|
||||
analysis.generatedClass(source, newClass)
|
||||
productToSource(newClass) = source
|
||||
sourceToClassFiles.getOrElseUpdate(source, new ArrayBuffer[ClassFile]) += classFile
|
||||
}
|
||||
|
||||
|
|
@ -61,10 +60,9 @@ private[sbt] object Analyze
|
|||
{
|
||||
val resolved = resolveClassFile(file, tpe)
|
||||
assume(resolved.exists, "Resolved class file " + resolved + " from " + source + " did not exist")
|
||||
val resolvedPath = Path.fromFile(resolved)
|
||||
if(Path.fromFile(file) == outputDirectory)
|
||||
if(file == outputDirectory)
|
||||
{
|
||||
productToSource.get(resolvedPath) match
|
||||
productToSource.get(resolved) match
|
||||
{
|
||||
case Some(dependsOn) => analysis.sourceDependency(dependsOn, source)
|
||||
case None => analysis.binaryDependency(resolved, clazz.getName, source)
|
||||
|
|
@ -80,7 +78,7 @@ private[sbt] object Analyze
|
|||
}
|
||||
|
||||
classFiles.flatMap(_.types).foreach(processDependency)
|
||||
readAPI(source asFile, classFiles.toSeq.flatMap(c => load(c.className, Some("Error reading API from class file") )))
|
||||
readAPI(source, classFiles.toSeq.flatMap(c => load(c.className, Some("Error reading API from class file") )))
|
||||
analysis.endSource(source)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,17 +54,15 @@ object ClasspathUtilities
|
|||
private[sbt] def printSource(c: Class[_]) =
|
||||
println(c.getName + " loader=" +c.getClassLoader + " location=" + IO.classLocationFile(c))
|
||||
|
||||
def isArchive(path: Path): Boolean = isArchive(path.asFile)
|
||||
def isArchive(file: File): Boolean = isArchiveName(file.getName)
|
||||
def isArchiveName(fileName: String) = fileName.endsWith(".jar") || fileName.endsWith(".zip")
|
||||
// Partitions the given classpath into (jars, directories)
|
||||
private[sbt] def separate(paths: Iterable[File]): (Iterable[File], Iterable[File]) = paths.partition(isArchive)
|
||||
// Partitions the given classpath into (jars, directories)
|
||||
private[sbt] def separatePaths(paths: Iterable[Path]) = separate(paths.map(_.asFile.getCanonicalFile))
|
||||
private[sbt] def buildSearchPaths(classpath: Iterable[Path]): (collection.Set[File], collection.Set[File]) =
|
||||
private[sbt] def buildSearchPaths(classpath: Iterable[File]): (collection.Set[File], collection.Set[File]) =
|
||||
{
|
||||
val (jars, dirs) = separatePaths(classpath)
|
||||
(linkedSet(jars ++ extraJars.toList), linkedSet(dirs ++ extraDirs.toList))
|
||||
val (jars, dirs) = separate(classpath)
|
||||
(linkedSet(jars ++ extraJars), linkedSet(dirs ++ extraDirs))
|
||||
}
|
||||
private[sbt] def onClasspath(classpathJars: collection.Set[File], classpathDirectories: collection.Set[File], file: File): Boolean =
|
||||
{
|
||||
|
|
@ -76,10 +74,10 @@ object ClasspathUtilities
|
|||
}
|
||||
|
||||
/** Returns all entries in 'classpath' that correspond to a compiler plugin.*/
|
||||
private[sbt] def compilerPlugins(classpath: Iterable[Path]): Iterable[File] =
|
||||
private[sbt] def compilerPlugins(classpath: Seq[File]): Iterable[File] =
|
||||
{
|
||||
import collection.JavaConversions._
|
||||
val loader = new URLClassLoader(Path.getURLs(classpath))
|
||||
val loader = new URLClassLoader(Path.toURLs(classpath))
|
||||
loader.getResources("scalac-plugin.xml").toList.flatMap(asFile(true))
|
||||
}
|
||||
/** Converts the given URL to a File. If the URL is for an entry in a jar, the File for the jar is returned. */
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ abstract class GeneratorBase(val basePkgName: String, val baseDirectory: File) e
|
|||
|
||||
def writeSource(name: String, pkgName: String, content: String)
|
||||
{
|
||||
import Path._
|
||||
val file = Path.fromString(baseDirectory, packagePath(pkgName)) / (name+ ".java")
|
||||
val file = new File(new File(baseDirectory, packagePath(pkgName)), name+ ".java")
|
||||
file.getParentFile.mkdirs()
|
||||
write(file, "package " + pkgName + ";\n\n" + content)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,18 @@
|
|||
package sbt
|
||||
|
||||
import scala.reflect.Manifest
|
||||
|
||||
import java.io.File
|
||||
import scala.collection.Map
|
||||
|
||||
trait BasicEnvironment extends Environment
|
||||
{
|
||||
protected def log: Logger
|
||||
/** The location of the properties file that backs the user-defined properties. */
|
||||
def envBackingPath: Path
|
||||
def envBackingPath: File
|
||||
/** The environment from which user-defined properties inherit (if enabled). */
|
||||
protected def parentEnvironment: Option[BasicEnvironment] = None
|
||||
/** The identifier used in messages to refer to this environment. */
|
||||
def environmentLabel = envBackingPath.absolutePath
|
||||
def environmentLabel = envBackingPath.getAbsolutePath
|
||||
|
||||
private[this] var isModified = false
|
||||
private[sbt] def setEnvironmentModified(modified: Boolean) { synchronized { isModified = modified } }
|
||||
|
|
|
|||
|
|
@ -17,11 +17,6 @@ abstract class SimpleFormat[T] extends Format[T]
|
|||
}
|
||||
object Format
|
||||
{
|
||||
def path(basePath: Path): Format[Path] = new Format[Path]
|
||||
{
|
||||
def toString(path: Path) = Path.relativize(basePath.asFile, path.asFile).getOrElse(error("Path " + path + " not in " + basePath))
|
||||
def fromString(s: String) = Path.fromString(basePath, s)
|
||||
}
|
||||
implicit val file: Format[File] = new Format[File]
|
||||
{
|
||||
def toString(file: File) = file.getAbsolutePath
|
||||
|
|
|
|||
|
|
@ -308,7 +308,6 @@ object IO
|
|||
}
|
||||
private def writeZip(sources: Seq[(File,String)], output: ZipOutputStream)(createEntry: String => ZipEntry)
|
||||
{
|
||||
import Path.{lazyPathFinder => pf}
|
||||
val files = sources.flatMap { case (file,name) => if (file.isFile) (file, normalizeName(name)) :: Nil else Nil }
|
||||
|
||||
val now = System.currentTimeMillis
|
||||
|
|
@ -443,7 +442,7 @@ object IO
|
|||
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)
|
||||
copy( (PathFinder(source) ***) x Path.rebase(source, target), overwrite, preserveLastModified)
|
||||
|
||||
def copyFile(sourceFile: File, targetFile: File, preserveLastModified: Boolean = false)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,9 +62,13 @@ object NameFilter
|
|||
def accept(name: String) = f(name)
|
||||
}
|
||||
}
|
||||
object FileFilter
|
||||
{
|
||||
implicit def globFilter(s: String): NameFilter = GlobFilter(s)
|
||||
}
|
||||
object GlobFilter
|
||||
{
|
||||
implicit def apply(expression: String): NameFilter =
|
||||
def apply(expression: String): NameFilter =
|
||||
{
|
||||
require(!expression.exists(java.lang.Character.isISOControl), "Control characters not allowed in filter expression.")
|
||||
if(expression == "*")
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ object SignJar
|
|||
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 signedJar(p: File) = new SignOption("-signedjar" :: p.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)
|
||||
|
|
|
|||
|
|
@ -7,54 +7,26 @@ import Path._
|
|||
import IO.{pathSplit, wrapNull}
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import scala.collection.{generic, immutable, mutable, TraversableLike}
|
||||
import scala.collection.{generic, immutable, mutable}
|
||||
|
||||
/** A Path represents a file in a project.
|
||||
* @see sbt.PathFinder*/
|
||||
sealed abstract class Path extends PathFinder
|
||||
final class RichFile(val asFile: File)
|
||||
{
|
||||
/** 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 / (component: String): File = if(component == ".") asFile else new File(asFile, component)
|
||||
/** True if and only if the wrapped file exists.*/
|
||||
def exists = asFile.exists
|
||||
/** True if and only if the file represented by this path is a directory.*/
|
||||
/** True if and only if the wrapped file is a directory.*/
|
||||
def isDirectory = asFile.isDirectory
|
||||
/** The last modified time of the file represented by this path.*/
|
||||
/** The last modified time of the wrapped file.*/
|
||||
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>.*/
|
||||
/* True if and only if the wrapped file `asFile` exists and the file 'other'
|
||||
* does not exist or was modified before the `asFile`.*/
|
||||
def newerThan(other: File): Boolean = Path.newerThan(asFile, other)
|
||||
/* True if and only if the wrapped file `asFile` does not exist or the file `other`
|
||||
* exists and was modified after `asFile`.*/
|
||||
def olderThan(other: File): Boolean = Path.newerThan(other, asFile)
|
||||
/** The wrapped file 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
|
||||
|
|
@ -68,166 +40,40 @@ sealed abstract class Path extends PathFinder
|
|||
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
|
||||
}
|
||||
|
||||
def relativize(sub: File): Option[File] = Path.relativizeFile(asFile, sub)
|
||||
def relativeTo(base: File): Option[File] = Path.relativizeFile(base, asFile)
|
||||
|
||||
def hash: Array[Byte] = Hash(asFile)
|
||||
def hashString: String = Hash.toHex(hash)
|
||||
def hashStringHalf: String = Hash.halve(hashString)
|
||||
}
|
||||
import java.io.File
|
||||
import File.pathSeparator
|
||||
trait PathExtra extends Alternatives with Mapper
|
||||
trait PathLow
|
||||
{
|
||||
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)
|
||||
implicit def singleFileFinder(file: File): PathFinder = PathFinder(file)
|
||||
}
|
||||
object Path extends PathExtra
|
||||
trait PathExtra extends Alternatives with Mapper with PathLow
|
||||
{
|
||||
def fileProperty(name: String) = Path.fromFile(System.getProperty(name))
|
||||
implicit def richFile(file: File): RichFile = new RichFile(file)
|
||||
implicit def filesToFinder(cc: Traversable[File]): PathFinder = PathFinder.strict(cc)
|
||||
}
|
||||
object Path extends PathExtra
|
||||
{
|
||||
def apply(f: File): RichFile = new RichFile(f)
|
||||
def apply(f: String): RichFile = new RichFile(new File(f))
|
||||
def fileProperty(name: String) = Path(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)
|
||||
def newerThan(a: File, b: File): Boolean = a.exists && (!b.exists || a.lastModified > b.lastModified)
|
||||
|
||||
/** 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]) = paths.foreach(_.addTo(pathSet))
|
||||
}
|
||||
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] =
|
||||
{
|
||||
|
|
@ -243,9 +89,7 @@ object Path extends PathExtra
|
|||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
@ -257,27 +101,29 @@ object Path extends PathExtra
|
|||
}
|
||||
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
|
||||
}
|
||||
object PathFinder
|
||||
{
|
||||
/** A <code>PathFinder</code> that always produces the empty set of <code>Path</code>s.*/
|
||||
val empty = new PathFinder { private[sbt] def addTo(fileSet: mutable.Set[File]) {} }
|
||||
def strict(files: Traversable[File]): PathFinder = apply(files)
|
||||
def apply(files: => Traversable[File]): PathFinder = new PathFinder {
|
||||
private[sbt] def addTo(fileSet: mutable.Set[File]) = fileSet ++= files
|
||||
}
|
||||
def apply(file: File): PathFinder = new SingleFile(file)
|
||||
}
|
||||
|
||||
/** 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
|
||||
sealed abstract class PathFinder
|
||||
{
|
||||
/** 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)
|
||||
def ---(excludePaths: PathFinder): PathFinder = new ExcludeFiles(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)
|
||||
|
|
@ -292,11 +138,6 @@ sealed abstract class PathFinder extends NotNull
|
|||
* 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_: 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.
|
||||
|
|
@ -304,10 +145,8 @@ sealed abstract class PathFinder extends NotNull
|
|||
def x[T](mapper: File => Option[T], errorIfNone: Boolean = true): Seq[(File,T)] =
|
||||
{
|
||||
val apply = if(errorIfNone) mapper | fail else mapper
|
||||
for(file <- getFiles; mapped <- apply(file)) yield (file, mapped)
|
||||
for(file <- get; 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:
|
||||
|
|
@ -316,108 +155,89 @@ sealed abstract class PathFinder extends NotNull
|
|||
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
|
||||
/** Evaluates this finder and converts the results to a `Seq` of distinct `File`s. The files 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
|
||||
}
|
||||
/** Evaluates this finder and converts the results to a `Seq` of `File`s.*/
|
||||
final def getFiles: Seq[File] =
|
||||
final def get: Seq[File] =
|
||||
{
|
||||
import collection.JavaConversions._
|
||||
val pathSet: mutable.Set[Path] = new java.util.LinkedHashSet[Path]
|
||||
val pathSet: mutable.Set[File] = new java.util.LinkedHashSet[File]
|
||||
addTo(pathSet)
|
||||
pathSet.map(_.asFile).toSeq
|
||||
pathSet.toSeq
|
||||
}
|
||||
@deprecated("Use `get`"/*, "0.9.7"*/) def getFiles: Seq[File] = get
|
||||
/** 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))
|
||||
final def filter(f: File => Boolean): PathFinder = PathFinder(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))
|
||||
final def flatMap(f: File => PathFinder): PathFinder = PathFinder(get.flatMap(p => f(p).get))
|
||||
/** Evaluates this finder and converts the results to an `Array` of `URL`s..*/
|
||||
final def getURLs: Array[URL] = getFiles.toArray.map(_.toURI.toURL)
|
||||
/** 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])
|
||||
final def getURLs: Array[URL] = get.toArray.map(_.toURI.toURL)
|
||||
/** Evaluates this finder and converts the results to a distinct sequence of absolute path strings.*/
|
||||
final def getPaths: Seq[String] = get.map(_.absolutePath)
|
||||
private[sbt] def addTo(fileSet: mutable.Set[File])
|
||||
|
||||
/** 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 )
|
||||
def distinct: PathFinder = PathFinder { get.map(p => (p.asFile.getName, p)).toMap.values }
|
||||
|
||||
/** 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 class SingleFile(asFile: File) extends PathFinder
|
||||
{
|
||||
private[sbt] def addTo(pathSet: mutable.Set[Path])
|
||||
{
|
||||
for(path <- base.get)
|
||||
pathSet += (path ###)
|
||||
}
|
||||
private[sbt] def addTo(fileSet: mutable.Set[File]): Unit = if(asFile.exists) fileSet += asFile
|
||||
}
|
||||
private abstract class FilterPath extends PathFinder with FileFilter
|
||||
private abstract class FilterFiles 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
|
||||
}
|
||||
protected def handleFile(file: File, fileSet: mutable.Set[File]): Unit =
|
||||
for(matchedFile <- wrapNull(file.listFiles(this)))
|
||||
fileSet += new File(file, matchedFile.getName)
|
||||
}
|
||||
private class DescendentOrSelfPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterPath
|
||||
private class DescendentOrSelfPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterFiles
|
||||
{
|
||||
private[sbt] def addTo(pathSet: mutable.Set[Path])
|
||||
private[sbt] def addTo(fileSet: mutable.Set[File])
|
||||
{
|
||||
for(path <- parent.get)
|
||||
for(file <- parent.get)
|
||||
{
|
||||
if(accept(path.asFile))
|
||||
pathSet += path
|
||||
handlePathDescendent(path, pathSet)
|
||||
if(accept(file))
|
||||
fileSet += file
|
||||
handleFileDescendent(file, fileSet)
|
||||
}
|
||||
}
|
||||
private def handlePathDescendent(path: Path, pathSet: mutable.Set[Path])
|
||||
private def handleFileDescendent(file: File, fileSet: mutable.Set[File])
|
||||
{
|
||||
handlePath(path, pathSet)
|
||||
for(childDirectory <- wrapNull(path.asFile.listFiles(DirectoryFilter)))
|
||||
handlePathDescendent(path / childDirectory.getName, pathSet)
|
||||
handleFile(file, fileSet)
|
||||
for(childDirectory <- wrapNull(file listFiles DirectoryFilter))
|
||||
handleFileDescendent(new File(file, childDirectory.getName), fileSet)
|
||||
}
|
||||
}
|
||||
private class ChildPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterPath
|
||||
private class ChildPathFinder(val parent: PathFinder, val filter: FileFilter) extends FilterFiles
|
||||
{
|
||||
private[sbt] def addTo(pathSet: mutable.Set[Path])
|
||||
{
|
||||
for(path <- parent.get)
|
||||
handlePath(path, pathSet)
|
||||
}
|
||||
private[sbt] def addTo(fileSet: mutable.Set[File]): Unit =
|
||||
for(file <- parent.get)
|
||||
handleFile(file, fileSet)
|
||||
}
|
||||
private class Paths(a: PathFinder, b: PathFinder) extends PathFinder
|
||||
{
|
||||
private[sbt] def addTo(pathSet: mutable.Set[Path])
|
||||
private[sbt] def addTo(fileSet: mutable.Set[File])
|
||||
{
|
||||
a.addTo(pathSet)
|
||||
b.addTo(pathSet)
|
||||
a.addTo(fileSet)
|
||||
b.addTo(fileSet)
|
||||
}
|
||||
}
|
||||
private class ExcludePaths(include: PathFinder, exclude: PathFinder) extends PathFinder
|
||||
private class ExcludeFiles(include: PathFinder, exclude: PathFinder) extends PathFinder
|
||||
{
|
||||
private[sbt] def addTo(pathSet: mutable.Set[Path])
|
||||
private[sbt] def addTo(pathSet: mutable.Set[File])
|
||||
{
|
||||
val includeSet = new mutable.HashSet[Path]
|
||||
val includeSet = new mutable.LinkedHashSet[File]
|
||||
include.addTo(includeSet)
|
||||
|
||||
val excludeSet = new mutable.HashSet[Path]
|
||||
val excludeSet = new mutable.HashSet[File]
|
||||
exclude.addTo(excludeSet)
|
||||
|
||||
includeSet --= excludeSet
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ object SourceModificationWatch
|
|||
{
|
||||
import state._
|
||||
|
||||
def sourceFiles: Iterable[java.io.File] = sourcesFinder.getFiles
|
||||
def sourceFiles: Iterable[java.io.File] = sourcesFinder.get
|
||||
val (lastModifiedTime, fileCount) =
|
||||
( (0L, 0) /: sourceFiles) {(acc, file) => (math.max(acc._1, file.lastModified), acc._2 + 1)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue