lib.path: path functions

lib.path.append

Type: append :: Path -> String -> Path

Append a subpath string to a path.

Like path + ("/" + string) but safer, because it errors instead of returning potentially surprising results. More specifically, it checks that the first argument is a path value type, and that the second argument is a valid subpath string.

Laws:

  • Not influenced by subpath normalisation:

    append p s == append p (subpath.normalise s)
    

path

The absolute path to append to

subpath

The subpath string to append

Example

lib.path.append usage example

append /foo "bar/baz"
=> /foo/bar/baz

# subpaths don't need to be normalised
append /foo "./bar//baz/./"
=> /foo/bar/baz

# can append to root directory
append /. "foo/bar"
=> /foo/bar

# first argument needs to be a path value type
append "/foo" "bar"
=> <error>

# second argument needs to be a valid subpath string
append /foo /bar
=> <error>
append /foo ""
=> <error>
append /foo "/bar"
=> <error>
append /foo "../bar"
=> <error>

Located at lib/path/default.nix:166 in <nixpkgs>.

lib.path.hasPrefix

Type: hasPrefix :: Path -> Path -> Bool

Whether the first path is a component-wise prefix of the second path.

Laws:

path1

Function argument

Example

lib.path.hasPrefix usage example

hasPrefix /foo /foo/bar
=> true
hasPrefix /foo /foo
=> true
hasPrefix /foo/bar /foo
=> false
hasPrefix /. /foo
=> true

Located at lib/path/default.nix:200 in <nixpkgs>.

lib.path.removePrefix

Type: removePrefix :: Path -> Path -> String

Remove the first path as a component-wise prefix from the second path. The result is a normalised subpath string.

Laws:

path1

Function argument

Example

lib.path.removePrefix usage example

removePrefix /foo /foo/bar/baz
=> "./bar/baz"
removePrefix /foo /foo
=> "./."
removePrefix /foo/bar /foo
=> <error>
removePrefix /. /foo
=> "./foo"

Located at lib/path/default.nix:245 in <nixpkgs>.

lib.path.splitRoot

Type: splitRoot :: Path -> { root :: Path, subpath :: String }

Split the filesystem root from a path. The result is an attribute set with these attributes:

  • root: The filesystem root of the path, meaning that this directory has no parent directory.
  • subpath: The normalised subpath string that when appended to root returns the original path.

Laws:

  • Appending the root and subpath gives the original path:

    p ==
      append
        (splitRoot p).root
        (splitRoot p).subpath
    
  • Trying to get the parent directory of root using readDir returns root itself:

    dirOf (splitRoot p).root == (splitRoot p).root
    

path

The path to split the root off of

Example

lib.path.splitRoot usage example

splitRoot /foo/bar
=> { root = /.; subpath = "./foo/bar"; }

splitRoot /.
=> { root = /.; subpath = "./."; }

# Nix neutralises `..` path components for all path values automatically
splitRoot /foo/../bar
=> { root = /.; subpath = "./bar"; }

splitRoot "/foo/bar"
=> <error>

Located at lib/path/default.nix:310 in <nixpkgs>.

lib.path.subpath.isValid

Type: subpath.isValid :: String -> Bool

Whether a value is a valid subpath string.

A subpath string points to a specific file or directory within an absolute base directory. It is a stricter form of a relative path that excludes .. components, since those could escape the base directory.

  • The value is a string.

  • The string is not empty.

  • The string doesn't start with a /.

  • The string doesn't contain any .. path components.

value

The value to check

Example

lib.path.subpath.isValid usage example

# Not a string
subpath.isValid null
=> false

# Empty string
subpath.isValid ""
=> false

# Absolute path
subpath.isValid "/foo"
=> false

# Contains a `..` path component
subpath.isValid "../foo"
=> false

# Valid subpath
subpath.isValid "foo/bar"
=> true

# Doesn't need to be normalised
subpath.isValid "./foo//bar/"
=> true

Located at lib/path/default.nix:365 in <nixpkgs>.

lib.path.subpath.join

Type: subpath.join :: [ String ] -> String

Join subpath strings together using /, returning a normalised subpath string.

