Skip to content

lib.path: path functions

Functions for working with path values.

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:192 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:226 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:271 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:336 in <nixpkgs>.

lib.path.hasStorePathPrefix

Type: hasStorePathPrefix :: Path -> Bool

Whether a path has a store path as a prefix.

Note

As with all functions of this lib.path library, it does not work on paths in strings, which is how you'd typically get store paths.

Instead, this function only handles path values themselves, which occur when Nix files in the store use relative path expressions.

path

: Function argument

Example

lib.path.hasStorePathPrefix usage example

# Subpaths of derivation outputs have a store path as a prefix
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo/bar/baz
=> true "The store directory itself is not a store path
hasStorePathPrefix /nix/store
=> false "Derivation outputs are store paths themselves
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo
=> true "Paths outside the Nix store don't have a store path prefix
hasStorePathPrefix /home/user
=> false "Not all paths under the Nix store are store paths
hasStorePathPrefix /nix/store/.links/10gg8k3rmbw8p7gszarbk7qyd9jwxhcfq9i6s5i0qikx8alkk4hq
=> false "Store derivations are also store paths themselves
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo.drv
=> true

Located at lib/path/default.nix:390 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:447 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:510 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:552 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:633 in <nixpkgs>.