Home Explore Blog Models CI



nixpkgs

4th chunk of `lib/path/README.md`
61cc0d2228c47f688c81d7fe6c61025d744813b5abcde1aa0000000100000b10
  - (+) Then we'd have to throw an error for doing `append /some/path "../foo"`, making it non-composable.
  - (+) The same is for returning paths with `..`: `relativeTo /foo /bar => "../bar"` would produce a non-composable path.
- (+) We argue that `..` is not needed at the Nix evaluation level, since we'd always start evaluation from the project root and don't go up from there.
  - (+) `..` is supported in Nix paths, turning them into absolute paths.
    - (-) This is ambiguous in the presence of symlinks.
- (+) If you need `..` for building or runtime, you can use build-/run-time tooling to create those (e.g. `realpath` with `--relative-to`), or use absolute paths instead.
  This also gives you the ability to correctly handle symlinks.

</details>

### Trailing slashes

Observing: Subpaths can contain trailing slashes, like `foo/`, indicating that the path points to a directory and not a file.

Considering: Paths should be as consistent as possible, there should only be a single normalisation for the same path.

Decision: All functions remove trailing slashes in their results.

<details>
<summary>Arguments</summary>

- (+) It allows normalisations to be unique, in that there's only a single normalisation for the same path.
  If trailing slashes were preserved, both `foo/bar` and `foo/bar/` would be valid but different normalisations for the same path.
- Comparison to other frameworks to figure out the least surprising behavior:
  - (+) Nix itself doesn't support trailing slashes when parsing and doesn't preserve them when appending paths.
  - (-) [Rust's std::path](https://doc.rust-lang.org/std/path/index.html) does preserve them during [construction](https://doc.rust-lang.org/std/path/struct.Path.html#method.new).
    - (+) Doesn't preserve them when returning individual [components](https://doc.rust-lang.org/std/path/struct.Path.html#method.components).
    - (+) Doesn't preserve them when [canonicalizing](https://doc.rust-lang.org/std/path/struct.Path.html#method.canonicalize).
  - (+) [Python 3's pathlib](https://docs.python.org/3/library/pathlib.html#module-pathlib) doesn't preserve them during [construction](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath).
    - Notably it represents the individual components as a list internally.
  - (-) [Haskell's filepath](https://hackage.haskell.org/package/filepath-1.4.100.0) has [explicit support](https://hackage.haskell.org/package/filepath-1.4.100.0/docs/System-FilePath.html#g:6) for handling trailing slashes.
    - (-) Does preserve them for [normalisation](https://hackage.haskell.org/package/filepath-1.4.100.0/docs/System-FilePath.html#v:normalise).
  - (-) [NodeJS's Path library](https://nodejs.org/api/path.html) preserves trailing slashes for [normalisation](https://nodejs.org/api/path.html#pathnormalizepath).

Title: Nix `lib.path` Decisions: Handling of Trailing Slashes
Summary
This document outlines the decision regarding trailing slashes in subpaths for the Nix `lib.path` library. Given the goal of consistency and having a single normalized representation for each path, the decision is to remove all trailing slashes from the results of all path functions. This ensures that `foo/bar` and `foo/bar/` are not treated as distinct valid normalizations of the same path. The rationale is supported by how Nix itself handles paths (not preserving trailing slashes) and by comparing with other frameworks: while some (like Rust's Path construction or NodeJS) might preserve them, others (like Python's pathlib or Rust's canonicalization) do not. The chosen approach aligns with Nix's existing behavior and promotes unique path normalizations.