at master 32 kB view raw
1/** 2 <!-- This anchor is here for backwards compatibility --> 3 []{#sec-fileset} 4 5 The [`lib.fileset`](#sec-functions-library-fileset) library allows you to work with _file sets_. 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 # Overview {#sec-fileset-overview} 10 11 Basics: 12 - [Implicit coercion from paths to file sets](#sec-fileset-path-coercion) 13 14 - [`lib.fileset.maybeMissing`](#function-library-lib.fileset.maybeMissing): 15 16 Create a file set from a path that may be missing. 17 18 - [`lib.fileset.trace`](#function-library-lib.fileset.trace)/[`lib.fileset.traceVal`](#function-library-lib.fileset.trace): 19 20 Pretty-print file sets for debugging. 21 22 - [`lib.fileset.toSource`](#function-library-lib.fileset.toSource): 23 24 Add files in file sets to the store to use as derivation sources. 25 26 - [`lib.fileset.toList`](#function-library-lib.fileset.toList): 27 28 The list of files contained in a file set. 29 30 Combinators: 31 - [`lib.fileset.union`](#function-library-lib.fileset.union)/[`lib.fileset.unions`](#function-library-lib.fileset.unions): 32 33 Create a larger file set from all the files in multiple file sets. 34 35 - [`lib.fileset.intersection`](#function-library-lib.fileset.intersection): 36 37 Create a smaller file set from only the files in both file sets. 38 39 - [`lib.fileset.difference`](#function-library-lib.fileset.difference): 40 41 Create a smaller file set containing all files that are in one file set, but not another one. 42 43 Filtering: 44 - [`lib.fileset.fileFilter`](#function-library-lib.fileset.fileFilter): 45 46 Create a file set from all files that satisisfy a predicate in a directory. 47 48 Utilities: 49 - [`lib.fileset.fromSource`](#function-library-lib.fileset.fromSource): 50 51 Create a file set from a `lib.sources`-based value. 52 53 - [`lib.fileset.gitTracked`](#function-library-lib.fileset.gitTracked)/[`lib.fileset.gitTrackedWith`](#function-library-lib.fileset.gitTrackedWith): 54 55 Create a file set from all tracked files in a local Git repository. 56 57 If you need more file set functions, 58 see [this issue](https://github.com/NixOS/nixpkgs/issues/266356) to request it. 59 60 # Implicit coercion from paths to file sets {#sec-fileset-path-coercion} 61 62 All functions accepting file sets as arguments can also accept [paths](https://nixos.org/manual/nix/stable/language/values.html#type-path) as arguments. 63 Such path arguments are implicitly coerced to file sets containing all files under that path: 64 - A path to a file turns into a file set containing that single file. 65 - A path to a directory turns into a file set containing all files _recursively_ in that directory. 66 67 If the path points to a non-existent location, an error is thrown. 68 69 ::: {.note} 70 Just like in Git, file sets cannot represent empty directories. 71 Because of this, a path to a directory that contains no files (recursively) will turn into a file set containing no files. 72 ::: 73 74 :::{.note} 75 File set coercion does _not_ add any of the files under the coerced paths to the store. 76 Only the [`toSource`](#function-library-lib.fileset.toSource) function adds files to the Nix store, and only those files contained in the `fileset` argument. 77 This is in contrast to using [paths in string interpolation](https://nixos.org/manual/nix/stable/language/values.html#type-path), which does add the entire referenced path to the store. 78 ::: 79 80 ## Example {#sec-fileset-path-coercion-example} 81 82 Assume we are in a local directory with a file hierarchy like this: 83 ``` 84 a/ 85 x (file) 86 b/ 87   y (file) 88 c/ 89    d/ 90 ``` 91 92 Here's a listing of which files get included when different path expressions get coerced to file sets: 93 - `./.` as a file set contains both `a/x` and `a/b/y` (`c/` does not contain any files and is therefore omitted). 94 - `./a` as a file set contains both `a/x` and `a/b/y`. 95 - `./a/x` as a file set contains only `a/x`. 96 - `./a/b` as a file set contains only `a/b/y`. 97 - `./c` as a file set is empty, since neither `c` nor `c/d` contain any files. 98*/ 99{ lib }: 100let 101 102 inherit (import ./internal.nix { inherit lib; }) 103 _coerce 104 _singleton 105 _coerceMany 106 _toSourceFilter 107 _fromSourceFilter 108 _toList 109 _unionMany 110 _fileFilter 111 _printFileset 112 _intersection 113 _difference 114 _fromFetchGit 115 _emptyWithoutBase 116 ; 117 118 inherit (builtins) 119 isBool 120 isList 121 isPath 122 pathExists 123 seq 124 typeOf 125 nixVersion 126 ; 127 128 inherit (lib.lists) 129 elemAt 130 imap0 131 ; 132 133 inherit (lib.path) 134 hasPrefix 135 splitRoot 136 ; 137 138 inherit (lib.strings) 139 isStringLike 140 versionOlder 141 ; 142 143 inherit (lib.filesystem) 144 pathType 145 ; 146 147 inherit (lib.sources) 148 cleanSourceWith 149 ; 150 151 inherit (lib.trivial) 152 isFunction 153 pipe 154 ; 155 156in 157{ 158 159 /** 160 Create a file set from a path that may or may not exist: 161 - If the path does exist, the path is [coerced to a file set](#sec-fileset-path-coercion). 162 - If the path does not exist, a file set containing no files is returned. 163 164 # Inputs 165 166 `path` 167 168 : 1\. Function argument 169 170 # Type 171 172 ``` 173 maybeMissing :: Path -> FileSet 174 ``` 175 176 # Examples 177 :::{.example} 178 ## `lib.fileset.maybeMissing` usage example 179 180 ```nix 181 # All files in the current directory, but excluding main.o if it exists 182 difference ./. (maybeMissing ./main.o) 183 ``` 184 185 ::: 186 */ 187 maybeMissing = 188 path: 189 if !isPath path then 190 if isStringLike path then 191 throw ''lib.fileset.maybeMissing: Argument ("${toString path}") is a string-like value, but it should be a path instead.'' 192 else 193 throw ''lib.fileset.maybeMissing: Argument is of type ${typeOf path}, but it should be a path instead.'' 194 else if !pathExists path then 195 _emptyWithoutBase 196 else 197 _singleton path; 198 199 /** 200 Incrementally evaluate and trace a file set in a pretty way. 201 This function is only intended for debugging purposes. 202 The exact tracing format is unspecified and may change. 203 204 This function takes a final argument to return. 205 In comparison, [`traceVal`](#function-library-lib.fileset.traceVal) returns 206 the given file set argument. 207 208 This variant is useful for tracing file sets in the Nix repl. 209 210 # Inputs 211 212 `fileset` 213 214 : The file set to trace. 215 216 This argument can also be a path, 217 which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 218 219 `val` 220 221 : The value to return. 222 223 # Type 224 225 ``` 226 trace :: FileSet -> Any -> Any 227 ``` 228 229 # Examples 230 :::{.example} 231 ## `lib.fileset.trace` usage example 232 233 ```nix 234 trace (unions [ ./Makefile ./src ./tests/run.sh ]) null 235 => 236 trace: /home/user/src/myProject 237 trace: - Makefile (regular) 238 trace: - src (all files in directory) 239 trace: - tests 240 trace: - run.sh (regular) 241 null 242 ``` 243 244 ::: 245 */ 246 trace = 247 fileset: 248 let 249 # "fileset" would be a better name, but that would clash with the argument name, 250 # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 251 actualFileset = _coerce "lib.fileset.trace: Argument" fileset; 252 in 253 seq (_printFileset actualFileset) (x: x); 254 255 /** 256 Incrementally evaluate and trace a file set in a pretty way. 257 This function is only intended for debugging purposes. 258 The exact tracing format is unspecified and may change. 259 260 This function returns the given file set. 261 In comparison, [`trace`](#function-library-lib.fileset.trace) takes another argument to return. 262 263 This variant is useful for tracing file sets passed as arguments to other functions. 264 265 # Inputs 266 267 `fileset` 268 269 : The file set to trace and return. 270 271 This argument can also be a path, 272 which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 273 274 # Type 275 276 ``` 277 traceVal :: FileSet -> FileSet 278 ``` 279 280 # Examples 281 :::{.example} 282 ## `lib.fileset.traceVal` usage example 283 284 ```nix 285 toSource { 286 root = ./.; 287 fileset = traceVal (unions [ 288 ./Makefile 289 ./src 290 ./tests/run.sh 291 ]); 292 } 293 => 294 trace: /home/user/src/myProject 295 trace: - Makefile (regular) 296 trace: - src (all files in directory) 297 trace: - tests 298 trace: - run.sh (regular) 299 "/nix/store/...-source" 300 ``` 301 302 ::: 303 */ 304 traceVal = 305 fileset: 306 let 307 # "fileset" would be a better name, but that would clash with the argument name, 308 # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 309 actualFileset = _coerce "lib.fileset.traceVal: Argument" fileset; 310 in 311 seq (_printFileset actualFileset) 312 # We could also return the original fileset argument here, 313 # but that would then duplicate work for consumers of the fileset, because then they have to coerce it again 314 actualFileset; 315 316 /** 317 Add the local files contained in `fileset` to the store as a single [store path](https://nixos.org/manual/nix/stable/glossary#gloss-store-path) rooted at `root`. 318 319 The result is the store path as a string-like value, making it usable e.g. as the `src` of a derivation, or in string interpolation: 320 ```nix 321 stdenv.mkDerivation { 322 src = lib.fileset.toSource { ... }; 323 # ... 324 } 325 ``` 326 327 The name of the store path is always `source`. 328 329 # Inputs 330 331 Takes an attribute set with the following attributes 332 333 `root` (Path; _required_) 334 335 : The local directory [path](https://nixos.org/manual/nix/stable/language/values.html#type-path) that will correspond to the root of the resulting store path. 336 Paths in [strings](https://nixos.org/manual/nix/stable/language/values.html#type-string), including Nix store paths, cannot be passed as `root`. 337 `root` has to be a directory. 338 339 :::{.note} 340 Changing `root` only affects the directory structure of the resulting store path, it does not change which files are added to the store. 341 The only way to change which files get added to the store is by changing the `fileset` attribute. 342 ::: 343 344 `fileset` (FileSet; _required_) 345 346 : The file set whose files to import into the store. 347 File sets can be created using other functions in this library. 348 This argument can also be a path, 349 which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 350 351 :::{.note} 352 If a directory does not recursively contain any file, it is omitted from the store path contents. 353 ::: 354 355 # Type 356 357 ``` 358 toSource :: { 359 root :: Path, 360 fileset :: FileSet, 361 } -> SourceLike 362 ``` 363 364 # Examples 365 :::{.example} 366 ## `lib.fileset.toSource` usage example 367 368 ```nix 369 # Import the current directory into the store 370 # but only include files under ./src 371 toSource { 372 root = ./.; 373 fileset = ./src; 374 } 375 => "/nix/store/...-source" 376 377 # Import the current directory into the store 378 # but only include ./Makefile and all files under ./src 379 toSource { 380 root = ./.; 381 fileset = union 382 ./Makefile 383 ./src; 384 } 385 => "/nix/store/...-source" 386 387 # Trying to include a file outside the root will fail 388 toSource { 389 root = ./.; 390 fileset = unions [ 391 ./Makefile 392 ./src 393 ../LICENSE 394 ]; 395 } 396 => <error> 397 398 # The root needs to point to a directory that contains all the files 399 toSource { 400 root = ../.; 401 fileset = unions [ 402 ./Makefile 403 ./src 404 ../LICENSE 405 ]; 406 } 407 => "/nix/store/...-source" 408 409 # The root has to be a local filesystem path 410 toSource { 411 root = "/nix/store/...-source"; 412 fileset = ./.; 413 } 414 => <error> 415 ``` 416 417 ::: 418 */ 419 toSource = 420 { 421 root, 422 fileset, 423 }: 424 let 425 # We cannot rename matched attribute arguments, so let's work around it with an extra `let in` statement 426 filesetArg = fileset; 427 in 428 let 429 fileset = _coerce "lib.fileset.toSource: `fileset`" filesetArg; 430 rootFilesystemRoot = (splitRoot root).root; 431 filesetFilesystemRoot = (splitRoot fileset._internalBase).root; 432 sourceFilter = _toSourceFilter fileset; 433 in 434 if !isPath root then 435 if root ? _isLibCleanSourceWith then 436 throw '' 437 lib.fileset.toSource: `root` is a `lib.sources`-based value, but it should be a path instead. 438 To use a `lib.sources`-based value, convert it to a file set using `lib.fileset.fromSource` and pass it as `fileset`. 439 Note that this only works for sources created from paths.'' 440 else if isStringLike root then 441 throw '' 442 lib.fileset.toSource: `root` (${toString root}) is a string-like value, but it should be a path instead. 443 Paths in strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.'' 444 else 445 throw ''lib.fileset.toSource: `root` is of type ${typeOf root}, but it should be a path instead.'' 446 # Currently all Nix paths have the same filesystem root, but this could change in the future. 447 # See also ../path/README.md 448 else if !fileset._internalIsEmptyWithoutBase && rootFilesystemRoot != filesetFilesystemRoot then 449 throw '' 450 lib.fileset.toSource: Filesystem roots are not the same for `fileset` and `root` (${toString root}): 451 `root`: Filesystem root is "${toString rootFilesystemRoot}" 452 `fileset`: Filesystem root is "${toString filesetFilesystemRoot}" 453 Different filesystem roots are not supported.'' 454 else if !pathExists root then 455 throw ''lib.fileset.toSource: `root` (${toString root}) is a path that does not exist.'' 456 else if pathType root != "directory" then 457 throw '' 458 lib.fileset.toSource: `root` (${toString root}) is a file, but it should be a directory instead. Potential solutions: 459 - If you want to import the file into the store _without_ a containing directory, use string interpolation or `builtins.path` instead of this function. 460 - If you want to import the file into the store _with_ a containing directory, set `root` to the containing directory, such as ${toString (dirOf root)}, and set `fileset` to the file path.'' 461 else if !fileset._internalIsEmptyWithoutBase && !hasPrefix root fileset._internalBase then 462 throw '' 463 lib.fileset.toSource: `fileset` could contain files in ${toString fileset._internalBase}, which is not under the `root` (${toString root}). Potential solutions: 464 - Set `root` to ${toString fileset._internalBase} or any directory higher up. This changes the layout of the resulting store path. 465 - Set `fileset` to a file set that cannot contain files outside the `root` (${toString root}). This could change the files included in the result.'' 466 else 467 seq sourceFilter cleanSourceWith { 468 name = "source"; 469 src = root; 470 filter = sourceFilter; 471 }; 472 473 /** 474 The list of file paths contained in the given file set. 475 476 :::{.note} 477 This function is strict in the entire file set. 478 This is in contrast with combinators [`lib.fileset.union`](#function-library-lib.fileset.union), 479 [`lib.fileset.intersection`](#function-library-lib.fileset.intersection) and [`lib.fileset.difference`](#function-library-lib.fileset.difference). 480 481 Thus it is recommended to call `toList` on file sets created using the combinators, 482 instead of doing list processing on the result of `toList`. 483 ::: 484 485 The resulting list of files can be turned back into a file set using [`lib.fileset.unions`](#function-library-lib.fileset.unions). 486 487 # Inputs 488 489 `fileset` 490 491 : The file set whose file paths to return. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 492 493 # Type 494 495 ``` 496 toList :: FileSet -> [ Path ] 497 ``` 498 499 # Examples 500 :::{.example} 501 ## `lib.fileset.toList` usage example 502 503 ```nix 504 toList ./. 505 [ ./README.md ./Makefile ./src/main.c ./src/main.h ] 506 507 toList (difference ./. ./src) 508 [ ./README.md ./Makefile ] 509 ``` 510 511 ::: 512 */ 513 toList = fileset: _toList (_coerce "lib.fileset.toList: Argument" fileset); 514 515 /** 516 The file set containing all files that are in either of two given file sets. 517 This is the same as [`unions`](#function-library-lib.fileset.unions), 518 but takes just two file sets instead of a list. 519 See also [Union (set theory)](https://en.wikipedia.org/wiki/Union_(set_theory)). 520 521 The given file sets are evaluated as lazily as possible, 522 with the first argument being evaluated first if needed. 523 524 # Inputs 525 526 `fileset1` 527 528 : The first file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 529 530 `fileset2` 531 532 : The second file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 533 534 # Type 535 536 ``` 537 union :: FileSet -> FileSet -> FileSet 538 ``` 539 540 # Examples 541 :::{.example} 542 ## `lib.fileset.union` usage example 543 544 ```nix 545 # Create a file set containing the file `Makefile` 546 # and all files recursively in the `src` directory 547 union ./Makefile ./src 548 549 # Create a file set containing the file `Makefile` 550 # and the LICENSE file from the parent directory 551 union ./Makefile ../LICENSE 552 ``` 553 554 ::: 555 */ 556 union = 557 fileset1: fileset2: 558 _unionMany ( 559 _coerceMany "lib.fileset.union" [ 560 { 561 context = "First argument"; 562 value = fileset1; 563 } 564 { 565 context = "Second argument"; 566 value = fileset2; 567 } 568 ] 569 ); 570 571 /** 572 The file set containing all files that are in any of the given file sets. 573 This is the same as [`union`](#function-library-lib.fileset.unions), 574 but takes a list of file sets instead of just two. 575 See also [Union (set theory)](https://en.wikipedia.org/wiki/Union_(set_theory)). 576 577 The given file sets are evaluated as lazily as possible, 578 with earlier elements being evaluated first if needed. 579 580 # Inputs 581 582 `filesets` 583 584 : A list of file sets. The elements can also be paths, which get [implicitly coerced to file sets](#sec-fileset-path-coercion). 585 586 # Type 587 588 ``` 589 unions :: [ FileSet ] -> FileSet 590 ``` 591 592 # Examples 593 :::{.example} 594 ## `lib.fileset.unions` usage example 595 596 ```nix 597 # Create a file set containing selected files 598 unions [ 599 # Include the single file `Makefile` in the current directory 600 # This errors if the file doesn't exist 601 ./Makefile 602 603 # Recursively include all files in the `src/code` directory 604 # If this directory is empty this has no effect 605 ./src/code 606 607 # Include the files `run.sh` and `unit.c` from the `tests` directory 608 ./tests/run.sh 609 ./tests/unit.c 610 611 # Include the `LICENSE` file from the parent directory 612 ../LICENSE 613 ] 614 ``` 615 616 ::: 617 */ 618 unions = 619 filesets: 620 if !isList filesets then 621 throw ''lib.fileset.unions: Argument is of type ${typeOf filesets}, but it should be a list instead.'' 622 else 623 pipe filesets [ 624 # Annotate the elements with context, used by _coerceMany for better errors 625 (imap0 ( 626 i: el: { 627 context = "Element ${toString i}"; 628 value = el; 629 } 630 )) 631 (_coerceMany "lib.fileset.unions") 632 _unionMany 633 ]; 634 635 /** 636 The file set containing all files that are in both of two given file sets. 637 See also [Intersection (set theory)](https://en.wikipedia.org/wiki/Intersection_(set_theory)). 638 639 The given file sets are evaluated as lazily as possible, 640 with the first argument being evaluated first if needed. 641 642 # Inputs 643 644 `fileset1` 645 646 : The first file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 647 648 `fileset2` 649 650 : The second file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 651 652 # Type 653 654 ``` 655 intersection :: FileSet -> FileSet -> FileSet 656 ``` 657 658 # Examples 659 :::{.example} 660 ## `lib.fileset.intersection` usage example 661 662 ```nix 663 # Limit the selected files to the ones in ./., so only ./src and ./Makefile 664 intersection ./. (unions [ ../LICENSE ./src ./Makefile ]) 665 ``` 666 667 ::: 668 */ 669 intersection = 670 fileset1: fileset2: 671 let 672 filesets = _coerceMany "lib.fileset.intersection" [ 673 { 674 context = "First argument"; 675 value = fileset1; 676 } 677 { 678 context = "Second argument"; 679 value = fileset2; 680 } 681 ]; 682 in 683 _intersection (elemAt filesets 0) (elemAt filesets 1); 684 685 /** 686 The file set containing all files from the first file set that are not in the second file set. 687 See also [Difference (set theory)](https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement). 688 689 The given file sets are evaluated as lazily as possible, 690 with the first argument being evaluated first if needed. 691 692 # Inputs 693 694 `positive` 695 696 : The positive file set. The result can only contain files that are also in this file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 697 698 `negative` 699 700 : The negative file set. The result will never contain files that are also in this file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). 701 702 # Type 703 704 ``` 705 difference :: FileSet -> FileSet -> FileSet 706 ``` 707 708 # Examples 709 :::{.example} 710 ## `lib.fileset.difference` usage example 711 712 ```nix 713 # Create a file set containing all files from the current directory, 714 # except ones under ./tests 715 difference ./. ./tests 716 717 let 718 # A set of Nix-related files 719 nixFiles = unions [ ./default.nix ./nix ./tests/default.nix ]; 720 in 721 # Create a file set containing all files under ./tests, except ones in `nixFiles`, 722 # meaning only without ./tests/default.nix 723 difference ./tests nixFiles 724 ``` 725 726 ::: 727 */ 728 difference = 729 positive: negative: 730 let 731 filesets = _coerceMany "lib.fileset.difference" [ 732 { 733 context = "First argument (positive set)"; 734 value = positive; 735 } 736 { 737 context = "Second argument (negative set)"; 738 value = negative; 739 } 740 ]; 741 in 742 _difference (elemAt filesets 0) (elemAt filesets 1); 743 744 /** 745 Filter a file set to only contain files matching some predicate. 746 747 # Inputs 748 749 `predicate` 750 751 : The predicate function to call on all files contained in given file set. 752 A file is included in the resulting file set if this function returns true for it. 753 754 This function is called with an attribute set containing these attributes: 755 756 - `name` (String): The name of the file 757 758 - `type` (String, one of `"regular"`, `"symlink"` or `"unknown"`): The type of the file. 759 This matches result of calling [`builtins.readFileType`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-readFileType) on the file's path. 760 761 - `hasExt` (String -> Bool): Whether the file has a certain file extension. 762 `hasExt ext` is true only if `hasSuffix ".${ext}" name`. 763 764 This also means that e.g. for a file with name `.gitignore`, 765 `hasExt "gitignore"` is true. 766 767 Other attributes may be added in the future. 768 769 `path` 770 771 : The path whose files to filter 772 773 # Type 774 775 ``` 776 fileFilter :: 777 ({ 778 name :: String, 779 type :: String, 780 hasExt :: String -> Bool, 781 ... 782 } -> Bool) 783 -> Path 784 -> FileSet 785 ``` 786 787 # Examples 788 :::{.example} 789 ## `lib.fileset.fileFilter` usage example 790 791 ```nix 792 # Include all regular `default.nix` files in the current directory 793 fileFilter (file: file.name == "default.nix") ./. 794 795 # Include all non-Nix files from the current directory 796 fileFilter (file: ! file.hasExt "nix") ./. 797 798 # Include all files that start with a "." in the current directory 799 fileFilter (file: hasPrefix "." file.name) ./. 800 801 # Include all regular files (not symlinks or others) in the current directory 802 fileFilter (file: file.type == "regular") ./. 803 ``` 804 805 ::: 806 */ 807 fileFilter = 808 predicate: path: 809 if !isFunction predicate then 810 throw ''lib.fileset.fileFilter: First argument is of type ${typeOf predicate}, but it should be a function instead.'' 811 else if !isPath path then 812 if path._type or "" == "fileset" then 813 throw '' 814 lib.fileset.fileFilter: Second argument is a file set, but it should be a path instead. 815 If you need to filter files in a file set, use `intersection fileset (fileFilter pred ./.)` instead.'' 816 else 817 throw ''lib.fileset.fileFilter: Second argument is of type ${typeOf path}, but it should be a path instead.'' 818 else if !pathExists path then 819 throw ''lib.fileset.fileFilter: Second argument (${toString path}) is a path that does not exist.'' 820 else 821 _fileFilter predicate path; 822 823 /** 824 Create a file set with the same files as a `lib.sources`-based value. 825 This does not import any of the files into the store. 826 827 This can be used to gradually migrate from `lib.sources`-based filtering to `lib.fileset`. 828 829 A file set can be turned back into a source using [`toSource`](#function-library-lib.fileset.toSource). 830 831 :::{.note} 832 File sets cannot represent empty directories. 833 Turning the result of this function back into a source using `toSource` will therefore not preserve empty directories. 834 ::: 835 836 # Inputs 837 838 `source` 839 840 : 1\. Function argument 841 842 # Type 843 844 ``` 845 fromSource :: SourceLike -> FileSet 846 ``` 847 848 # Examples 849 :::{.example} 850 ## `lib.fileset.fromSource` usage example 851 852 ```nix 853 # There's no cleanSource-like function for file sets yet, 854 # but we can just convert cleanSource to a file set and use it that way 855 toSource { 856 root = ./.; 857 fileset = fromSource (lib.sources.cleanSource ./.); 858 } 859 860 # Keeping a previous sourceByRegex (which could be migrated to `lib.fileset.unions`), 861 # but removing a subdirectory using file set functions 862 difference 863 (fromSource (lib.sources.sourceByRegex ./. [ 864 "^README\.md$" 865 # This regex includes everything in ./doc 866 "^doc(/.*)?$" 867 ]) 868 ./doc/generated 869 870 # Use cleanSource, but limit it to only include ./Makefile and files under ./src 871 intersection 872 (fromSource (lib.sources.cleanSource ./.)) 873 (unions [ 874 ./Makefile 875 ./src 876 ]); 877 ``` 878 879 ::: 880 */ 881 fromSource = 882 source: 883 let 884 # This function uses `._isLibCleanSourceWith`, `.origSrc` and `.filter`, 885 # which are technically internal to lib.sources, 886 # but we'll allow this since both libraries are in the same code base 887 # and this function is a bridge between them. 888 isFiltered = source ? _isLibCleanSourceWith; 889 path = if isFiltered then source.origSrc else source; 890 in 891 # We can only support sources created from paths 892 if !isPath path then 893 if isStringLike path then 894 throw '' 895 lib.fileset.fromSource: The source origin of the argument is a string-like value ("${toString path}"), but it should be a path instead. 896 Sources created from paths in strings cannot be turned into file sets, use `lib.sources` or derivations instead.'' 897 else 898 throw ''lib.fileset.fromSource: The source origin of the argument is of type ${typeOf path}, but it should be a path instead.'' 899 else if !pathExists path then 900 throw ''lib.fileset.fromSource: The source origin (${toString path}) of the argument is a path that does not exist.'' 901 else if isFiltered then 902 _fromSourceFilter path source.filter 903 else 904 # If there's no filter, no need to run the expensive conversion, all subpaths will be included 905 _singleton path; 906 907 /** 908 Create a file set containing all [Git-tracked files](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) in a repository. 909 910 This function behaves like [`gitTrackedWith { }`](#function-library-lib.fileset.gitTrackedWith) - using the defaults. 911 912 # Inputs 913 914 `path` 915 916 : The [path](https://nixos.org/manual/nix/stable/language/values#type-path) to the working directory of a local Git repository. 917 This directory must contain a `.git` file or subdirectory. 918 919 # Type 920 921 ``` 922 gitTracked :: Path -> FileSet 923 ``` 924 925 # Examples 926 :::{.example} 927 ## `lib.fileset.gitTracked` usage example 928 929 ```nix 930 # Include all files tracked by the Git repository in the current directory 931 gitTracked ./. 932 933 # Include only files tracked by the Git repository in the parent directory 934 # that are also in the current directory 935 intersection ./. (gitTracked ../.) 936 ``` 937 938 ::: 939 */ 940 gitTracked = path: _fromFetchGit "gitTracked" "argument" path { }; 941 942 /** 943 Create a file set containing all [Git-tracked files](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) in a repository. 944 The first argument allows configuration with an attribute set, 945 while the second argument is the path to the Git working tree. 946 947 `gitTrackedWith` does not perform any filtering when the path is a [Nix store path](https://nixos.org/manual/nix/stable/store/store-path.html#store-path) and not a repository. 948 In this way, it accommodates the use case where the expression that makes the `gitTracked` call does not reside in an actual git repository anymore, 949 and has presumably already been fetched in a way that excludes untracked files. 950 Fetchers with such equivalent behavior include `builtins.fetchGit`, `builtins.fetchTree` (experimental), and `pkgs.fetchgit` when used without `leaveDotGit`. 951 952 If you don't need the configuration, 953 you can use [`gitTracked`](#function-library-lib.fileset.gitTracked) instead. 954 955 This is equivalent to the result of [`unions`](#function-library-lib.fileset.unions) on all files returned by [`git ls-files`](https://git-scm.com/docs/git-ls-files) 956 (which uses [`--cached`](https://git-scm.com/docs/git-ls-files#Documentation/git-ls-files.txt--c) by default). 957 958 :::{.warning} 959 Currently this function is based on [`builtins.fetchGit`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-fetchGit) 960 As such, this function causes all Git-tracked files to be unnecessarily added to the Nix store, 961 without being re-usable by [`toSource`](#function-library-lib.fileset.toSource). 962 963 This may change in the future. 964 ::: 965 966 # Inputs 967 968 `options` (attribute set) 969 : `recurseSubmodules` (optional, default: `false`) 970 : Whether to recurse into [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to also include their tracked files. 971 If `true`, this is equivalent to passing the [--recurse-submodules](https://git-scm.com/docs/git-ls-files#Documentation/git-ls-files.txt---recurse-submodules) flag to `git ls-files`. 972 973 `path` 974 : The [path](https://nixos.org/manual/nix/stable/language/values#type-path) to the working directory of a local Git repository. 975 This directory must contain a `.git` file or subdirectory. 976 977 # Type 978 979 ``` 980 gitTrackedWith :: { recurseSubmodules :: Bool ? false } -> Path -> FileSet 981 ``` 982 983 # Examples 984 :::{.example} 985 ## `lib.fileset.gitTrackedWith` usage example 986 987 ```nix 988 # Include all files tracked by the Git repository in the current directory 989 # and any submodules under it 990 gitTracked { recurseSubmodules = true; } ./. 991 ``` 992 993 ::: 994 */ 995 gitTrackedWith = 996 { 997 recurseSubmodules ? false, 998 }: 999 path: 1000 if !isBool recurseSubmodules then 1001 throw "lib.fileset.gitTrackedWith: Expected the attribute `recurseSubmodules` of the first argument to be a boolean, but it's a ${typeOf recurseSubmodules} instead." 1002 else 1003 _fromFetchGit "gitTrackedWith" "second argument" path 1004 # This is the only `fetchGit` parameter that makes sense in this context. 1005 { 1006 submodules = recurseSubmodules; 1007 }; 1008}