Like concatStringsSep "/" but safer, specifically:

  • All elements must be valid subpath strings.

  • The result gets normalised.

  • The edge case of an empty list gets properly handled by returning the neutral subpath "./.".

Laws:

  • Associativity:

    subpath.join [ x (subpath.join [ y z ]) ] == subpath.join [ (subpath.join [ x y ]) z ]
    
  • Identity - "./." is the neutral element for normalised paths:

    subpath.join [ ] == "./."
    subpath.join [ (subpath.normalise p) "./." ] == subpath.normalise p
    subpath.join [ "./." (subpath.normalise p) ] == subpath.normalise p
    
  • Normalisation - the result is normalised:

    subpath.join ps == subpath.normalise (subpath.join ps)
    
  • For non-empty lists, the implementation is equivalent to normalising the result of concatStringsSep "/". Note that the above laws can be derived from this one:

    ps != [] -> subpath.join ps == subpath.normalise (concatStringsSep "/" ps)
    

subpaths

The list of subpaths to join together

Example

lib.path.subpath.join usage example

subpath.join [ "foo" "bar/baz" ]
=> "./foo/bar/baz"

# normalise the result
subpath.join [ "./foo" "." "bar//./baz/" ]
=> "./foo/bar/baz"

# passing an empty list results in the current directory
subpath.join [ ]
=> "./."

# elements must be valid subpath strings
subpath.join [ /foo ]
=> <error>
subpath.join [ "" ]
=> <error>
subpath.join [ "/foo" ]
=> <error>
subpath.join [ "../foo" ]
=> <error>

Located at lib/path/default.nix:428 in <nixpkgs>.

lib.path.subpath.components

Type: subpath.components :: String -> [ String ]

Split a subpath into its path component strings. Throw an error if the subpath isn't valid. Note that the returned path components are also valid subpath strings, though they are intentionally not normalised.

Laws:

  • Splitting a subpath into components and joining the components gives the same subpath but normalised:

    subpath.join (subpath.components s) == subpath.normalise s
    

subpath

The subpath string to split into components

Example

lib.path.subpath.components usage example

subpath.components "."
=> [ ]

subpath.components "./foo//bar/./baz/"
=> [ "foo" "bar" "baz" ]

subpath.components "/foo"
=> <error>

Located at lib/path/default.nix:470 in <nixpkgs>.

lib.path.subpath.normalise

Type: subpath.normalise :: String -> String

Normalise a subpath. Throw an error if the subpath isn't valid.

  • Limit repeating / to a single one.

  • Remove redundant . components.

  • Remove trailing / and /..

  • Add leading ./.

Laws:

  • Idempotency - normalising multiple times gives the same result:

    subpath.normalise (subpath.normalise p) == subpath.normalise p
    
  • Uniqueness - there's only a single normalisation for the paths that lead to the same file system node:

    subpath.normalise p != subpath.normalise q -> $(realpath ${p}) != $(realpath ${q})
    
  • Don't change the result when appended to a Nix path value:

    append base p == append base (subpath.normalise p)
    
  • Don't change the path according to realpath:

    $(realpath ${p}) == $(realpath ${subpath.normalise p})
    
  • Only error on invalid subpaths:

    builtins.tryEval (subpath.normalise p)).success == subpath.isValid p
    

subpath

The subpath string to normalise

Example

lib.path.subpath.normalise usage example

# limit repeating `/` to a single one
subpath.normalise "foo//bar"
=> "./foo/bar"

# remove redundant `.` components
subpath.normalise "foo/./bar"
=> "./foo/bar"

# add leading `./`
subpath.normalise "foo/bar"
=> "./foo/bar"

# remove trailing `/`
subpath.normalise "foo/bar/"
=> "./foo/bar"

# remove trailing `/.`
subpath.normalise "foo/bar/."
=> "./foo/bar"

# Return the current directory as `./.`
subpath.normalise "."
=> "./."

# error on `..` path components
subpath.normalise "foo/../bar"
=> <error>

# error on empty string
subpath.normalise ""
=> <error>

# error on absolute path
subpath.normalise "/foo"
=> <error>

Located at lib/path/default.nix:551 in <nixpkgs>.