=============
Mapping Files
=============

Tasks like :key:`package`, :key:`packageSrc`, and :key:`packageDoc` accept
mappings of type `Seq[(File, String)]` from an input file to the path
to use in the resulting artifact (jar). Similarly, tasks that copy files
accept mappings of type `Seq[(File, File)]` from an input file to the
destination file. There are some methods on
`PathFinder <../../api/sbt/PathFinder.html>`_
and `Path <../../api/sbt/Path$.html>`_
that can be useful for constructing the `Seq[(File, String)]` or
`Seq[(File, File)]` sequences.

A common way of making this sequence is to start with a `PathFinder`
or `Seq[File]` (which is implicitly convertible to `PathFinder`) and
then call the `pair` method. See the
`PathFinder <../../api/sbt/PathFinder.html>`_
API for details, but essentially this method accepts a function
`File => Option[String]` or `File => Option[File]` that is used to
generate mappings.

Relative to a directory
-----------------------

The `Path.relativeTo` method is used to map a `File` to its path
`String` relative to a base directory or directories. The
`relativeTo` method accepts a base directory or sequence of base
directories to relativize an input file against. The first directory
that is an ancestor of the file is used in the case of a sequence of
base directories.

For example:

::

      import Path.relativeTo
    val files: Seq[File] = file("/a/b/C.scala") :: Nil
    val baseDirectories: Seq[File] = file("/a") :: Nil
    val mappings: Seq[(File,String)] = files pair relativeTo(baseDirectories)

    val expected = (file("/a/b/C.scala") -> "b/C.scala") :: Nil
    assert( mappings == expected )

Rebase
------

The `Path.rebase` method relativizes an input file against one or more
base directories (the first argument) and then prepends a base String or
File (the second argument) to the result. As with `relativeTo`, the
first base directory that is an ancestor of the input file is used in
the case of multiple base directories.

For example, the following demonstrates building a
`Seq[(File, String)]` using `rebase`:

::

    import Path.rebase
    val files: Seq[File] = file("/a/b/C.scala") :: Nil
    val baseDirectories: Seq[File] = file("/a") :: Nil
    val mappings: Seq[(File,String)] = files pair rebase(baseDirectories, "pre/")

    val expected = (file("/a/b/C.scala") -> "pre/b/C.scala" ) :: Nil
    assert( mappings == expected )

Or, to build a `Seq[(File, File)]`:

::

    import Path.rebase
    val files: Seq[File] = file("/a/b/C.scala") :: Nil
    val baseDirectories: Seq[File] = file("/a") :: Nil
    val newBase: File = file("/new/base")
    val mappings: Seq[(File,File)] = files pair rebase(baseDirectories, newBase)

    val expected = (file("/a/b/C.scala") -> file("/new/base/b/C.scala") ) :: Nil
    assert( mappings == expected )

Flatten
-------

The `Path.flat` method provides a function that maps a file to the
last component of the path (its name). For a File to File mapping, the
input file is mapped to a file with the same name in a given target
directory. For example:

::

    import Path.flat
    val files: Seq[File] = file("/a/b/C.scala") :: Nil
    val mappings: Seq[(File,String)] = files pair flat

    val expected = (file("/a/b/C.scala") -> "C.scala" ) :: Nil
    assert( mappings == expected )

To build a `Seq[(File, File)]` using `flat`:

::

    import Path.flat
    val files: Seq[File] = file("/a/b/C.scala") :: Nil
    val newBase: File = file("/new/base")
    val mappings: Seq[(File,File)] = files pair flat(newBase)

    val expected = (file("/a/b/C.scala") -> file("/new/base/C.scala") ) :: Nil
    assert( mappings == expected )

Alternatives
------------

To try to apply several alternative mappings for a file, use `|`,
which is implicitly added to a function of type `A => Option[B]`. For
example, to try to relativize a file against some base directories but
fall back to flattening:

::

    import Path.relativeTo
    val files: Seq[File] = file("/a/b/C.scala") :: file("/zzz/D.scala") :: Nil
    val baseDirectories: Seq[File] = file("/a") :: Nil
    val mappings: Seq[(File,String)] = files pair ( relativeTo(baseDirectories) | flat )

    val expected = (file("/a/b/C.scala") -> "b/C.scala") ) :: (file("/zzz/D.scala") -> "D.scala") ) :: Nil
    assert( mappings == expected )
