mirror of https://github.com/sbt/sbt.git
Add Path.allSubpaths and API documentation for mappers
This commit is contained in:
parent
f092fb35c9
commit
f55d34f617
|
|
@ -364,10 +364,8 @@ object Defaults extends BuildCommon
|
|||
packageTasks(packageSrc, packageSrcTask) ++
|
||||
packageTasks(packageDoc, packageDocTask)
|
||||
|
||||
private[this] val allSubpaths = (dir: File) => (dir.*** --- dir) x (relativeTo(dir)|flat)
|
||||
|
||||
def packageBinTask = products map { ps => ps flatMap { p => allSubpaths(p) } }
|
||||
def packageDocTask = doc map allSubpaths
|
||||
def packageBinTask = products map { _ flatMap Path.allSubpaths }
|
||||
def packageDocTask = doc map { p => Path.allSubpaths(p).toSeq }
|
||||
def packageSrcTask = concatMappings(resourceMappings, sourceMappings)
|
||||
|
||||
private type Mappings = Initialize[Task[Seq[(File, String)]]]
|
||||
|
|
@ -375,12 +373,12 @@ object Defaults extends BuildCommon
|
|||
|
||||
// drop base directories, since there are no valid mappings for these
|
||||
def sourceMappings = (unmanagedSources, unmanagedSourceDirectories, baseDirectory) map { (srcs, sdirs, base) =>
|
||||
( (srcs --- sdirs --- base) x (relativeTo(sdirs)|relativeTo(base)|flat)) toSeq
|
||||
( (srcs --- sdirs --- base) pair (relativeTo(sdirs)|relativeTo(base)|flat)) toSeq
|
||||
}
|
||||
def resourceMappings = relativeMappings(unmanagedResources, unmanagedResourceDirectories)
|
||||
def relativeMappings(files: ScopedTaskable[Seq[File]], dirs: ScopedTaskable[Seq[File]]): Initialize[Task[Seq[(File, String)]]] =
|
||||
(files, dirs) map { (rs, rdirs) =>
|
||||
(rs --- rdirs) x (relativeTo(rdirs)|flat) toSeq
|
||||
(rs --- rdirs) pair (relativeTo(rdirs)|flat) toSeq
|
||||
}
|
||||
|
||||
def collectFiles(dirs: ScopedTaskable[Seq[File]], filter: ScopedTaskable[FileFilter], excludes: ScopedTaskable[FileFilter]): Initialize[Task[Seq[File]]] =
|
||||
|
|
@ -548,7 +546,7 @@ object Defaults extends BuildCommon
|
|||
def copyResourcesTask =
|
||||
(classDirectory, cacheDirectory, resources, resourceDirectories, streams) map { (target, cache, resrcs, dirs, s) =>
|
||||
val cacheFile = cache / "copy-resources"
|
||||
val mappings = (resrcs --- dirs) x (rebase(dirs, target) | flat(target))
|
||||
val mappings = (resrcs --- dirs) pair (rebase(dirs, target) | flat(target))
|
||||
s.log.debug("Copy resource mappings: " + mappings.mkString("\n\t","\n\t",""))
|
||||
Sync(cacheFile)( mappings )
|
||||
mappings
|
||||
|
|
|
|||
|
|
@ -139,6 +139,13 @@ sealed abstract class PathFinder
|
|||
final def \ (literal: String): PathFinder = this / literal
|
||||
|
||||
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.
|
||||
* If `errorIfNone` is false, the path is dropped from the returned Traversable.*/
|
||||
def pair[T](mapper: File => Option[T], errorIfNone: Boolean = true): Seq[(File,T)] =
|
||||
x(mapper, errorIfNone)
|
||||
|
||||
/** 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.*/
|
||||
|
|
@ -154,7 +161,7 @@ sealed abstract class PathFinder
|
|||
* <code>descendantsExcept("*.jar", ".svn")</code>*/
|
||||
def descendantsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
|
||||
(this ** include) --- (this ** intermediateExclude ** include)
|
||||
@deprecated("Use `descendantsExcept` instead.", "0.11.3")
|
||||
@deprecated("Use `descendantsExcept` instead.", "0.12.0")
|
||||
def descendentsExcept(include: FileFilter, intermediateExclude: FileFilter): PathFinder =
|
||||
descendantsExcept(include, intermediateExclude)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,35 +10,62 @@ trait Mapper
|
|||
type PathMap = File => Option[String]
|
||||
type FileMap = File => Option[File]
|
||||
|
||||
/** A path mapper that pairs a File with the path returned by calling `getPath` on it.*/
|
||||
val basic: PathMap = f => Some(f.getPath)
|
||||
|
||||
/** A path mapper that pairs a File with its path relative to `base`.
|
||||
* If the File is not a descendant of `base`, it is not handled (None is returned by the mapper). */
|
||||
def relativeTo(base: File): PathMap = IO.relativize(base, _)
|
||||
|
||||
def relativeTo(bases: Iterable[File], zero: PathMap = transparent): PathMap = fold(zero, bases)(relativeTo)
|
||||
|
||||
def rebase(oldBase: File, newBase0: String): PathMap =
|
||||
/** A path mapper that pairs a descendent of `oldBase` with `newBase` prepended to the path relative to `oldBase`.
|
||||
* For example, if `oldBase = /old/x/` and `newBase = new/a/`, then `/old/x/y/z.txt` gets paired with `new/a/y/z.txt`. */
|
||||
def rebase(oldBase: File, newBase: String): PathMap =
|
||||
{
|
||||
val newBase = normalizeBase(newBase0)
|
||||
val normNewBase = normalizeBase(newBase)
|
||||
(file: File) =>
|
||||
if(file == oldBase)
|
||||
Some( if(newBase.isEmpty) "." else newBase )
|
||||
Some( if(normNewBase.isEmpty) "." else normNewBase )
|
||||
else
|
||||
IO.relativize(oldBase, file).map(newBase + _)
|
||||
IO.relativize(oldBase, file).map(normNewBase + _)
|
||||
}
|
||||
/** A mapper that throws an exception for any input. This is useful as the last mapper in a pipeline to ensure every input gets mapped.*/
|
||||
def fail: Any => Nothing = f => error("No mapping for " + f)
|
||||
|
||||
/** A path mapper that pairs a File with its name. For example, `/x/y/z.txt` gets paired with `z.txt`.*/
|
||||
val flat: PathMap = f => Some(f.getName)
|
||||
def flatRebase(newBase0: String): PathMap =
|
||||
|
||||
/** A path mapper that pairs a File with a path constructed from `newBase` and the file's name.
|
||||
* For example, if `newBase = /new/a/`, then `/old/x/z.txt` gets paired with `/new/a/z.txt`. */
|
||||
def flatRebase(newBase: String): PathMap =
|
||||
{
|
||||
val newBase = normalizeBase(newBase0)
|
||||
f => Some(newBase + f.getName)
|
||||
val newBase0 = normalizeBase(newBase)
|
||||
f => Some(newBase0 + f.getName)
|
||||
}
|
||||
|
||||
/** A mapper that is defined on all inputs by the function `f`.*/
|
||||
def total[A,B](f: A => B): A => Some[B] = x => Some(f(x))
|
||||
|
||||
/** A mapper that ignores all inputs.*/
|
||||
def transparent: Any => Option[Nothing] = _ => None
|
||||
|
||||
def normalizeBase(base: String) = if(!base.isEmpty && !base.endsWith("/")) base + "/" else base
|
||||
|
||||
/** Pairs a File with the absolute File obtained by calling `getAbsoluteFile`.
|
||||
* Note that this usually means that relative files are resolved against the current working directory.*/
|
||||
def abs: FileMap = f => Some(f.getAbsoluteFile)
|
||||
def resolve(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getPath))
|
||||
|
||||
/** Returns a File mapper that resolves a relative File against `newDirectory` and pairs the original File with the resolved File.
|
||||
* The mapper ignores absolute files. */
|
||||
def resolve(newDirectory: File): FileMap = file => if(file.isAbsolute) None else Some(new File(newDirectory, file.getPath))
|
||||
|
||||
def rebase(oldBases: Iterable[File], newBase: File, zero: FileMap = transparent): FileMap =
|
||||
fold(zero, oldBases)(old => rebase(old, newBase))
|
||||
|
||||
/** Produces a File mapper that pairs a descendant of `oldBase` with a file in `newBase` that preserving the relative path of the original file against `oldBase`.
|
||||
* For example, if `oldBase` is `/old/x/` and `newBase` is `/new/a/`, `/old/x/y/z.txt` gets paired with `/new/a/y/z.txt`.
|
||||
* */
|
||||
def rebase(oldBase: File, newBase: File): FileMap =
|
||||
file =>
|
||||
if(file == oldBase)
|
||||
|
|
@ -46,9 +73,22 @@ trait Mapper
|
|||
else
|
||||
IO.relativize(oldBase, file) map { r => new File(newBase, r) }
|
||||
|
||||
/** Constructs a File mapper that pairs a file with a file with the same name in `newDirectory`.
|
||||
* For example, if `newDirectory` is `/a/b`, then `/r/s/t/d.txt` will be paired with `/a/b/d.txt`*/
|
||||
def flat(newDirectory: File): FileMap = file => Some(new File(newDirectory, file.getName))
|
||||
|
||||
import Alternatives._
|
||||
|
||||
/** Selects all descendents of `base` directory and maps them to a path relative to `base`.
|
||||
* `base` itself is not included. */
|
||||
def allSubpaths(base: File): Traversable[(File,String)] =
|
||||
selectSubpaths(base, AllPassFilter)
|
||||
|
||||
/** Selects descendents of `base` directory matching `filter` and maps them to a path relative to `base`.
|
||||
* `base` itself is not included. */
|
||||
def selectSubpaths(base: File, filter: FileFilter): Traversable[(File,String)] =
|
||||
(PathFinder(base) ** filter --- PathFinder(base)) pair (relativeTo(base)|flat)
|
||||
|
||||
private[this] def fold[A,B,T](zero: A => Option[B], in: Iterable[T])(f: T => A => Option[B]): A => Option[B] =
|
||||
(zero /: in)( (mapper, base) => f(base) | mapper )
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue