Home Explore Blog Models CI



nixpkgs

1st chunk of `lib/path/README.md`
b8a75aa079dadbc28cf17b2d8dafe079c7cbdcafb34145e90000000100000fb3
# Path library

This document explains why the `lib.path` library is designed the way it is.

The purpose of this library is to process [filesystem paths].
It does not read files from the filesystem.
It exists to support the native Nix [path value type] with extra functionality.


As an extension of the path value type, it inherits the same intended use cases and limitations:
- Only use paths to access files at evaluation time, such as the local project source.
- Paths cannot point to derivations, so they are unfit to represent dependencies.
- A path implicitly imports the referenced files into the Nix store when interpolated to a string.
  Therefore paths are not suitable to access files at build- or run-time, as you risk importing the path from the evaluation system instead.

Overall, this library works with two types of paths:
- Absolute paths are represented with the Nix [path value type].
  Nix automatically normalises these paths.
- Subpaths are represented with the [string value type] since path value types don't support relative paths.
  This library normalises these paths as safely as possible.
  Absolute paths in strings are not supported.

  A subpath refers to a specific file or directory within an absolute base directory.
  It is a stricter form of a relative path, notably [without support for `..` components][parents] since those could escape the base directory.


This library is designed to be as safe and intuitive as possible, throwing errors when operations are attempted that would produce surprising results, and giving the expected result otherwise.

This library is designed to work well as a dependency for the `lib.filesystem` and `lib.sources` library components.
Contrary to these library components, `lib.path` does not read any paths from the filesystem.

This library makes only these assumptions about paths and no others:
- `dirOf path` returns the path to the parent directory of `path`, unless `path` is the filesystem root, in which case `path` is returned.
  - There can be multiple filesystem roots: `p == dirOf p` and `q == dirOf q` does not imply `p == q`.
    - While there's only a single filesystem root in stable Nix, the [lazy trees feature](https://github.com/NixOS/nix/pull/6530) introduces [additional filesystem roots](https://github.com/NixOS/nix/pull/6530#discussion_r1041442173).
- `path + ("/" + string)` returns the path to the `string` subdirectory in `path`.
  - If `string` contains no `/` characters, then `dirOf (path + ("/" + string)) == path`.
  - If `string` contains no `/` characters, then `baseNameOf (path + ("/" + string)) == string`.
- `path1 == path2` returns `true` only if `path1` points to the same filesystem path as `path2`.

Notably we do not make the assumption that we can turn paths into strings using `toString path`.

## Design decisions

Each subsection here contains a decision along with arguments and counter-arguments for (+) and against (-) that decision.

### Leading dots for relative paths

Observing: Since subpaths are a form of relative paths, they can have a leading `./` to indicate it being a relative path, this is generally not necessary for tools though.

Considering: Paths should be as explicit, consistent and unambiguous as possible.

Decision: Returned subpaths should always have a leading `./`.

<details>
<summary>Arguments</summary>

- (+) In shells, just running `foo` as a command wouldn't execute the file `foo`, whereas `./foo` would execute the file.
  In contrast, `foo/bar` does execute that file without the need for `./`.
  This can lead to confusion about when a `./` needs to be prefixed.
  If a `./` is always included, this becomes a non-issue.
  This effectively then means that paths don't overlap with command names.
- (+) Prepending with `./` makes the subpaths always valid as relative Nix path expressions.
- (+) Using paths in command line arguments could give problems if not escaped properly, e.g. if a path was `--version`.
  This is not a problem with `./--version`.

Title: Nix `lib.path` Library Design and Principles
Summary
This document outlines the design and purpose of the `lib.path` library in Nix, which processes filesystem paths without reading files. It extends the native Nix path value type, inheriting limitations like its suitability only for evaluation-time access (e.g., local project sources) and unsuitability for dependencies or build/run-time operations due to implicit store imports. The library handles two path types: absolute paths (Nix path value type, auto-normalized) and subpaths (string value type, strictly relative without `..` components, normalized by the library). Its design prioritizes safety and intuitiveness, making specific assumptions about path operations (e.g., `dirOf`, path concatenation). A key design decision discussed is always prepending `./` to returned subpaths for clarity, consistency, and to prevent conflicts with command names or CLI arguments.