Merge pull request #266349 from tweag/fileset/cleanups

Minor `lib.fileset` cleanups

authored by

Silvan Mosberger and committed by
GitHub
187c04f1 b9534d65

+54 -60
-3
doc/functions/fileset.section.md
··· 6 A file set is a mathematical set of local files that can be added to the Nix store for use in Nix derivations. 7 File sets are easy and safe to use, providing obvious and composable semantics with good error messages to prevent mistakes. 8 9 - These sections apply to the entire library. 10 See the [function reference](#sec-functions-library-fileset) for function-specific documentation. 11 - 12 - The file set library is currently somewhat limited but is being expanded to include more functions over time. 13 14 ## Implicit coercion from paths to file sets {#sec-fileset-path-coercion} 15
··· 6 A file set is a mathematical set of local files that can be added to the Nix store for use in Nix derivations. 7 File sets are easy and safe to use, providing obvious and composable semantics with good error messages to prevent mistakes. 8 9 See the [function reference](#sec-functions-library-fileset) for function-specific documentation. 10 11 ## Implicit coercion from paths to file sets {#sec-fileset-path-coercion} 12
+27 -27
lib/fileset/default.nix
··· 122 Paths in [strings](https://nixos.org/manual/nix/stable/language/values.html#type-string), including Nix store paths, cannot be passed as `root`. 123 `root` has to be a directory. 124 125 - <!-- Ignore the indentation here, this is a nixdoc rendering bug that needs to be fixed: https://github.com/nix-community/nixdoc/issues/75 --> 126 - :::{.note} 127 - Changing `root` only affects the directory structure of the resulting store path, it does not change which files are added to the store. 128 - The only way to change which files get added to the store is by changing the `fileset` attribute. 129 - ::: 130 */ 131 root, 132 /* ··· 135 This argument can also be a path, 136 which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 137 138 - <!-- Ignore the indentation here, this is a nixdoc rendering bug that needs to be fixed: https://github.com/nix-community/nixdoc/issues/75 --> 139 - :::{.note} 140 - If a directory does not recursively contain any file, it is omitted from the store path contents. 141 - ::: 142 143 */ 144 fileset, ··· 156 if ! isPath root then 157 if isStringLike root then 158 throw '' 159 - lib.fileset.toSource: `root` ("${toString root}") is a string-like value, but it should be a path instead. 160 Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.'' 161 else 162 throw '' ··· 165 # See also ../path/README.md 166 else if ! fileset._internalIsEmptyWithoutBase && rootFilesystemRoot != filesetFilesystemRoot then 167 throw '' 168 - lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` ("${toString root}"): 169 - `root`: root "${toString rootFilesystemRoot}" 170 - `fileset`: root "${toString filesetFilesystemRoot}" 171 - Different roots are not supported.'' 172 else if ! pathExists root then 173 throw '' 174 - lib.fileset.toSource: `root` (${toString root}) does not exist.'' 175 else if pathType root != "directory" then 176 throw '' 177 lib.fileset.toSource: `root` (${toString root}) is a file, but it should be a directory instead. Potential solutions: ··· 223 _unionMany 224 (_coerceMany "lib.fileset.union" [ 225 { 226 - context = "first argument"; 227 value = fileset1; 228 } 229 { 230 - context = "second argument"; 231 value = fileset2; 232 } 233 ]); ··· 269 # which get [implicitly coerced to file sets](#sec-fileset-path-coercion). 270 filesets: 271 if ! isList filesets then 272 - throw "lib.fileset.unions: Expected argument to be a list, but got a ${typeOf filesets}." 273 else 274 pipe filesets [ 275 # Annotate the elements with context, used by _coerceMany for better errors 276 (imap0 (i: el: { 277 - context = "element ${toString i}"; 278 value = el; 279 })) 280 (_coerceMany "lib.fileset.unions") ··· 325 # The file set to filter based on the predicate function 326 fileset: 327 if ! isFunction predicate then 328 - throw "lib.fileset.fileFilter: Expected the first argument to be a function, but it's a ${typeOf predicate} instead." 329 else 330 _fileFilter predicate 331 - (_coerce "lib.fileset.fileFilter: second argument" fileset); 332 333 /* 334 The file set containing all files that are in both of two given file sets. ··· 356 let 357 filesets = _coerceMany "lib.fileset.intersection" [ 358 { 359 - context = "first argument"; 360 value = fileset1; 361 } 362 { 363 - context = "second argument"; 364 value = fileset2; 365 } 366 ]; ··· 408 let 409 filesets = _coerceMany "lib.fileset.difference" [ 410 { 411 - context = "first argument (positive set)"; 412 value = positive; 413 } 414 { 415 - context = "second argument (negative set)"; 416 value = negative; 417 } 418 ]; ··· 456 let 457 # "fileset" would be a better name, but that would clash with the argument name, 458 # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 459 - actualFileset = _coerce "lib.fileset.trace: argument" fileset; 460 in 461 seq 462 (_printFileset actualFileset) ··· 503 let 504 # "fileset" would be a better name, but that would clash with the argument name, 505 # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 506 - actualFileset = _coerce "lib.fileset.traceVal: argument" fileset; 507 in 508 seq 509 (_printFileset actualFileset)
··· 122 Paths in [strings](https://nixos.org/manual/nix/stable/language/values.html#type-string), including Nix store paths, cannot be passed as `root`. 123 `root` has to be a directory. 124 125 + :::{.note} 126 + Changing `root` only affects the directory structure of the resulting store path, it does not change which files are added to the store. 127 + The only way to change which files get added to the store is by changing the `fileset` attribute. 128 + ::: 129 */ 130 root, 131 /* ··· 134 This argument can also be a path, 135 which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 136 137 + :::{.note} 138 + If a directory does not recursively contain any file, it is omitted from the store path contents. 139 + ::: 140 141 */ 142 fileset, ··· 154 if ! isPath root then 155 if isStringLike root then 156 throw '' 157 + lib.fileset.toSource: `root` (${toString root}) is a string-like value, but it should be a path instead. 158 Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.'' 159 else 160 throw '' ··· 163 # See also ../path/README.md 164 else if ! fileset._internalIsEmptyWithoutBase && rootFilesystemRoot != filesetFilesystemRoot then 165 throw '' 166 + lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` (${toString root}): 167 + `root`: Filesystem root is "${toString rootFilesystemRoot}" 168 + `fileset`: Filesystem root is "${toString filesetFilesystemRoot}" 169 + Different filesystem roots are not supported.'' 170 else if ! pathExists root then 171 throw '' 172 + lib.fileset.toSource: `root` (${toString root}) is a path that does not exist.'' 173 else if pathType root != "directory" then 174 throw '' 175 lib.fileset.toSource: `root` (${toString root}) is a file, but it should be a directory instead. Potential solutions: ··· 221 _unionMany 222 (_coerceMany "lib.fileset.union" [ 223 { 224 + context = "First argument"; 225 value = fileset1; 226 } 227 { 228 + context = "Second argument"; 229 value = fileset2; 230 } 231 ]); ··· 267 # which get [implicitly coerced to file sets](#sec-fileset-path-coercion). 268 filesets: 269 if ! isList filesets then 270 + throw '' 271 + lib.fileset.unions: Argument is of type ${typeOf filesets}, but it should be a list instead.'' 272 else 273 pipe filesets [ 274 # Annotate the elements with context, used by _coerceMany for better errors 275 (imap0 (i: el: { 276 + context = "Element ${toString i}"; 277 value = el; 278 })) 279 (_coerceMany "lib.fileset.unions") ··· 324 # The file set to filter based on the predicate function 325 fileset: 326 if ! isFunction predicate then 327 + throw '' 328 + lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function.'' 329 else 330 _fileFilter predicate 331 + (_coerce "lib.fileset.fileFilter: Second argument" fileset); 332 333 /* 334 The file set containing all files that are in both of two given file sets. ··· 356 let 357 filesets = _coerceMany "lib.fileset.intersection" [ 358 { 359 + context = "First argument"; 360 value = fileset1; 361 } 362 { 363 + context = "Second argument"; 364 value = fileset2; 365 } 366 ]; ··· 408 let 409 filesets = _coerceMany "lib.fileset.difference" [ 410 { 411 + context = "First argument (positive set)"; 412 value = positive; 413 } 414 { 415 + context = "Second argument (negative set)"; 416 value = negative; 417 } 418 ]; ··· 456 let 457 # "fileset" would be a better name, but that would clash with the argument name, 458 # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 459 + actualFileset = _coerce "lib.fileset.trace: Argument" fileset; 460 in 461 seq 462 (_printFileset actualFileset) ··· 503 let 504 # "fileset" would be a better name, but that would clash with the argument name, 505 # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 506 + actualFileset = _coerce "lib.fileset.traceVal: Argument" fileset; 507 in 508 seq 509 (_printFileset actualFileset)
+4 -7
lib/fileset/internal.nix
··· 7 isString 8 pathExists 9 readDir 10 - seq 11 split 12 trace 13 typeOf ··· 17 attrNames 18 attrValues 19 mapAttrs 20 - setAttrByPath 21 zipAttrsWith 22 ; 23 ··· 28 inherit (lib.lists) 29 all 30 commonPrefix 31 - drop 32 elemAt 33 filter 34 findFirst ··· 179 ${context} is of type ${typeOf value}, but it should be a file set or a path instead.'' 180 else if ! pathExists value then 181 throw '' 182 - ${context} (${toString value}) does not exist.'' 183 else 184 _singleton value; 185 ··· 208 if firstWithBase != null && differentIndex != null then 209 throw '' 210 ${functionContext}: Filesystem roots are not the same: 211 - ${(head list).context}: root "${toString firstBaseRoot}" 212 - ${(elemAt list differentIndex).context}: root "${toString (elemAt filesets differentIndex)._internalBaseRoot}" 213 - Different roots are not supported.'' 214 else 215 filesets; 216
··· 7 isString 8 pathExists 9 readDir 10 split 11 trace 12 typeOf ··· 16 attrNames 17 attrValues 18 mapAttrs 19 zipAttrsWith 20 ; 21 ··· 26 inherit (lib.lists) 27 all 28 commonPrefix 29 elemAt 30 filter 31 findFirst ··· 176 ${context} is of type ${typeOf value}, but it should be a file set or a path instead.'' 177 else if ! pathExists value then 178 throw '' 179 + ${context} (${toString value}) is a path that does not exist.'' 180 else 181 _singleton value; 182 ··· 205 if firstWithBase != null && differentIndex != null then 206 throw '' 207 ${functionContext}: Filesystem roots are not the same: 208 + ${(head list).context}: Filesystem root is "${toString firstBaseRoot}" 209 + ${(elemAt list differentIndex).context}: Filesystem root is "${toString (elemAt filesets differentIndex)._internalBaseRoot}" 210 + Different filesystem roots are not supported.'' 211 else 212 filesets; 213
+23 -23
lib/fileset/tests.sh
··· 318 #### Error messages ##### 319 320 # Absolute paths in strings cannot be passed as `root` 321 - 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. 322 \s*Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.' 323 324 # Only paths are accepted as `root` ··· 328 mkdir -p {foo,bar}/mock-root 329 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 330 toSource { root = ./foo/mock-root; fileset = ./bar/mock-root; } 331 - ' 'lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` \("'"$work"'/foo/mock-root"\): 332 - \s*`root`: root "'"$work"'/foo/mock-root" 333 - \s*`fileset`: root "'"$work"'/bar/mock-root" 334 - \s*Different roots are not supported.' 335 rm -rf -- * 336 337 # `root` needs to exist 338 - expectFailure 'toSource { root = ./a; fileset = ./.; }' 'lib.fileset.toSource: `root` \('"$work"'/a\) does not exist.' 339 340 # `root` needs to be a file 341 touch a ··· 367 \s*Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.' 368 369 # Path coercion errors for non-existent paths 370 - expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) does not exist.' 371 372 # File sets cannot be evaluated directly 373 expectFailure 'union ./. ./.' 'lib.fileset: Directly evaluating a file set is not supported. ··· 490 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 491 toSource { root = ./.; fileset = union ./foo/mock-root ./bar/mock-root; } 492 ' 'lib.fileset.union: Filesystem roots are not the same: 493 - \s*first argument: root "'"$work"'/foo/mock-root" 494 - \s*second argument: root "'"$work"'/bar/mock-root" 495 - \s*Different roots are not supported.' 496 497 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 498 toSource { root = ./.; fileset = unions [ ./foo/mock-root ./bar/mock-root ]; } 499 ' 'lib.fileset.unions: Filesystem roots are not the same: 500 - \s*element 0: root "'"$work"'/foo/mock-root" 501 - \s*element 1: root "'"$work"'/bar/mock-root" 502 - \s*Different roots are not supported.' 503 rm -rf -- * 504 505 # Coercion errors show the correct context 506 - expectFailure 'toSource { root = ./.; fileset = union ./a ./.; }' 'lib.fileset.union: first argument \('"$work"'/a\) does not exist.' 507 - expectFailure 'toSource { root = ./.; fileset = union ./. ./b; }' 'lib.fileset.union: second argument \('"$work"'/b\) does not exist.' 508 - expectFailure 'toSource { root = ./.; fileset = unions [ ./a ./. ]; }' 'lib.fileset.unions: element 0 \('"$work"'/a\) does not exist.' 509 - expectFailure 'toSource { root = ./.; fileset = unions [ ./. ./b ]; }' 'lib.fileset.unions: element 1 \('"$work"'/b\) does not exist.' 510 511 # unions needs a list 512 - expectFailure 'toSource { root = ./.; fileset = unions null; }' 'lib.fileset.unions: Expected argument to be a list, but got a null.' 513 514 # The tree of later arguments should not be evaluated if a former argument already includes all files 515 tree=() ··· 603 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 604 toSource { root = ./.; fileset = intersection ./foo/mock-root ./bar/mock-root; } 605 ' 'lib.fileset.intersection: Filesystem roots are not the same: 606 - \s*first argument: root "'"$work"'/foo/mock-root" 607 - \s*second argument: root "'"$work"'/bar/mock-root" 608 - \s*Different roots are not supported.' 609 rm -rf -- * 610 611 # Coercion errors show the correct context 612 - expectFailure 'toSource { root = ./.; fileset = intersection ./a ./.; }' 'lib.fileset.intersection: first argument \('"$work"'/a\) does not exist.' 613 - expectFailure 'toSource { root = ./.; fileset = intersection ./. ./b; }' 'lib.fileset.intersection: second argument \('"$work"'/b\) does not exist.' 614 615 # The tree of later arguments should not be evaluated if a former argument already excludes all files 616 tree=(
··· 318 #### Error messages ##### 319 320 # Absolute paths in strings cannot be passed as `root` 321 + 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. 322 \s*Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.' 323 324 # Only paths are accepted as `root` ··· 328 mkdir -p {foo,bar}/mock-root 329 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 330 toSource { root = ./foo/mock-root; fileset = ./bar/mock-root; } 331 + ' 'lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` \('"$work"'/foo/mock-root\): 332 + \s*`root`: Filesystem root is "'"$work"'/foo/mock-root" 333 + \s*`fileset`: Filesystem root is "'"$work"'/bar/mock-root" 334 + \s*Different filesystem roots are not supported.' 335 rm -rf -- * 336 337 # `root` needs to exist 338 + expectFailure 'toSource { root = ./a; fileset = ./.; }' 'lib.fileset.toSource: `root` \('"$work"'/a\) is a path that does not exist.' 339 340 # `root` needs to be a file 341 touch a ··· 367 \s*Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.' 368 369 # Path coercion errors for non-existent paths 370 + expectFailure 'toSource { root = ./.; fileset = ./a; }' 'lib.fileset.toSource: `fileset` \('"$work"'/a\) is a path that does not exist.' 371 372 # File sets cannot be evaluated directly 373 expectFailure 'union ./. ./.' 'lib.fileset: Directly evaluating a file set is not supported. ··· 490 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 491 toSource { root = ./.; fileset = union ./foo/mock-root ./bar/mock-root; } 492 ' 'lib.fileset.union: Filesystem roots are not the same: 493 + \s*First argument: Filesystem root is "'"$work"'/foo/mock-root" 494 + \s*Second argument: Filesystem root is "'"$work"'/bar/mock-root" 495 + \s*Different filesystem roots are not supported.' 496 497 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 498 toSource { root = ./.; fileset = unions [ ./foo/mock-root ./bar/mock-root ]; } 499 ' 'lib.fileset.unions: Filesystem roots are not the same: 500 + \s*Element 0: Filesystem root is "'"$work"'/foo/mock-root" 501 + \s*Element 1: Filesystem root is "'"$work"'/bar/mock-root" 502 + \s*Different filesystem roots are not supported.' 503 rm -rf -- * 504 505 # Coercion errors show the correct context 506 + expectFailure 'toSource { root = ./.; fileset = union ./a ./.; }' 'lib.fileset.union: First argument \('"$work"'/a\) is a path that does not exist.' 507 + expectFailure 'toSource { root = ./.; fileset = union ./. ./b; }' 'lib.fileset.union: Second argument \('"$work"'/b\) is a path that does not exist.' 508 + expectFailure 'toSource { root = ./.; fileset = unions [ ./a ./. ]; }' 'lib.fileset.unions: Element 0 \('"$work"'/a\) is a path that does not exist.' 509 + expectFailure 'toSource { root = ./.; fileset = unions [ ./. ./b ]; }' 'lib.fileset.unions: Element 1 \('"$work"'/b\) is a path that does not exist.' 510 511 # unions needs a list 512 + expectFailure 'toSource { root = ./.; fileset = unions null; }' 'lib.fileset.unions: Argument is of type null, but it should be a list instead.' 513 514 # The tree of later arguments should not be evaluated if a former argument already includes all files 515 tree=() ··· 603 expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset; 604 toSource { root = ./.; fileset = intersection ./foo/mock-root ./bar/mock-root; } 605 ' 'lib.fileset.intersection: Filesystem roots are not the same: 606 + \s*First argument: Filesystem root is "'"$work"'/foo/mock-root" 607 + \s*Second argument: Filesystem root is "'"$work"'/bar/mock-root" 608 + \s*Different filesystem roots are not supported.' 609 rm -rf -- * 610 611 # Coercion errors show the correct context 612 + expectFailure 'toSource { root = ./.; fileset = intersection ./a ./.; }' 'lib.fileset.intersection: First argument \('"$work"'/a\) is a path that does not exist.' 613 + expectFailure 'toSource { root = ./.; fileset = intersection ./. ./b; }' 'lib.fileset.intersection: Second argument \('"$work"'/b\) is a path that does not exist.' 614 615 # The tree of later arguments should not be evaluated if a former argument already excludes all files 616 tree=(