Home Explore Blog Models CI



nixpkgs

2nd chunk of `lib/path/README.md`
8c3658e709a87c8fa3c1c1dda8d6f137d5dcd02dcc579b72000000010000101e
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`.
  This effectively then means that paths don't overlap with GNU-style command line options.
- (-) `./` is not required to resolve relative paths, resolution always has an implicit `./` as prefix.
- (-) It's less noisy without the `./`, e.g. in error messages.
  - (+) But similarly, it could be confusing whether something was even a path.
    e.g. `foo` could be anything, but `./foo` is more clearly a path.
- (+) Makes it more uniform with absolute paths (those always start with `/`).
  - (-) That is not relevant for practical purposes.
- (+) `find` also outputs results with `./`.
  - (-) But only if you give it an argument of `.`.
    If you give it the argument `some-directory`, it won't prefix that.
- (-) `realpath --relative-to` doesn't prefix relative paths with `./`.
  - (+) There is no need to return the same result as `realpath`.

</details>

### Representation of the current directory

Observing: The subpath that produces the base directory can be represented with `.` or `./` or `./.`.

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

Decision: It should be `./.`.

<details>
<summary>Arguments</summary>

- (+) `./` would be inconsistent with [the decision to not persist trailing slashes][trailing-slashes].
- (-) `.` is how `realpath` normalises paths.
- (+) `.` can be interpreted as a shell command (it's a builtin for sourcing files in `bash` and `zsh`).
- (+) `.` would be the only path without a `/`.
  It could not be used as a Nix path expression, since those require at least one `/` to be parsed as such.
- (-) `./.` is rather long.
  - (-) We don't require users to type this though, as it's only output by the library.
    As inputs all three variants are supported for subpaths (and we can't do anything about absolute paths)
- (-) `builtins.dirOf "foo" == "."`, so `.` would be consistent with that.
- (+) `./.` is consistent with the [decision to have leading `./`][leading-dots].
- (+) `./.` is a valid Nix path expression, although this property does not hold for every relative path or subpath.

</details>

### Subpath representation

Observing: Subpaths such as `foo/bar` can be represented in various ways:
- string: `"foo/bar"`
- list with all the components: `[ "foo" "bar" ]`
- attribute set: `{ type = "relative-path"; components = [ "foo" "bar" ]; }`

Considering: Paths should be as safe to use as possible.
We should generate string outputs in the library and not encourage users to do that themselves.

Decision: Paths are represented as strings.

<details>
<summary>Arguments</summary>

- (+) It's simpler for the users of the library.
  One doesn't have to convert a path a string before it can be used.
  - (+) Naively converting the list representation to a string with `concatStringsSep "/"` would break for `[]`, requiring library users to be more careful.
- (+) It doesn't encourage people to do their own path processing and instead use the library.
  With a list representation it would seem easy to just use `lib.lists.init` to get the parent directory, but then it breaks for `.`, which would be represented as `[ ]`.

Title: Nix `lib.path` Design: Subpath Normalization and Representation
Summary
This document details specific design decisions for the Nix `lib.path` library concerning the normalization and representation of subpaths. Key decisions include: 1) Always prepending `./` to returned subpaths. This enhances explicitness, consistency, and unambiguousness, preventing clashes with shell commands or CLI options and ensuring validity as Nix path expressions, despite potential verbosity. 2) Representing the current directory as `./.`. This choice ensures consistency with other path decisions (like not persisting trailing slashes), avoids conflict with shell builtins, and makes it a valid Nix path expression, though it's longer than `.` or `./`. 3) Representing subpaths as strings (e.g., `"foo/bar"`) rather than lists of components or attribute sets. This simplifies usage for library consumers, eliminating the need for manual conversions and discouraging potentially error-prone custom path processing.