at master 52 kB view raw
1/** 2 Operations on attribute sets. 3*/ 4{ lib }: 5 6let 7 inherit (builtins) head length typeOf; 8 inherit (lib.asserts) assertMsg; 9 inherit (lib.trivial) 10 oldestSupportedReleaseIsAtLeast 11 mergeAttrs 12 warn 13 warnIf 14 ; 15 inherit (lib.strings) 16 concatStringsSep 17 concatMapStringsSep 18 escapeNixIdentifier 19 sanitizeDerivationName 20 ; 21 inherit (lib.lists) 22 filter 23 foldr 24 foldl' 25 concatMap 26 elemAt 27 all 28 partition 29 groupBy 30 take 31 foldl 32 ; 33in 34 35rec { 36 inherit (builtins) 37 attrNames 38 listToAttrs 39 hasAttr 40 isAttrs 41 getAttr 42 removeAttrs 43 intersectAttrs 44 ; 45 46 /** 47 Return an attribute from nested attribute sets. 48 49 Nix has an [attribute selection operator `.`](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example: 50 51 ```nix 52 (x.a.b or 6) == attrByPath ["a" "b"] 6 x 53 # and 54 (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x 55 ``` 56 57 # Inputs 58 59 `attrPath` 60 61 : A list of strings representing the attribute path to return from `set` 62 63 `default` 64 65 : Default value if `attrPath` does not resolve to an existing value 66 67 `set` 68 69 : The nested attribute set to select values from 70 71 # Type 72 73 ``` 74 attrByPath :: [String] -> Any -> AttrSet -> Any 75 ``` 76 77 # Examples 78 :::{.example} 79 ## `lib.attrsets.attrByPath` usage example 80 81 ```nix 82 x = { a = { b = 3; }; } 83 # ["a" "b"] is equivalent to x.a.b 84 # 6 is a default value to return if the path does not exist in attrset 85 attrByPath ["a" "b"] 6 x 86 => 3 87 attrByPath ["z" "z"] 6 x 88 => 6 89 ``` 90 91 ::: 92 */ 93 attrByPath = 94 attrPath: default: set: 95 let 96 lenAttrPath = length attrPath; 97 attrByPath' = 98 n: s: 99 ( 100 if n == lenAttrPath then 101 s 102 else 103 ( 104 let 105 attr = elemAt attrPath n; 106 in 107 if s ? ${attr} then attrByPath' (n + 1) s.${attr} else default 108 ) 109 ); 110 in 111 attrByPath' 0 set; 112 113 /** 114 Return if an attribute from nested attribute set exists. 115 116 Nix has a [has attribute operator `?`](https://nixos.org/manual/nix/stable/language/operators#has-attribute), which is sufficient for such queries, as long as the number of attributes is static. For example: 117 118 ```nix 119 (x?a.b) == hasAttrByPath ["a" "b"] x 120 # and 121 (x?${f p}."example.com") == hasAttrByPath [ (f p) "example.com" ] x 122 ``` 123 124 **Laws**: 125 1. ```nix 126 hasAttrByPath [] x == true 127 ``` 128 129 # Inputs 130 131 `attrPath` 132 133 : A list of strings representing the attribute path to check from `set` 134 135 `e` 136 137 : The nested attribute set to check 138 139 # Type 140 141 ``` 142 hasAttrByPath :: [String] -> AttrSet -> Bool 143 ``` 144 145 # Examples 146 :::{.example} 147 ## `lib.attrsets.hasAttrByPath` usage example 148 149 ```nix 150 x = { a = { b = 3; }; } 151 hasAttrByPath ["a" "b"] x 152 => true 153 hasAttrByPath ["z" "z"] x 154 => false 155 hasAttrByPath [] (throw "no need") 156 => true 157 ``` 158 159 ::: 160 */ 161 hasAttrByPath = 162 attrPath: e: 163 let 164 lenAttrPath = length attrPath; 165 hasAttrByPath' = 166 n: s: 167 ( 168 n == lenAttrPath 169 || ( 170 let 171 attr = elemAt attrPath n; 172 in 173 if s ? ${attr} then hasAttrByPath' (n + 1) s.${attr} else false 174 ) 175 ); 176 in 177 hasAttrByPath' 0 e; 178 179 /** 180 Return the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets. 181 182 Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition, 183 although this will evaluate the predicate function on sibling attributes as well. 184 185 Note that the empty attribute path is valid for all values, so this function only throws an exception if any of its inputs does. 186 187 **Laws**: 188 1. ```nix 189 attrsets.longestValidPathPrefix [] x == [] 190 ``` 191 192 2. ```nix 193 hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true 194 ``` 195 196 # Inputs 197 198 `attrPath` 199 200 : A list of strings representing the longest possible path that may be returned. 201 202 `v` 203 204 : The nested attribute set to check. 205 206 # Type 207 208 ``` 209 attrsets.longestValidPathPrefix :: [String] -> Value -> [String] 210 ``` 211 212 # Examples 213 :::{.example} 214 ## `lib.attrsets.longestValidPathPrefix` usage example 215 216 ```nix 217 x = { a = { b = 3; }; } 218 attrsets.longestValidPathPrefix ["a" "b" "c"] x 219 => ["a" "b"] 220 attrsets.longestValidPathPrefix ["a"] x 221 => ["a"] 222 attrsets.longestValidPathPrefix ["z" "z"] x 223 => [] 224 attrsets.longestValidPathPrefix ["z" "z"] (throw "no need") 225 => [] 226 ``` 227 228 ::: 229 */ 230 longestValidPathPrefix = 231 attrPath: v: 232 let 233 lenAttrPath = length attrPath; 234 getPrefixForSetAtIndex = 235 # The nested attribute set to check, if it is an attribute set, which 236 # is not a given. 237 remainingSet: 238 # The index of the attribute we're about to check, as well as 239 # the length of the prefix we've already checked. 240 remainingPathIndex: 241 242 if remainingPathIndex == lenAttrPath then 243 # All previously checked attributes exist, and no attr names left, 244 # so we return the whole path. 245 attrPath 246 else 247 let 248 attr = elemAt attrPath remainingPathIndex; 249 in 250 if remainingSet ? ${attr} then 251 getPrefixForSetAtIndex remainingSet.${attr} # advance from the set to the attribute value 252 (remainingPathIndex + 1) # advance the path 253 else 254 # The attribute doesn't exist, so we return the prefix up to the 255 # previously checked length. 256 take remainingPathIndex attrPath; 257 in 258 getPrefixForSetAtIndex v 0; 259 260 /** 261 Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. 262 263 # Inputs 264 265 `attrPath` 266 267 : A list of strings representing the attribute path to set 268 269 `value` 270 271 : The value to set at the location described by `attrPath` 272 273 # Type 274 275 ``` 276 setAttrByPath :: [String] -> Any -> AttrSet 277 ``` 278 279 # Examples 280 :::{.example} 281 ## `lib.attrsets.setAttrByPath` usage example 282 283 ```nix 284 setAttrByPath ["a" "b"] 3 285 => { a = { b = 3; }; } 286 ``` 287 288 ::: 289 */ 290 setAttrByPath = 291 attrPath: value: 292 let 293 len = length attrPath; 294 atDepth = n: if n == len then value else { ${elemAt attrPath n} = atDepth (n + 1); }; 295 in 296 atDepth 0; 297 298 /** 299 Like `attrByPath`, but without a default value. If it doesn't find the 300 path it will throw an error. 301 302 Nix has an [attribute selection operator](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example: 303 304 ```nix 305 x.a.b == getAttrFromPath ["a" "b"] x 306 # and 307 x.${f p}."example.com" == getAttrFromPath [ (f p) "example.com" ] x 308 ``` 309 310 # Inputs 311 312 `attrPath` 313 314 : A list of strings representing the attribute path to get from `set` 315 316 `set` 317 318 : The nested attribute set to find the value in. 319 320 # Type 321 322 ``` 323 getAttrFromPath :: [String] -> AttrSet -> Any 324 ``` 325 326 # Examples 327 :::{.example} 328 ## `lib.attrsets.getAttrFromPath` usage example 329 330 ```nix 331 x = { a = { b = 3; }; } 332 getAttrFromPath ["a" "b"] x 333 => 3 334 getAttrFromPath ["z" "z"] x 335 => error: cannot find attribute `z.z' 336 ``` 337 338 ::: 339 */ 340 getAttrFromPath = 341 attrPath: set: 342 attrByPath attrPath (abort ("cannot find attribute '" + concatStringsSep "." attrPath + "'")) set; 343 344 /** 345 Map each attribute in the given set and merge them into a new attribute set. 346 347 # Inputs 348 349 `f` 350 351 : 1\. Function argument 352 353 `v` 354 355 : 2\. Function argument 356 357 # Type 358 359 ``` 360 concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet 361 ``` 362 363 # Examples 364 :::{.example} 365 ## `lib.attrsets.concatMapAttrs` usage example 366 367 ```nix 368 concatMapAttrs 369 (name: value: { 370 ${name} = value; 371 ${name + value} = value; 372 }) 373 { x = "a"; y = "b"; } 374 => { x = "a"; xa = "a"; y = "b"; yb = "b"; } 375 ``` 376 377 ::: 378 */ 379 concatMapAttrs = f: v: foldl' mergeAttrs { } (attrValues (mapAttrs f v)); 380 381 /** 382 Update or set specific paths of an attribute set. 383 384 Takes a list of updates to apply and an attribute set to apply them to, 385 and returns the attribute set with the updates applied. Updates are 386 represented as `{ path = ...; update = ...; }` values, where `path` is a 387 list of strings representing the attribute path that should be updated, 388 and `update` is a function that takes the old value at that attribute path 389 as an argument and returns the new 390 value it should be. 391 392 Properties: 393 394 - Updates to deeper attribute paths are applied before updates to more 395 shallow attribute paths 396 397 - Multiple updates to the same attribute path are applied in the order 398 they appear in the update list 399 400 - If any but the last `path` element leads into a value that is not an 401 attribute set, an error is thrown 402 403 - If there is an update for an attribute path that doesn't exist, 404 accessing the argument in the update function causes an error, but 405 intermediate attribute sets are implicitly created as needed 406 407 # Type 408 409 ``` 410 updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet 411 ``` 412 413 # Examples 414 :::{.example} 415 ## `lib.attrsets.updateManyAttrsByPath` usage example 416 417 ```nix 418 updateManyAttrsByPath [ 419 { 420 path = [ "a" "b" ]; 421 update = old: { d = old.c; }; 422 } 423 { 424 path = [ "a" "b" "c" ]; 425 update = old: old + 1; 426 } 427 { 428 path = [ "x" "y" ]; 429 update = old: "xy"; 430 } 431 ] { a.b.c = 0; } 432 => { a = { b = { d = 1; }; }; x = { y = "xy"; }; } 433 ``` 434 435 ::: 436 */ 437 updateManyAttrsByPath = 438 let 439 # When recursing into attributes, instead of updating the `path` of each 440 # update using `tail`, which needs to allocate an entirely new list, 441 # we just pass a prefix length to use and make sure to only look at the 442 # path without the prefix length, so that we can reuse the original list 443 # entries. 444 go = 445 prefixLength: hasValue: value: updates: 446 let 447 # Splits updates into ones on this level (split.right) 448 # And ones on levels further down (split.wrong) 449 split = partition (el: length el.path == prefixLength) updates; 450 451 # Groups updates on further down levels into the attributes they modify 452 nested = groupBy (el: elemAt el.path prefixLength) split.wrong; 453 454 # Applies only nested modification to the input value 455 withNestedMods = 456 # Return the value directly if we don't have any nested modifications 457 if split.wrong == [ ] then 458 if hasValue then 459 value 460 else 461 # Throw an error if there is no value. This `head` call here is 462 # safe, but only in this branch since `go` could only be called 463 # with `hasValue == false` for nested updates, in which case 464 # it's also always called with at least one update 465 let 466 updatePath = (head split.right).path; 467 in 468 throw ( 469 "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does " 470 + "not exist in the given value, but the first update to this " 471 + "path tries to access the existing value." 472 ) 473 else 474 # If there are nested modifications, try to apply them to the value 475 if !hasValue then 476 # But if we don't have a value, just use an empty attribute set 477 # as the value, but simplify the code a bit 478 mapAttrs (name: go (prefixLength + 1) false null) nested 479 else if isAttrs value then 480 # If we do have a value and it's an attribute set, override it 481 # with the nested modifications 482 value // mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested 483 else 484 # However if it's not an attribute set, we can't apply the nested 485 # modifications, throw an error 486 let 487 updatePath = (head split.wrong).path; 488 in 489 throw ( 490 "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to " 491 + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' " 492 + "of the given value is not an attribute set, so we can't " 493 + "update an attribute inside of it." 494 ); 495 496 # We get the final result by applying all the updates on this level 497 # after having applied all the nested updates 498 # We use foldl instead of foldl' so that in case of multiple updates, 499 # intermediate values aren't evaluated if not needed 500 in 501 foldl (acc: el: el.update acc) withNestedMods split.right; 502 503 in 504 updates: value: go 0 true value updates; 505 506 /** 507 Return the specified attributes from a set. 508 509 # Inputs 510 511 `nameList` 512 513 : The list of attributes to fetch from `set`. Each attribute name must exist on the attribute set 514 515 `set` 516 517 : The set to get attribute values from 518 519 # Type 520 521 ``` 522 attrVals :: [String] -> AttrSet -> [Any] 523 ``` 524 525 # Examples 526 :::{.example} 527 ## `lib.attrsets.attrVals` usage example 528 529 ```nix 530 attrVals ["a" "b" "c"] as 531 => [as.a as.b as.c] 532 ``` 533 534 ::: 535 */ 536 attrVals = nameList: set: map (x: set.${x}) nameList; 537 538 /** 539 Return the values of all attributes in the given set, sorted by 540 attribute name. 541 542 # Type 543 544 ``` 545 attrValues :: AttrSet -> [Any] 546 ``` 547 548 # Examples 549 :::{.example} 550 ## `lib.attrsets.attrValues` usage example 551 552 ```nix 553 attrValues {c = 3; a = 1; b = 2;} 554 => [1 2 3] 555 ``` 556 557 ::: 558 */ 559 attrValues = builtins.attrValues; 560 561 /** 562 Given a set of attribute names, return the set of the corresponding 563 attributes from the given set. 564 565 # Inputs 566 567 `names` 568 569 : A list of attribute names to get out of `set` 570 571 `attrs` 572 573 : The set to get the named attributes from 574 575 # Type 576 577 ``` 578 getAttrs :: [String] -> AttrSet -> AttrSet 579 ``` 580 581 # Examples 582 :::{.example} 583 ## `lib.attrsets.getAttrs` usage example 584 585 ```nix 586 getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; } 587 => { a = 1; b = 2; } 588 ``` 589 590 ::: 591 */ 592 getAttrs = names: attrs: genAttrs names (name: attrs.${name}); 593 594 /** 595 Collect each attribute named `attr` from a list of attribute 596 sets. Sets that don't contain the named attribute are ignored. 597 598 # Inputs 599 600 `attr` 601 602 : The attribute name to get out of the sets. 603 604 `list` 605 606 : The list of attribute sets to go through 607 608 # Type 609 610 ``` 611 catAttrs :: String -> [AttrSet] -> [Any] 612 ``` 613 614 # Examples 615 :::{.example} 616 ## `lib.attrsets.catAttrs` usage example 617 618 ```nix 619 catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}] 620 => [1 2] 621 ``` 622 623 ::: 624 */ 625 catAttrs = builtins.catAttrs; 626 627 /** 628 Filter an attribute set by removing all attributes for which the 629 given predicate return false. 630 631 # Inputs 632 633 `pred` 634 635 : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. 636 637 <!-- TIP --> 638 If possible, decide on `name` first and on `value` only if necessary. 639 This avoids evaluating the value if the name is already enough, making it possible, potentially, to have the argument reference the return value. 640 (Depending on context, that could still be considered a self reference by users; a common pattern in Nix.) 641 642 <!-- TIP --> 643 `filterAttrs` is occasionally the cause of infinite recursion in configuration systems that allow self-references. 644 To support the widest range of user-provided logic, perform the `filterAttrs` call as late as possible. 645 Typically that's right before using it in a derivation, as opposed to an implicit conversion whose result is accessible to the user's expressions. 646 647 `set` 648 649 : The attribute set to filter 650 651 # Type 652 653 ``` 654 filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet 655 ``` 656 657 # Examples 658 :::{.example} 659 ## `lib.attrsets.filterAttrs` usage example 660 661 ```nix 662 filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; } 663 => { foo = 1; } 664 ``` 665 666 ::: 667 */ 668 filterAttrs = pred: set: removeAttrs set (filter (name: !pred name set.${name}) (attrNames set)); 669 670 /** 671 Filter an attribute set recursively by removing all attributes for 672 which the given predicate return false. 673 674 # Inputs 675 676 `pred` 677 678 : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. 679 680 `set` 681 682 : The attribute set to filter 683 684 # Type 685 686 ``` 687 filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet 688 ``` 689 690 # Examples 691 :::{.example} 692 ## `lib.attrsets.filterAttrsRecursive` usage example 693 694 ```nix 695 filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; } 696 => { foo = {}; } 697 ``` 698 699 ::: 700 */ 701 filterAttrsRecursive = 702 pred: set: 703 listToAttrs ( 704 concatMap ( 705 name: 706 let 707 v = set.${name}; 708 in 709 if pred name v then 710 [ 711 (nameValuePair name (if isAttrs v then filterAttrsRecursive pred v else v)) 712 ] 713 else 714 [ ] 715 ) (attrNames set) 716 ); 717 718 /** 719 Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets. 720 Iterates over every name-value pair in the given attribute set. 721 The result of the callback function is often called `acc` for accumulator. It is passed between callbacks from left to right and the final `acc` is the return value of `foldlAttrs`. 722 723 Attention: 724 725 There is a completely different function `lib.foldAttrs` 726 which has nothing to do with this function, despite the similar name. 727 728 # Inputs 729 730 `f` 731 732 : 1\. Function argument 733 734 `init` 735 736 : 2\. Function argument 737 738 `set` 739 740 : 3\. Function argument 741 742 # Type 743 744 ``` 745 foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a 746 ``` 747 748 # Examples 749 :::{.example} 750 ## `lib.attrsets.foldlAttrs` usage example 751 752 ```nix 753 foldlAttrs 754 (acc: name: value: { 755 sum = acc.sum + value; 756 names = acc.names ++ [name]; 757 }) 758 { sum = 0; names = []; } 759 { 760 foo = 1; 761 bar = 10; 762 } 763 -> 764 { 765 sum = 11; 766 names = ["bar" "foo"]; 767 } 768 769 foldlAttrs 770 (throw "function not needed") 771 123 772 {}; 773 -> 774 123 775 776 foldlAttrs 777 (acc: _: _: acc) 778 3 779 { z = throw "value not needed"; a = throw "value not needed"; }; 780 -> 781 3 782 783 The accumulator doesn't have to be an attrset. 784 It can be as simple as a number or string. 785 786 foldlAttrs 787 (acc: _: v: acc * 10 + v) 788 1 789 { z = 1; a = 2; }; 790 -> 791 121 792 ``` 793 794 ::: 795 */ 796 foldlAttrs = 797 f: init: set: 798 foldl' (acc: name: f acc name set.${name}) init (attrNames set); 799 800 /** 801 Apply fold functions to values grouped by key. 802 803 # Inputs 804 805 `op` 806 807 : A function, given a value and a collector combines the two. 808 809 `nul` 810 811 : The starting value. 812 813 `list_of_attrs` 814 815 : A list of attribute sets to fold together by key. 816 817 # Type 818 819 ``` 820 foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any 821 ``` 822 823 # Examples 824 :::{.example} 825 ## `lib.attrsets.foldAttrs` usage example 826 827 ```nix 828 foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }] 829 => { a = [ 2 3 ]; } 830 ``` 831 832 ::: 833 */ 834 foldAttrs = 835 op: nul: list_of_attrs: 836 foldr ( 837 n: a: foldr (name: o: o // { ${name} = op n.${name} (a.${name} or nul); }) a (attrNames n) 838 ) { } list_of_attrs; 839 840 /** 841 Recursively collect sets that verify a given predicate named `pred` 842 from the set `attrs`. The recursion is stopped when the predicate is 843 verified. 844 845 # Inputs 846 847 `pred` 848 849 : Given an attribute's value, determine if recursion should stop. 850 851 `attrs` 852 853 : The attribute set to recursively collect. 854 855 # Type 856 857 ``` 858 collect :: (AttrSet -> Bool) -> AttrSet -> [x] 859 ``` 860 861 # Examples 862 :::{.example} 863 ## `lib.attrsets.collect` usage example 864 865 ```nix 866 collect isList { a = { b = ["b"]; }; c = [1]; } 867 => [["b"] [1]] 868 869 collect (x: x ? outPath) 870 { a = { outPath = "a/"; }; b = { outPath = "b/"; }; } 871 => [{ outPath = "a/"; } { outPath = "b/"; }] 872 ``` 873 874 ::: 875 */ 876 collect = 877 pred: attrs: 878 if pred attrs then 879 [ attrs ] 880 else if isAttrs attrs then 881 concatMap (collect pred) (attrValues attrs) 882 else 883 [ ]; 884 885 /** 886 Return the cartesian product of attribute set value combinations. 887 888 # Inputs 889 890 `attrsOfLists` 891 892 : Attribute set with attributes that are lists of values 893 894 # Type 895 896 ``` 897 cartesianProduct :: AttrSet -> [AttrSet] 898 ``` 899 900 # Examples 901 :::{.example} 902 ## `lib.attrsets.cartesianProduct` usage example 903 904 ```nix 905 cartesianProduct { a = [ 1 2 ]; b = [ 10 20 ]; } 906 => [ 907 { a = 1; b = 10; } 908 { a = 1; b = 20; } 909 { a = 2; b = 10; } 910 { a = 2; b = 20; } 911 ] 912 ``` 913 914 ::: 915 */ 916 cartesianProduct = 917 attrsOfLists: 918 foldl' ( 919 listOfAttrs: attrName: 920 concatMap ( 921 attrs: map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName} 922 ) listOfAttrs 923 ) [ { } ] (attrNames attrsOfLists); 924 925 /** 926 Return the result of function f applied to the cartesian product of attribute set value combinations. 927 Equivalent to using cartesianProduct followed by map. 928 929 # Inputs 930 931 `f` 932 933 : A function, given an attribute set, it returns a new value. 934 935 `attrsOfLists` 936 937 : Attribute set with attributes that are lists of values 938 939 # Type 940 941 ``` 942 mapCartesianProduct :: (AttrSet -> a) -> AttrSet -> [a] 943 ``` 944 945 # Examples 946 :::{.example} 947 ## `lib.attrsets.mapCartesianProduct` usage example 948 949 ```nix 950 mapCartesianProduct ({a, b}: "${a}-${b}") { a = [ "1" "2" ]; b = [ "3" "4" ]; } 951 => [ "1-3" "1-4" "2-3" "2-4" ] 952 ``` 953 954 ::: 955 */ 956 mapCartesianProduct = f: attrsOfLists: map f (cartesianProduct attrsOfLists); 957 958 /** 959 Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`. 960 961 # Inputs 962 963 `name` 964 965 : Attribute name 966 967 `value` 968 969 : Attribute value 970 971 # Type 972 973 ``` 974 nameValuePair :: String -> Any -> { name :: String; value :: Any; } 975 ``` 976 977 # Examples 978 :::{.example} 979 ## `lib.attrsets.nameValuePair` usage example 980 981 ```nix 982 nameValuePair "some" 6 983 => { name = "some"; value = 6; } 984 ``` 985 986 ::: 987 */ 988 nameValuePair = name: value: { inherit name value; }; 989 990 /** 991 Apply a function to each element in an attribute set, creating a new attribute set. 992 993 # Inputs 994 995 `f` 996 997 : A function that takes an attribute name and its value, and returns the new value for the attribute. 998 999 `attrset` 1000 1001 : The attribute set to iterate through. 1002 1003 # Type 1004 1005 ``` 1006 mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet 1007 ``` 1008 1009 # Examples 1010 :::{.example} 1011 ## `lib.attrsets.mapAttrs` usage example 1012 1013 ```nix 1014 mapAttrs (name: value: name + "-" + value) 1015 { x = "foo"; y = "bar"; } 1016 => { x = "x-foo"; y = "y-bar"; } 1017 ``` 1018 1019 ::: 1020 */ 1021 mapAttrs = builtins.mapAttrs; 1022 1023 /** 1024 Like `mapAttrs`, but allows the name of each attribute to be 1025 changed in addition to the value. The applied function should 1026 return both the new name and value as a `nameValuePair`. 1027 1028 # Inputs 1029 1030 `f` 1031 1032 : A function, given an attribute's name and value, returns a new `nameValuePair`. 1033 1034 `set` 1035 1036 : Attribute set to map over. 1037 1038 # Type 1039 1040 ``` 1041 mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet 1042 ``` 1043 1044 # Examples 1045 :::{.example} 1046 ## `lib.attrsets.mapAttrs'` usage example 1047 1048 ```nix 1049 mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value)) 1050 { x = "a"; y = "b"; } 1051 => { foo_x = "bar-a"; foo_y = "bar-b"; } 1052 ``` 1053 1054 ::: 1055 */ 1056 mapAttrs' = f: set: listToAttrs (mapAttrsToList f set); 1057 1058 /** 1059 Call a function for each attribute in the given set and return 1060 the result in a list. 1061 1062 # Inputs 1063 1064 `f` 1065 1066 : A function, given an attribute's name and value, returns a new value. 1067 1068 `attrs` 1069 1070 : Attribute set to map over. 1071 1072 # Type 1073 1074 ``` 1075 mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b] 1076 ``` 1077 1078 # Examples 1079 :::{.example} 1080 ## `lib.attrsets.mapAttrsToList` usage example 1081 1082 ```nix 1083 mapAttrsToList (name: value: name + value) 1084 { x = "a"; y = "b"; } 1085 => [ "xa" "yb" ] 1086 ``` 1087 1088 ::: 1089 */ 1090 mapAttrsToList = f: attrs: attrValues (mapAttrs f attrs); 1091 1092 /** 1093 Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs). 1094 Each element of the resulting list is an attribute set with these attributes: 1095 - `name` (string): The name of the attribute 1096 - `value` (any): The value of the attribute 1097 1098 The following is always true: 1099 ```nix 1100 builtins.listToAttrs (attrsToList attrs) == attrs 1101 ``` 1102 1103 :::{.warning} 1104 The opposite is not always true. In general expect that 1105 ```nix 1106 attrsToList (builtins.listToAttrs list) != list 1107 ``` 1108 1109 This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list. 1110 ::: 1111 1112 # Inputs 1113 1114 `set` 1115 1116 : The attribute set to deconstruct. 1117 1118 # Type 1119 1120 ``` 1121 attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ] 1122 ``` 1123 1124 # Examples 1125 :::{.example} 1126 ## `lib.attrsets.attrsToList` usage example 1127 1128 ```nix 1129 attrsToList { foo = 1; bar = "asdf"; } 1130 => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ] 1131 ``` 1132 1133 ::: 1134 */ 1135 attrsToList = mapAttrsToList nameValuePair; 1136 1137 /** 1138 Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set: 1139 the second argument of the function will never be an attrset. 1140 Also, the first argument of the mapping function is a *list* of the attribute names that form the path to the leaf attribute. 1141 1142 For a function that gives you control over what counts as a leaf, see `mapAttrsRecursiveCond`. 1143 1144 :::{#map-attrs-recursive-example .example} 1145 # Map over leaf attributes 1146 1147 ```nix 1148 mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value])) 1149 { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; } 1150 ``` 1151 evaluates to 1152 ```nix 1153 { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; } 1154 ``` 1155 ::: 1156 1157 # Type 1158 ``` 1159 mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet 1160 ``` 1161 */ 1162 mapAttrsRecursive = f: set: mapAttrsRecursiveCond (as: true) f set; 1163 1164 /** 1165 Like `mapAttrsRecursive`, but it takes an additional predicate that tells it whether to recurse into an attribute set. 1166 If the predicate returns false, `mapAttrsRecursiveCond` does not recurse, but instead applies the mapping function. 1167 If the predicate returns true, it does recurse, and does not apply the mapping function. 1168 1169 :::{#map-attrs-recursive-cond-example .example} 1170 # Map over an leaf attributes defined by a condition 1171 1172 Map derivations to their `name` attribute. 1173 Derivatons are identified as attribute sets that contain `{ type = "derivation"; }`. 1174 ```nix 1175 mapAttrsRecursiveCond 1176 (as: !(as ? "type" && as.type == "derivation")) 1177 (path: x: x.name) 1178 attrs 1179 ``` 1180 ::: 1181 1182 # Type 1183 ``` 1184 mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet 1185 ``` 1186 */ 1187 mapAttrsRecursiveCond = 1188 cond: f: set: 1189 let 1190 recurse = 1191 path: 1192 mapAttrs ( 1193 name: value: 1194 if isAttrs value && cond value then recurse (path ++ [ name ]) value else f (path ++ [ name ]) value 1195 ); 1196 in 1197 recurse [ ] set; 1198 1199 /** 1200 Apply a function to each leaf (nonattributeset attribute) of a tree of 1201 nested attribute sets, returning the results of the function as a list, 1202 ordered lexicographically by their attribute paths. 1203 1204 Like `mapAttrsRecursive`, but concatenates the mapping function results 1205 into a list. 1206 1207 # Inputs 1208 1209 `f` 1210 1211 : Mapping function which, given an attributes path and value, returns a 1212 new value. 1213 1214 This value will be an element of the list returned by 1215 `mapAttrsToListRecursive`. 1216 1217 The first argument to the mapping function is a list of attribute names 1218 forming the path to the leaf attribute. The second argument is the leaf 1219 attribute value, which will never be an attribute set. 1220 1221 `set` 1222 1223 : Attribute set to map over. 1224 1225 # Type 1226 1227 ``` 1228 mapAttrsToListRecursive :: ([String] -> a -> b) -> AttrSet -> [b] 1229 ``` 1230 1231 # Examples 1232 :::{.example} 1233 ## `lib.attrsets.mapAttrsToListRecursive` usage example 1234 1235 ```nix 1236 mapAttrsToListRecursive (path: value: "${concatStringsSep "." path}=${value}") 1237 { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; } 1238 => [ "n.a=A" "n.m.b=B" "n.m.c=C" "d=D" ] 1239 ``` 1240 ::: 1241 */ 1242 mapAttrsToListRecursive = mapAttrsToListRecursiveCond (_: _: true); 1243 1244 /** 1245 Determine the nodes of a tree of nested attribute sets by applying a 1246 predicate, then apply a function to the leaves, returning the results 1247 as a list, ordered lexicographically by their attribute paths. 1248 1249 Like `mapAttrsToListRecursive`, but takes an additional predicate to 1250 decide whether to recurse into an attribute set. 1251 1252 Unlike `mapAttrsRecursiveCond` this predicate receives the attribute path 1253 as its first argument, in addition to the attribute set. 1254 1255 # Inputs 1256 1257 `pred` 1258 1259 : Predicate to decide whether to recurse into an attribute set. 1260 1261 If the predicate returns true, `mapAttrsToListRecursiveCond` recurses into 1262 the attribute set. If the predicate returns false, it does not recurse 1263 but instead applies the mapping function, treating the attribute set as 1264 a leaf. 1265 1266 The first argument to the predicate is a list of attribute names forming 1267 the path to the attribute set. The second argument is the attribute set. 1268 1269 `f` 1270 1271 : Mapping function which, given an attributes path and value, returns a 1272 new value. 1273 1274 This value will be an element of the list returned by 1275 `mapAttrsToListRecursiveCond`. 1276 1277 The first argument to the mapping function is a list of attribute names 1278 forming the path to the leaf attribute. The second argument is the leaf 1279 attribute value, which may be an attribute set if the predicate returned 1280 false. 1281 1282 `set` 1283 1284 : Attribute set to map over. 1285 1286 # Type 1287 ``` 1288 mapAttrsToListRecursiveCond :: ([String] -> AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> [b] 1289 ``` 1290 1291 # Examples 1292 :::{.example} 1293 ## `lib.attrsets.mapAttrsToListRecursiveCond` usage example 1294 1295 ```nix 1296 mapAttrsToListRecursiveCond 1297 (path: as: !(lib.isDerivation as)) 1298 (path: value: "--set=${lib.concatStringsSep "." path}=${toString value}") 1299 { 1300 rust.optimize = 2; 1301 target = { 1302 riscv64-unknown-linux-gnu.linker = pkgs.lld; 1303 }; 1304 } 1305 => [ "--set=rust.optimize=2" "--set=target.riscv64-unknown-linux-gnu.linker=/nix/store/sjw4h1k" ] 1306 ``` 1307 ::: 1308 */ 1309 mapAttrsToListRecursiveCond = 1310 pred: f: set: 1311 let 1312 mapRecursive = 1313 path: value: if isAttrs value && pred path value then recurse path value else [ (f path value) ]; 1314 recurse = path: set: concatMap (name: mapRecursive (path ++ [ name ]) set.${name}) (attrNames set); 1315 in 1316 recurse [ ] set; 1317 1318 /** 1319 Generate an attribute set by mapping a function over a list of 1320 attribute names. 1321 1322 # Inputs 1323 1324 `names` 1325 1326 : Names of values in the resulting attribute set. 1327 1328 `f` 1329 1330 : A function, given the name of the attribute, returns the attribute's value. 1331 1332 # Type 1333 1334 ``` 1335 genAttrs :: [ String ] -> (String -> Any) -> AttrSet 1336 ``` 1337 1338 # Examples 1339 :::{.example} 1340 ## `lib.attrsets.genAttrs` usage example 1341 1342 ```nix 1343 genAttrs [ "foo" "bar" ] (name: "x_" + name) 1344 => { foo = "x_foo"; bar = "x_bar"; } 1345 ``` 1346 1347 ::: 1348 */ 1349 genAttrs = names: f: genAttrs' names (n: nameValuePair n (f n)); 1350 1351 /** 1352 Like `genAttrs`, but allows the name of each attribute to be specified in addition to the value. 1353 The applied function should return both the new name and value as a `nameValuePair`. 1354 ::: {.warning} 1355 In case of attribute name collision the first entry determines the value, 1356 all subsequent conflicting entries for the same name are silently ignored. 1357 ::: 1358 1359 # Inputs 1360 1361 `xs` 1362 1363 : A list of strings `s` used as generator. 1364 1365 `f` 1366 1367 : A function, given a string `s` from the list `xs`, returns a new `nameValuePair`. 1368 1369 # Type 1370 1371 ``` 1372 genAttrs' :: [ Any ] -> (Any -> { name :: String; value :: Any; }) -> AttrSet 1373 ``` 1374 1375 # Examples 1376 :::{.example} 1377 ## `lib.attrsets.genAttrs'` usage example 1378 1379 ```nix 1380 genAttrs' [ "foo" "bar" ] (s: nameValuePair ("x_" + s) ("y_" + s)) 1381 => { x_foo = "y_foo"; x_bar = "y_bar"; } 1382 ``` 1383 1384 ::: 1385 */ 1386 genAttrs' = xs: f: listToAttrs (map f xs); 1387 1388 /** 1389 Check whether the argument is a derivation. Any set with 1390 `{ type = "derivation"; }` counts as a derivation. 1391 1392 # Inputs 1393 1394 `value` 1395 1396 : Value to check. 1397 1398 # Type 1399 1400 ``` 1401 isDerivation :: Any -> Bool 1402 ``` 1403 1404 # Examples 1405 :::{.example} 1406 ## `lib.attrsets.isDerivation` usage example 1407 1408 ```nix 1409 nixpkgs = import <nixpkgs> {} 1410 isDerivation nixpkgs.ruby 1411 => true 1412 isDerivation "foobar" 1413 => false 1414 ``` 1415 1416 ::: 1417 */ 1418 isDerivation = value: value.type or null == "derivation"; 1419 1420 /** 1421 Converts a store path to a fake derivation. 1422 1423 # Inputs 1424 1425 `path` 1426 1427 : A store path to convert to a derivation. 1428 1429 # Type 1430 1431 ``` 1432 toDerivation :: Path -> Derivation 1433 ``` 1434 */ 1435 toDerivation = 1436 path: 1437 let 1438 path' = builtins.storePath path; 1439 res = { 1440 type = "derivation"; 1441 name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path')); 1442 outPath = path'; 1443 outputs = [ "out" ]; 1444 out = res; 1445 outputName = "out"; 1446 }; 1447 in 1448 res; 1449 1450 /** 1451 If `cond` is true, return the attribute set `as`, 1452 otherwise an empty attribute set. 1453 1454 # Inputs 1455 1456 `cond` 1457 1458 : Condition under which the `as` attribute set is returned. 1459 1460 `as` 1461 1462 : The attribute set to return if `cond` is `true`. 1463 1464 # Type 1465 1466 ``` 1467 optionalAttrs :: Bool -> AttrSet -> AttrSet 1468 ``` 1469 1470 # Examples 1471 :::{.example} 1472 ## `lib.attrsets.optionalAttrs` usage example 1473 1474 ```nix 1475 optionalAttrs (true) { my = "set"; } 1476 => { my = "set"; } 1477 optionalAttrs (false) { my = "set"; } 1478 => { } 1479 ``` 1480 1481 ::: 1482 */ 1483 optionalAttrs = cond: as: if cond then as else { }; 1484 1485 /** 1486 Merge sets of attributes and use the function `f` to merge attributes 1487 values. 1488 1489 # Inputs 1490 1491 `names` 1492 1493 : List of attribute names to zip. 1494 1495 `f` 1496 1497 : A function, accepts an attribute name, all the values, and returns a combined value. 1498 1499 `sets` 1500 1501 : List of values from the list of attribute sets. 1502 1503 # Type 1504 1505 ``` 1506 zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet 1507 ``` 1508 1509 # Examples 1510 :::{.example} 1511 ## `lib.attrsets.zipAttrsWithNames` usage example 1512 1513 ```nix 1514 zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}] 1515 => { a = ["x" "y"]; } 1516 ``` 1517 1518 ::: 1519 */ 1520 zipAttrsWithNames = 1521 names: f: sets: 1522 listToAttrs ( 1523 map (name: { 1524 inherit name; 1525 value = f name (catAttrs name sets); 1526 }) names 1527 ); 1528 1529 /** 1530 Merge sets of attributes and use the function f to merge attribute values. 1531 Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`. 1532 1533 Implementation note: Common names appear multiple times in the list of 1534 names, hopefully this does not affect the system because the maximal 1535 laziness avoid computing twice the same expression and `listToAttrs` does 1536 not care about duplicated attribute names. 1537 1538 # Type 1539 1540 ``` 1541 zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet 1542 ``` 1543 1544 # Examples 1545 :::{.example} 1546 ## `lib.attrsets.zipAttrsWith` usage example 1547 1548 ```nix 1549 zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}] 1550 => { a = ["x" "y"]; b = ["z"]; } 1551 ``` 1552 1553 ::: 1554 */ 1555 zipAttrsWith = 1556 builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets); 1557 1558 /** 1559 Merge sets of attributes and combine each attribute value in to a list. 1560 1561 Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function. 1562 1563 # Type 1564 1565 ``` 1566 zipAttrs :: [ AttrSet ] -> AttrSet 1567 ``` 1568 1569 # Examples 1570 :::{.example} 1571 ## `lib.attrsets.zipAttrs` usage example 1572 1573 ```nix 1574 zipAttrs [{a = "x";} {a = "y"; b = "z";}] 1575 => { a = ["x" "y"]; b = ["z"]; } 1576 ``` 1577 1578 ::: 1579 */ 1580 zipAttrs = zipAttrsWith (name: values: values); 1581 1582 /** 1583 Merge a list of attribute sets together using the `//` operator. 1584 In case of duplicate attributes, values from later list elements take precedence over earlier ones. 1585 The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs. 1586 For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n). 1587 1588 # Inputs 1589 1590 `list` 1591 1592 : 1\. Function argument 1593 1594 # Type 1595 1596 ``` 1597 mergeAttrsList :: [ Attrs ] -> Attrs 1598 ``` 1599 1600 # Examples 1601 :::{.example} 1602 ## `lib.attrsets.mergeAttrsList` usage example 1603 1604 ```nix 1605 mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ] 1606 => { a = 0; b = 1; c = 2; d = 3; } 1607 mergeAttrsList [ { a = 0; } { a = 1; } ] 1608 => { a = 1; } 1609 ``` 1610 1611 ::: 1612 */ 1613 mergeAttrsList = 1614 list: 1615 let 1616 # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end` 1617 # Type: Int -> Int -> Attrs 1618 binaryMerge = 1619 start: end: 1620 # assert start < end; # Invariant 1621 if end - start >= 2 then 1622 # If there's at least 2 elements, split the range in two, recurse on each part and merge the result 1623 # The invariant is satisfied because each half will have at least 1 element 1624 binaryMerge start (start + (end - start) / 2) // binaryMerge (start + (end - start) / 2) end 1625 else 1626 # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly 1627 elemAt list start; 1628 in 1629 if list == [ ] then 1630 # Calling binaryMerge as below would not satisfy its invariant 1631 { } 1632 else 1633 binaryMerge 0 (length list); 1634 1635 /** 1636 Does the same as the update operator '//' except that attributes are 1637 merged until the given predicate is verified. The predicate should 1638 accept 3 arguments which are the path to reach the attribute, a part of 1639 the first attribute set and a part of the second attribute set. When 1640 the predicate is satisfied, the value of the first attribute set is 1641 replaced by the value of the second attribute set. 1642 1643 # Inputs 1644 1645 `pred` 1646 1647 : Predicate, taking the path to the current attribute as a list of strings for attribute names, and the two values at that path from the original arguments. 1648 1649 `lhs` 1650 1651 : Left attribute set of the merge. 1652 1653 `rhs` 1654 1655 : Right attribute set of the merge. 1656 1657 # Type 1658 1659 ``` 1660 recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet 1661 ``` 1662 1663 # Examples 1664 :::{.example} 1665 ## `lib.attrsets.recursiveUpdateUntil` usage example 1666 1667 ```nix 1668 recursiveUpdateUntil (path: l: r: path == ["foo"]) { 1669 # first attribute set 1670 foo.bar = 1; 1671 foo.baz = 2; 1672 bar = 3; 1673 } { 1674 #second attribute set 1675 foo.bar = 1; 1676 foo.quz = 2; 1677 baz = 4; 1678 } 1679 1680 => { 1681 foo.bar = 1; # 'foo.*' from the second set 1682 foo.quz = 2; # 1683 bar = 3; # 'bar' from the first set 1684 baz = 4; # 'baz' from the second set 1685 } 1686 ``` 1687 1688 ::: 1689 */ 1690 recursiveUpdateUntil = 1691 pred: lhs: rhs: 1692 let 1693 f = 1694 attrPath: 1695 zipAttrsWith ( 1696 n: values: 1697 let 1698 here = attrPath ++ [ n ]; 1699 in 1700 if length values == 1 || pred here (elemAt values 1) (head values) then 1701 head values 1702 else 1703 f here values 1704 ); 1705 in 1706 f [ ] [ rhs lhs ]; 1707 1708 /** 1709 A recursive variant of the update operator //. The recursion 1710 stops when one of the attribute values is not an attribute set, 1711 in which case the right hand side value takes precedence over the 1712 left hand side value. 1713 1714 # Inputs 1715 1716 `lhs` 1717 1718 : Left attribute set of the merge. 1719 1720 `rhs` 1721 1722 : Right attribute set of the merge. 1723 1724 # Type 1725 1726 ``` 1727 recursiveUpdate :: AttrSet -> AttrSet -> AttrSet 1728 ``` 1729 1730 # Examples 1731 :::{.example} 1732 ## `lib.attrsets.recursiveUpdate` usage example 1733 1734 ```nix 1735 recursiveUpdate { 1736 boot.loader.grub.enable = true; 1737 boot.loader.grub.device = "/dev/hda"; 1738 } { 1739 boot.loader.grub.device = ""; 1740 } 1741 1742 returns: { 1743 boot.loader.grub.enable = true; 1744 boot.loader.grub.device = ""; 1745 } 1746 ``` 1747 1748 ::: 1749 */ 1750 recursiveUpdate = 1751 lhs: rhs: 1752 recursiveUpdateUntil ( 1753 path: lhs: rhs: 1754 !(isAttrs lhs && isAttrs rhs) 1755 ) lhs rhs; 1756 1757 /** 1758 Recurse into every attribute set of the first argument and check that: 1759 - Each attribute path also exists in the second argument. 1760 - If the attribute's value is not a nested attribute set, it must have the same value in the right argument. 1761 1762 # Inputs 1763 1764 `pattern` 1765 1766 : Attribute set structure to match 1767 1768 `attrs` 1769 1770 : Attribute set to check 1771 1772 # Type 1773 1774 ``` 1775 matchAttrs :: AttrSet -> AttrSet -> Bool 1776 ``` 1777 1778 # Examples 1779 :::{.example} 1780 ## `lib.attrsets.matchAttrs` usage example 1781 1782 ```nix 1783 matchAttrs { cpu = {}; } { cpu = { bits = 64; }; } 1784 => true 1785 ``` 1786 1787 ::: 1788 */ 1789 matchAttrs = 1790 pattern: attrs: 1791 assert isAttrs pattern; 1792 all ( 1793 # Compare equality between `pattern` & `attrs`. 1794 attr: 1795 # Missing attr, not equal. 1796 attrs ? ${attr} 1797 && ( 1798 let 1799 lhs = pattern.${attr}; 1800 rhs = attrs.${attr}; 1801 in 1802 # If attrset check recursively 1803 if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs else lhs == rhs 1804 ) 1805 ) (attrNames pattern); 1806 1807 /** 1808 Override only the attributes that are already present in the old set 1809 useful for deep-overriding. 1810 1811 # Inputs 1812 1813 `old` 1814 1815 : Original attribute set 1816 1817 `new` 1818 1819 : Attribute set with attributes to override in `old`. 1820 1821 # Type 1822 1823 ``` 1824 overrideExisting :: AttrSet -> AttrSet -> AttrSet 1825 ``` 1826 1827 # Examples 1828 :::{.example} 1829 ## `lib.attrsets.overrideExisting` usage example 1830 1831 ```nix 1832 overrideExisting {} { a = 1; } 1833 => {} 1834 overrideExisting { b = 2; } { a = 1; } 1835 => { b = 2; } 1836 overrideExisting { a = 3; b = 2; } { a = 1; } 1837 => { a = 1; b = 2; } 1838 ``` 1839 1840 ::: 1841 */ 1842 overrideExisting = old: new: mapAttrs (name: value: new.${name} or value) old; 1843 1844 /** 1845 Turns a list of strings into a human-readable description of those 1846 strings represented as an attribute path. The result of this function is 1847 not intended to be machine-readable. 1848 Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`. 1849 1850 # Inputs 1851 1852 `path` 1853 1854 : Attribute path to render to a string 1855 1856 # Type 1857 1858 ``` 1859 showAttrPath :: [String] -> String 1860 ``` 1861 1862 # Examples 1863 :::{.example} 1864 ## `lib.attrsets.showAttrPath` usage example 1865 1866 ```nix 1867 showAttrPath [ "foo" "10" "bar" ] 1868 => "foo.\"10\".bar" 1869 showAttrPath [] 1870 => "<root attribute path>" 1871 ``` 1872 1873 ::: 1874 */ 1875 showAttrPath = 1876 path: 1877 if path == [ ] then "<root attribute path>" else concatMapStringsSep "." escapeNixIdentifier path; 1878 1879 /** 1880 Get a package output. 1881 If no output is found, fallback to `.out` and then to the default. 1882 The function is idempotent: `getOutput "b" (getOutput "a" p) == getOutput "a" p`. 1883 1884 # Inputs 1885 1886 `output` 1887 1888 : 1\. Function argument 1889 1890 `pkg` 1891 1892 : 2\. Function argument 1893 1894 # Type 1895 1896 ``` 1897 getOutput :: String -> :: Derivation -> Derivation 1898 ``` 1899 1900 # Examples 1901 :::{.example} 1902 ## `lib.attrsets.getOutput` usage example 1903 1904 ```nix 1905 "${getOutput "dev" pkgs.openssl}" 1906 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev" 1907 ``` 1908 1909 ::: 1910 */ 1911 getOutput = 1912 output: pkg: 1913 if !pkg ? outputSpecified || !pkg.outputSpecified then pkg.${output} or pkg.out or pkg else pkg; 1914 1915 /** 1916 Get the first of the `outputs` provided by the package, or the default. 1917 This function is aligned with `_overrideFirst()` from the `multiple-outputs.sh` setup hook. 1918 Like `getOutput`, the function is idempotent. 1919 1920 # Inputs 1921 1922 `outputs` 1923 1924 : 1\. Function argument 1925 1926 `pkg` 1927 1928 : 2\. Function argument 1929 1930 # Type 1931 1932 ``` 1933 getFirstOutput :: [String] -> Derivation -> Derivation 1934 ``` 1935 1936 # Examples 1937 :::{.example} 1938 ## `lib.attrsets.getFirstOutput` usage example 1939 1940 ```nix 1941 "${getFirstOutput [ "include" "dev" ] pkgs.openssl}" 1942 => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r-dev" 1943 ``` 1944 1945 ::: 1946 */ 1947 getFirstOutput = 1948 candidates: pkg: 1949 let 1950 outputs = builtins.filter (name: hasAttr name pkg) candidates; 1951 output = builtins.head outputs; 1952 in 1953 if pkg.outputSpecified or false || outputs == [ ] then pkg else pkg.${output}; 1954 1955 /** 1956 Get a package's `bin` output. 1957 If the output does not exist, fallback to `.out` and then to the default. 1958 1959 # Inputs 1960 1961 `pkg` 1962 1963 : The package whose `bin` output will be retrieved. 1964 1965 # Type 1966 1967 ``` 1968 getBin :: Derivation -> Derivation 1969 ``` 1970 1971 # Examples 1972 :::{.example} 1973 ## `lib.attrsets.getBin` usage example 1974 1975 ```nix 1976 "${getBin pkgs.openssl}" 1977 => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r" 1978 ``` 1979 1980 ::: 1981 */ 1982 getBin = getOutput "bin"; 1983 1984 /** 1985 Get a package's `lib` output. 1986 If the output does not exist, fallback to `.out` and then to the default. 1987 1988 # Inputs 1989 1990 `pkg` 1991 1992 : The package whose `lib` output will be retrieved. 1993 1994 # Type 1995 1996 ``` 1997 getLib :: Derivation -> Derivation 1998 ``` 1999 2000 # Examples 2001 :::{.example} 2002 ## `lib.attrsets.getLib` usage example 2003 2004 ```nix 2005 "${getLib pkgs.openssl}" 2006 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib" 2007 ``` 2008 2009 ::: 2010 */ 2011 getLib = getOutput "lib"; 2012 2013 /** 2014 Get a package's `static` output. 2015 If the output does not exist, fallback to `.lib`, then to `.out`, and then to the default. 2016 2017 # Inputs 2018 2019 `pkg` 2020 2021 : The package whose `static` output will be retrieved. 2022 2023 # Type 2024 2025 ``` 2026 getStatic :: Derivation -> Derivation 2027 ``` 2028 2029 # Examples 2030 :::{.example} 2031 ## `lib.attrsets.getStatic` usage example 2032 2033 ```nix 2034 "${lib.getStatic pkgs.glibc}" 2035 => "/nix/store/00000000000000000000000000000000-glibc-2.39-52-static" 2036 ``` 2037 2038 ::: 2039 */ 2040 getStatic = getFirstOutput [ 2041 "static" 2042 "lib" 2043 "out" 2044 ]; 2045 2046 /** 2047 Get a package's `dev` output. 2048 If the output does not exist, fallback to `.out` and then to the default. 2049 2050 # Inputs 2051 2052 `pkg` 2053 2054 : The package whose `dev` output will be retrieved. 2055 2056 # Type 2057 2058 ``` 2059 getDev :: Derivation -> Derivation 2060 ``` 2061 2062 # Examples 2063 :::{.example} 2064 ## `lib.attrsets.getDev` usage example 2065 2066 ```nix 2067 "${getDev pkgs.openssl}" 2068 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev" 2069 ``` 2070 2071 ::: 2072 */ 2073 getDev = getOutput "dev"; 2074 2075 /** 2076 Get a package's `include` output. 2077 If the output does not exist, fallback to `.dev`, then to `.out`, and then to the default. 2078 2079 # Inputs 2080 2081 `pkg` 2082 2083 : The package whose `include` output will be retrieved. 2084 2085 # Type 2086 2087 ``` 2088 getInclude :: Derivation -> Derivation 2089 ``` 2090 2091 # Examples 2092 :::{.example} 2093 ## `lib.attrsets.getInclude` usage example 2094 2095 ```nix 2096 "${getInclude pkgs.openssl}" 2097 => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r-dev" 2098 ``` 2099 2100 ::: 2101 */ 2102 getInclude = getFirstOutput [ 2103 "include" 2104 "dev" 2105 "out" 2106 ]; 2107 2108 /** 2109 Get a package's `man` output. 2110 If the output does not exist, fallback to `.out` and then to the default. 2111 2112 # Inputs 2113 2114 `pkg` 2115 2116 : The package whose `man` output will be retrieved. 2117 2118 # Type 2119 2120 ``` 2121 getMan :: Derivation -> Derivation 2122 ``` 2123 2124 # Examples 2125 :::{.example} 2126 ## `lib.attrsets.getMan` usage example 2127 2128 ```nix 2129 "${getMan pkgs.openssl}" 2130 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man" 2131 ``` 2132 2133 ::: 2134 */ 2135 getMan = getOutput "man"; 2136 2137 /** 2138 Pick the outputs of packages to place in `buildInputs` 2139 2140 # Inputs 2141 2142 `pkgs` 2143 2144 : List of packages. 2145 2146 # Type 2147 2148 ``` 2149 chooseDevOutputs :: [Derivation] -> [Derivation] 2150 ``` 2151 */ 2152 chooseDevOutputs = map getDev; 2153 2154 /** 2155 Make various Nix tools consider the contents of the resulting 2156 attribute set when looking for what to build, find, etc. 2157 2158 This function only affects a single attribute set; it does not 2159 apply itself recursively for nested attribute sets. 2160 2161 # Inputs 2162 2163 `attrs` 2164 2165 : An attribute set to scan for derivations. 2166 2167 # Type 2168 2169 ``` 2170 recurseIntoAttrs :: AttrSet -> AttrSet 2171 ``` 2172 2173 # Examples 2174 :::{.example} 2175 ## `lib.attrsets.recurseIntoAttrs` usage example 2176 2177 ```nix 2178 { pkgs ? import <nixpkgs> {} }: 2179 { 2180 myTools = pkgs.lib.recurseIntoAttrs { 2181 inherit (pkgs) hello figlet; 2182 }; 2183 } 2184 ``` 2185 2186 ::: 2187 */ 2188 recurseIntoAttrs = attrs: attrs // { recurseForDerivations = true; }; 2189 2190 /** 2191 Undo the effect of recurseIntoAttrs. 2192 2193 # Inputs 2194 2195 `attrs` 2196 2197 : An attribute set to not scan for derivations. 2198 2199 # Type 2200 2201 ``` 2202 dontRecurseIntoAttrs :: AttrSet -> AttrSet 2203 ``` 2204 */ 2205 dontRecurseIntoAttrs = attrs: attrs // { recurseForDerivations = false; }; 2206 2207 /** 2208 `unionOfDisjoint x y` is equal to `x // y`, but accessing attributes present 2209 in both `x` and `y` will throw an error. This operator is commutative, unlike `//`. 2210 2211 # Inputs 2212 2213 `x` 2214 2215 : 1\. Function argument 2216 2217 `y` 2218 2219 : 2\. Function argument 2220 2221 # Type 2222 2223 ``` 2224 unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet 2225 ``` 2226 */ 2227 unionOfDisjoint = 2228 x: y: 2229 let 2230 intersection = builtins.intersectAttrs x y; 2231 collisions = lib.concatStringsSep " " (builtins.attrNames intersection); 2232 mask = builtins.mapAttrs ( 2233 name: value: throw "unionOfDisjoint: collision on ${name}; complete list: ${collisions}" 2234 ) intersection; 2235 in 2236 (x // y) // mask; 2237 2238 # DEPRECATED 2239 zipWithNames = warn "lib.zipWithNames is a deprecated alias of lib.zipAttrsWithNames." zipAttrsWithNames; 2240 2241 # DEPRECATED 2242 zip = warn "lib.zip is a deprecated alias of lib.zipAttrsWith." zipAttrsWith; 2243 2244 # DEPRECATED 2245 cartesianProductOfSets = 2246 warnIf (oldestSupportedReleaseIsAtLeast 2405) 2247 "lib.cartesianProductOfSets is a deprecated alias of lib.cartesianProduct." 2248 cartesianProduct; 2249}