Unverified Commit 187c04f1 authored by Silvan Mosberger's avatar Silvan Mosberger Committed by GitHub
Browse files

Merge pull request #266349 from tweag/fileset/cleanups

Minor `lib.fileset` cleanups
parents b9534d65 9cbd394a
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -6,11 +6,8 @@ The [`lib.fileset`](#sec-functions-library-fileset) library allows you to work w
A file set is a mathematical set of local files that can be added to the Nix store for use in Nix derivations.
File sets are easy and safe to use, providing obvious and composable semantics with good error messages to prevent mistakes.

These sections apply to the entire library.
See the [function reference](#sec-functions-library-fileset) for function-specific documentation.

The file set library is currently somewhat limited but is being expanded to include more functions over time.

## Implicit coercion from paths to file sets {#sec-fileset-path-coercion}

All functions accepting file sets as arguments can also accept [paths](https://nixos.org/manual/nix/stable/language/values.html#type-path) as arguments.
+27 −27
Original line number Diff line number Diff line
@@ -122,7 +122,6 @@ in {
      Paths in [strings](https://nixos.org/manual/nix/stable/language/values.html#type-string), including Nix store paths, cannot be passed as `root`.
      `root` has to be a directory.

<!-- Ignore the indentation here, this is a nixdoc rendering bug that needs to be fixed: https://github.com/nix-community/nixdoc/issues/75 -->
      :::{.note}
      Changing `root` only affects the directory structure of the resulting store path, it does not change which files are added to the store.
      The only way to change which files get added to the store is by changing the `fileset` attribute.
@@ -135,7 +134,6 @@ The only way to change which files get added to the store is by changing the `fi
      This argument can also be a path,
      which gets [implicitly coerced to a file set](#sec-fileset-path-coercion).

<!-- Ignore the indentation here, this is a nixdoc rendering bug that needs to be fixed: https://github.com/nix-community/nixdoc/issues/75 -->
      :::{.note}
      If a directory does not recursively contain any file, it is omitted from the store path contents.
      :::
@@ -156,7 +154,7 @@ If a directory does not recursively contain any file, it is omitted from the sto
    if ! isPath root then
      if isStringLike root then
        throw ''
          lib.fileset.toSource: `root` ("${toString root}") is a string-like value, but it should be a path instead.
          lib.fileset.toSource: `root` (${toString root}) is a string-like value, but it should be a path instead.
              Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.''
      else
        throw ''
@@ -165,13 +163,13 @@ If a directory does not recursively contain any file, it is omitted from the sto
    # See also ../path/README.md
    else if ! fileset._internalIsEmptyWithoutBase && rootFilesystemRoot != filesetFilesystemRoot then
      throw ''
        lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` ("${toString root}"):
            `root`: root "${toString rootFilesystemRoot}"
            `fileset`: root "${toString filesetFilesystemRoot}"
            Different roots are not supported.''
        lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` (${toString root}):
            `root`: Filesystem root is "${toString rootFilesystemRoot}"
            `fileset`: Filesystem root is "${toString filesetFilesystemRoot}"
            Different filesystem roots are not supported.''
    else if ! pathExists root then
      throw ''
        lib.fileset.toSource: `root` (${toString root}) does not exist.''
        lib.fileset.toSource: `root` (${toString root}) is a path that does not exist.''
    else if pathType root != "directory" then
      throw ''
        lib.fileset.toSource: `root` (${toString root}) is a file, but it should be a directory instead. Potential solutions:
@@ -223,11 +221,11 @@ If a directory does not recursively contain any file, it is omitted from the sto
    _unionMany
      (_coerceMany "lib.fileset.union" [
        {
          context = "first argument";
          context = "First argument";
          value = fileset1;
        }
        {
          context = "second argument";
          context = "Second argument";
          value = fileset2;
        }
      ]);
@@ -269,12 +267,13 @@ If a directory does not recursively contain any file, it is omitted from the sto
    # which get [implicitly coerced to file sets](#sec-fileset-path-coercion).
    filesets:
    if ! isList filesets then
      throw "lib.fileset.unions: Expected argument to be a list, but got a ${typeOf filesets}."
      throw ''
        lib.fileset.unions: Argument is of type ${typeOf filesets}, but it should be a list instead.''
    else
      pipe filesets [
        # Annotate the elements with context, used by _coerceMany for better errors
        (imap0 (i: el: {
          context = "element ${toString i}";
          context = "Element ${toString i}";
          value = el;
        }))
        (_coerceMany "lib.fileset.unions")
@@ -325,10 +324,11 @@ If a directory does not recursively contain any file, it is omitted from the sto
    # The file set to filter based on the predicate function
    fileset:
    if ! isFunction predicate then
      throw "lib.fileset.fileFilter: Expected the first argument to be a function, but it's a ${typeOf predicate} instead."
      throw ''
        lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function.''
    else
      _fileFilter predicate
        (_coerce "lib.fileset.fileFilter: second argument" fileset);
        (_coerce "lib.fileset.fileFilter: Second argument" fileset);

  /*
    The file set containing all files that are in both of two given file sets.
@@ -356,11 +356,11 @@ If a directory does not recursively contain any file, it is omitted from the sto
    let
      filesets = _coerceMany "lib.fileset.intersection" [
        {
          context = "first argument";
          context = "First argument";
          value = fileset1;
        }
        {
          context = "second argument";
          context = "Second argument";
          value = fileset2;
        }
      ];
@@ -408,11 +408,11 @@ If a directory does not recursively contain any file, it is omitted from the sto
    let
      filesets = _coerceMany "lib.fileset.difference" [
        {
          context = "first argument (positive set)";
          context = "First argument (positive set)";
          value = positive;
        }
        {
          context = "second argument (negative set)";
          context = "Second argument (negative set)";
          value = negative;
        }
      ];
@@ -456,7 +456,7 @@ If a directory does not recursively contain any file, it is omitted from the sto
    let
      # "fileset" would be a better name, but that would clash with the argument name,
      # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76
      actualFileset = _coerce "lib.fileset.trace: argument" fileset;
      actualFileset = _coerce "lib.fileset.trace: Argument" fileset;
    in
    seq
      (_printFileset actualFileset)
@@ -503,7 +503,7 @@ If a directory does not recursively contain any file, it is omitted from the sto
    let
      # "fileset" would be a better name, but that would clash with the argument name,
      # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76
      actualFileset = _coerce "lib.fileset.traceVal: argument" fileset;
      actualFileset = _coerce "lib.fileset.traceVal: Argument" fileset;
    in
    seq
      (_printFileset actualFileset)
+4 −7
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@ let
    isString
    pathExists
    readDir
    seq
    split
    trace
    typeOf
@@ -17,7 +16,6 @@ let
    attrNames
    attrValues
    mapAttrs
    setAttrByPath
    zipAttrsWith
    ;

@@ -28,7 +26,6 @@ let
  inherit (lib.lists)
    all
    commonPrefix
    drop
    elemAt
    filter
    findFirst
@@ -179,7 +176,7 @@ rec {
          ${context} is of type ${typeOf value}, but it should be a file set or a path instead.''
    else if ! pathExists value then
      throw ''
        ${context} (${toString value}) does not exist.''
        ${context} (${toString value}) is a path that does not exist.''
    else
      _singleton value;

@@ -208,9 +205,9 @@ rec {
    if firstWithBase != null && differentIndex != null then
      throw ''
        ${functionContext}: Filesystem roots are not the same:
            ${(head list).context}: root "${toString firstBaseRoot}"
            ${(elemAt list differentIndex).context}: root "${toString (elemAt filesets differentIndex)._internalBaseRoot}"
            Different roots are not supported.''
            ${(head list).context}: Filesystem root is "${toString firstBaseRoot}"
            ${(elemAt list differentIndex).context}: Filesystem root is "${toString (elemAt filesets differentIndex)._internalBaseRoot}"
            Different filesystem roots are not supported.''
    else
      filesets;

+23 −23
Original line number Diff line number Diff line
@@ -318,7 +318,7 @@ checkFileset() {
#### Error messages #####

# Absolute paths in strings cannot be passed as `root`
expectFailure 'toSource { root = "/nix/store/foobar"; fileset = ./.; }' 'lib.fileset.toSource: `root` \("/nix/store/foobar"\) is a string-like value, but it should be a path instead.
expectFailure 'toSource { root = "/nix/store/foobar"; fileset = ./.; }' 'lib.fileset.toSource: `root` \(/nix/store/foobar\) is a string-like value, but it should be a path instead.
\s*Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.'

# Only paths are accepted as `root`
@@ -328,14 +328,14 @@ expectFailure 'toSource { root = 10; fileset = ./.; }' 'lib.fileset.toSource: `r
mkdir -p {foo,bar}/mock-root
expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset;
  toSource { root = ./foo/mock-root; fileset = ./bar/mock-root; }
' 'lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` \("'"$work"'/foo/mock-root"\):
\s*`root`: root "'"$work"'/foo/mock-root"
\s*`fileset`: root "'"$work"'/bar/mock-root"
\s*Different roots are not supported.'
' 'lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` \('"$work"'/foo/mock-root\):
\s*`root`: Filesystem root is "'"$work"'/foo/mock-root"
\s*`fileset`: Filesystem root is "'"$work"'/bar/mock-root"
\s*Different filesystem roots are not supported.'
rm -rf -- *

# `root` needs to exist
expectFailure 'toSource { root = ./a; fileset = ./.; }' 'lib.fileset.toSource: `root` \('"$work"'/a\) does not exist.'
expectFailure 'toSource { root = ./a; fileset = ./.; }' 'lib.fileset.toSource: `root` \('"$work"'/a\) is a path that does not exist.'

# `root` needs to be a file
touch a
@@ -367,7 +367,7 @@ expectFailure 'toSource { root = ./.; fileset = "/some/path"; }' 'lib.fileset.to
\s*Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.'

# Path coercion errors for non-existent paths
expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) is a path that does not exist.'

# File sets cannot be evaluated directly
expectFailure 'union ./. ./.' 'lib.fileset: Directly evaluating a file set is not supported.
@@ -490,26 +490,26 @@ mkdir -p {foo,bar}/mock-root
expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset;
  toSource { root = ./.; fileset = union ./foo/mock-root ./bar/mock-root; }
' 'lib.fileset.union: Filesystem roots are not the same:
\s*first argument: root "'"$work"'/foo/mock-root"
\s*second argument: root "'"$work"'/bar/mock-root"
\s*Different roots are not supported.'
\s*First argument: Filesystem root is "'"$work"'/foo/mock-root"
\s*Second argument: Filesystem root is "'"$work"'/bar/mock-root"
\s*Different filesystem roots are not supported.'

expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset;
  toSource { root = ./.; fileset = unions [ ./foo/mock-root ./bar/mock-root ]; }
' 'lib.fileset.unions: Filesystem roots are not the same:
\s*element 0: root "'"$work"'/foo/mock-root"
\s*element 1: root "'"$work"'/bar/mock-root"
\s*Different roots are not supported.'
\s*Element 0: Filesystem root is "'"$work"'/foo/mock-root"
\s*Element 1: Filesystem root is "'"$work"'/bar/mock-root"
\s*Different filesystem roots are not supported.'
rm -rf -- *

# Coercion errors show the correct context
expectFailure 'toSource { root = ./.; fileset = union ./a ./.; }' 'lib.fileset.union: first argument \('"$work"'/a\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = union ./. ./b; }' 'lib.fileset.union: second argument \('"$work"'/b\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = unions [ ./a ./. ]; }' 'lib.fileset.unions: element 0 \('"$work"'/a\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = unions [ ./. ./b ]; }' 'lib.fileset.unions: element 1 \('"$work"'/b\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = union ./a ./.; }' 'lib.fileset.union: First argument \('"$work"'/a\) is a path that does not exist.'
expectFailure 'toSource { root = ./.; fileset = union ./. ./b; }' 'lib.fileset.union: Second argument \('"$work"'/b\) is a path that does not exist.'
expectFailure 'toSource { root = ./.; fileset = unions [ ./a ./. ]; }' 'lib.fileset.unions: Element 0 \('"$work"'/a\) is a path that does not exist.'
expectFailure 'toSource { root = ./.; fileset = unions [ ./. ./b ]; }' 'lib.fileset.unions: Element 1 \('"$work"'/b\) is a path that does not exist.'

# unions needs a list
expectFailure 'toSource { root = ./.; fileset = unions null; }' 'lib.fileset.unions: Expected argument to be a list, but got a null.'
expectFailure 'toSource { root = ./.; fileset = unions null; }' 'lib.fileset.unions: Argument is of type null, but it should be a list instead.'

# The tree of later arguments should not be evaluated if a former argument already includes all files
tree=()
@@ -603,14 +603,14 @@ mkdir -p {foo,bar}/mock-root
expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset;
  toSource { root = ./.; fileset = intersection ./foo/mock-root ./bar/mock-root; }
' 'lib.fileset.intersection: Filesystem roots are not the same:
\s*first argument: root "'"$work"'/foo/mock-root"
\s*second argument: root "'"$work"'/bar/mock-root"
\s*Different roots are not supported.'
\s*First argument: Filesystem root is "'"$work"'/foo/mock-root"
\s*Second argument: Filesystem root is "'"$work"'/bar/mock-root"
\s*Different filesystem roots are not supported.'
rm -rf -- *

# Coercion errors show the correct context
expectFailure 'toSource { root = ./.; fileset = intersection ./a ./.; }' 'lib.fileset.intersection: first argument \('"$work"'/a\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = intersection ./. ./b; }' 'lib.fileset.intersection: second argument \('"$work"'/b\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = intersection ./a ./.; }' 'lib.fileset.intersection: First argument \('"$work"'/a\) is a path that does not exist.'
expectFailure 'toSource { root = ./.; fileset = intersection ./. ./b; }' 'lib.fileset.intersection: Second argument \('"$work"'/b\) is a path that does not exist.'

# The tree of later arguments should not be evaluated if a former argument already excludes all files
tree=(