Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ lib }: 2 3let 4 inherit (builtins) 5 intersectAttrs 6 ; 7 inherit (lib) 8 functionArgs 9 isFunction 10 mirrorFunctionArgs 11 isAttrs 12 setFunctionArgs 13 optionalAttrs 14 attrNames 15 filter 16 elemAt 17 concatStringsSep 18 sortOn 19 take 20 length 21 filterAttrs 22 optionalString 23 flip 24 pathIsDirectory 25 head 26 pipe 27 isDerivation 28 listToAttrs 29 mapAttrs 30 seq 31 flatten 32 deepSeq 33 extends 34 toFunction 35 id 36 ; 37 inherit (lib.strings) levenshtein levenshteinAtMost; 38 39in 40rec { 41 42 /** 43 `overrideDerivation drv f` takes a derivation (i.e., the result 44 of a call to the builtin function `derivation`) and returns a new 45 derivation in which the attributes of the original are overridden 46 according to the function `f`. The function `f` is called with 47 the original derivation attributes. 48 49 `overrideDerivation` allows certain "ad-hoc" customisation 50 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance, 51 if you want to "patch" the derivation returned by a package 52 function in Nixpkgs to build another version than what the 53 function itself provides. 54 55 For another application, see build-support/vm, where this 56 function is used to build arbitrary derivations inside a QEMU 57 virtual machine. 58 59 Note that in order to preserve evaluation errors, the new derivation's 60 outPath depends on the old one's, which means that this function cannot 61 be used in circular situations when the old derivation also depends on the 62 new one. 63 64 You should in general prefer `drv.overrideAttrs` over this function; 65 see the nixpkgs manual for more information on overriding. 66 67 # Inputs 68 69 `drv` 70 71 : 1\. Function argument 72 73 `f` 74 75 : 2\. Function argument 76 77 # Type 78 79 ``` 80 overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation 81 ``` 82 83 # Examples 84 :::{.example} 85 ## `lib.customisation.overrideDerivation` usage example 86 87 ```nix 88 mySed = overrideDerivation pkgs.gnused (oldAttrs: { 89 name = "sed-4.2.2-pre"; 90 src = fetchurl { 91 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2; 92 hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY="; 93 }; 94 patches = []; 95 }); 96 ``` 97 98 ::: 99 */ 100 overrideDerivation = 101 drv: f: 102 let 103 newDrv = derivation (drv.drvAttrs // (f drv)); 104 in 105 flip (extendDerivation (seq drv.drvPath true)) newDrv ( 106 { 107 meta = drv.meta or { }; 108 passthru = if drv ? passthru then drv.passthru else { }; 109 } 110 // (drv.passthru or { }) 111 // optionalAttrs (drv ? __spliced) { 112 __spliced = { } // (mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced); 113 } 114 ); 115 116 /** 117 `makeOverridable` takes a function from attribute set to attribute set and 118 injects `override` attribute which can be used to override arguments of 119 the function. 120 121 Please refer to documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats 122 related to its use. 123 124 # Inputs 125 126 `f` 127 128 : 1\. Function argument 129 130 # Type 131 132 ``` 133 makeOverridable :: (AttrSet -> a) -> AttrSet -> a 134 ``` 135 136 # Examples 137 :::{.example} 138 ## `lib.customisation.makeOverridable` usage example 139 140 ```nix 141 nix-repl> x = {a, b}: { result = a + b; } 142 143 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; } 144 145 nix-repl> y 146 { override = «lambda»; overrideDerivation = «lambda»; result = 3; } 147 148 nix-repl> y.override { a = 10; } 149 { override = «lambda»; overrideDerivation = «lambda»; result = 12; } 150 ``` 151 152 ::: 153 */ 154 makeOverridable = 155 f: 156 let 157 # Creates a functor with the same arguments as f 158 mirrorArgs = mirrorFunctionArgs f; 159 in 160 mirrorArgs ( 161 origArgs: 162 let 163 result = f origArgs; 164 165 # Changes the original arguments with (potentially a function that returns) a set of new attributes 166 overrideWith = newArgs: origArgs // (if isFunction newArgs then newArgs origArgs else newArgs); 167 168 # Re-call the function but with different arguments 169 overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs)); 170 # Change the result of the function call by applying g to it 171 overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs; 172 in 173 if isAttrs result then 174 result 175 // { 176 override = overrideArgs; 177 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv); 178 ${if result ? overrideAttrs then "overrideAttrs" else null} = 179 fdrv: overrideResult (x: x.overrideAttrs fdrv); 180 } 181 else if isFunction result then 182 # Transform the result into a functor while propagating its arguments 183 setFunctionArgs result (functionArgs result) 184 // { 185 override = overrideArgs; 186 } 187 else 188 result 189 ); 190 191 /** 192 Call the package function in the file `fn` with the required 193 arguments automatically. The function is called with the 194 arguments `args`, but any missing arguments are obtained from 195 `autoArgs`. This function is intended to be partially 196 parameterised, e.g., 197 198 ```nix 199 callPackage = callPackageWith pkgs; 200 pkgs = { 201 libfoo = callPackage ./foo.nix { }; 202 libbar = callPackage ./bar.nix { }; 203 }; 204 ``` 205 206 If the `libbar` function expects an argument named `libfoo`, it is 207 automatically passed as an argument. Overrides or missing 208 arguments can be supplied in `args`, e.g. 209 210 ```nix 211 libbar = callPackage ./bar.nix { 212 libfoo = null; 213 enableX11 = true; 214 }; 215 ``` 216 217 <!-- TODO: Apply "Example:" tag to the examples above --> 218 219 # Inputs 220 221 `autoArgs` 222 223 : 1\. Function argument 224 225 `fn` 226 227 : 2\. Function argument 228 229 `args` 230 231 : 3\. Function argument 232 233 # Type 234 235 ``` 236 callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 237 ``` 238 */ 239 callPackageWith = 240 autoArgs: fn: args: 241 let 242 f = if isFunction fn then fn else import fn; 243 fargs = functionArgs f; 244 245 # All arguments that will be passed to the function 246 # This includes automatic ones and ones passed explicitly 247 allArgs = intersectAttrs fargs autoArgs // args; 248 249 # a list of argument names that the function requires, but 250 # wouldn't be passed to it 251 missingArgs = 252 # Filter out arguments that have a default value 253 ( 254 filterAttrs (name: value: !value) 255 # Filter out arguments that would be passed 256 (removeAttrs fargs (attrNames allArgs)) 257 ); 258 259 # Get a list of suggested argument names for a given missing one 260 getSuggestions = 261 arg: 262 pipe (autoArgs // args) [ 263 attrNames 264 # Only use ones that are at most 2 edits away. While mork would work, 265 # levenshteinAtMost is only fast for 2 or less. 266 (filter (levenshteinAtMost 2 arg)) 267 # Put strings with shorter distance first 268 (sortOn (levenshtein arg)) 269 # Only take the first couple results 270 (take 3) 271 # Quote all entries 272 (map (x: "\"" + x + "\"")) 273 ]; 274 275 prettySuggestions = 276 suggestions: 277 if suggestions == [ ] then 278 "" 279 else if length suggestions == 1 then 280 ", did you mean ${elemAt suggestions 0}?" 281 else 282 ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?"; 283 284 errorForArg = 285 arg: 286 let 287 loc = builtins.unsafeGetAttrPos arg fargs; 288 # loc' can be removed once lib/minver.nix is >2.3.4, since that includes 289 # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null 290 loc' = 291 if loc != null then 292 loc.file + ":" + toString loc.line 293 else if !isFunction fn then 294 toString (lib.filesystem.resolveDefaultNix fn) 295 else 296 "<unknown location>"; 297 in 298 "Function called without required argument \"${arg}\" at " 299 + "${loc'}${prettySuggestions (getSuggestions arg)}"; 300 301 # Only show the error for the first missing argument 302 error = errorForArg (head (attrNames missingArgs)); 303 304 in 305 if missingArgs == { } then 306 makeOverridable f allArgs 307 # This needs to be an abort so it can't be caught with `builtins.tryEval`, 308 # which is used by nix-env and ofborg to filter out packages that don't evaluate. 309 # This way we're forced to fix such errors in Nixpkgs, 310 # which is especially relevant with allowAliases = false 311 else 312 abort "lib.customisation.callPackageWith: ${error}"; 313 314 /** 315 Like callPackage, but for a function that returns an attribute 316 set of derivations. The override function is added to the 317 individual attributes. 318 319 # Inputs 320 321 `autoArgs` 322 323 : 1\. Function argument 324 325 `fn` 326 327 : 2\. Function argument 328 329 `args` 330 331 : 3\. Function argument 332 333 # Type 334 335 ``` 336 callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet 337 ``` 338 */ 339 callPackagesWith = 340 autoArgs: fn: args: 341 let 342 f = if isFunction fn then fn else import fn; 343 auto = intersectAttrs (functionArgs f) autoArgs; 344 mirrorArgs = mirrorFunctionArgs f; 345 origArgs = auto // args; 346 pkgs = f origArgs; 347 mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs; 348 in 349 if isDerivation pkgs then 350 throw ( 351 "function `callPackages` was called on a *single* derivation " 352 + ''"${pkgs.name or "<unknown-name>"}";'' 353 + " did you mean to use `callPackage` instead?" 354 ) 355 else 356 mapAttrs mkAttrOverridable pkgs; 357 358 /** 359 Add attributes to each output of a derivation without changing 360 the derivation itself and check a given condition when evaluating. 361 362 # Inputs 363 364 `condition` 365 366 : 1\. Function argument 367 368 `passthru` 369 370 : 2\. Function argument 371 372 `drv` 373 374 : 3\. Function argument 375 376 # Type 377 378 ``` 379 extendDerivation :: Bool -> Any -> Derivation -> Derivation 380 ``` 381 */ 382 extendDerivation = 383 condition: passthru: drv: 384 let 385 outputs = drv.outputs or [ "out" ]; 386 387 commonAttrs = 388 drv // (listToAttrs outputsList) // ({ all = map (x: x.value) outputsList; }) // passthru; 389 390 outputToAttrListElement = outputName: { 391 name = outputName; 392 value = 393 commonAttrs 394 // { 395 inherit (drv.${outputName}) type outputName; 396 outputSpecified = true; 397 drvPath = 398 assert condition; 399 drv.${outputName}.drvPath; 400 outPath = 401 assert condition; 402 drv.${outputName}.outPath; 403 } 404 // 405 # TODO: give the derivation control over the outputs. 406 # `overrideAttrs` may not be the only attribute that needs 407 # updating when switching outputs. 408 optionalAttrs (passthru ? overrideAttrs) { 409 # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing. 410 overrideAttrs = f: (passthru.overrideAttrs f).${outputName}; 411 }; 412 }; 413 414 outputsList = map outputToAttrListElement outputs; 415 in 416 commonAttrs 417 // { 418 drvPath = 419 assert condition; 420 drv.drvPath; 421 outPath = 422 assert condition; 423 drv.outPath; 424 }; 425 426 /** 427 Strip a derivation of all non-essential attributes, returning 428 only those needed by hydra-eval-jobs. Also strictly evaluate the 429 result to ensure that there are no thunks kept alive to prevent 430 garbage collection. 431 432 # Inputs 433 434 `drv` 435 436 : 1\. Function argument 437 438 # Type 439 440 ``` 441 hydraJob :: (Derivation | Null) -> (Derivation | Null) 442 ``` 443 */ 444 hydraJob = 445 drv: 446 let 447 outputs = drv.outputs or [ "out" ]; 448 449 commonAttrs = { 450 inherit (drv) name system meta; 451 inherit outputs; 452 } 453 // optionalAttrs (drv._hydraAggregate or false) { 454 _hydraAggregate = true; 455 constituents = map hydraJob (flatten drv.constituents); 456 } 457 // (listToAttrs outputsList); 458 459 makeOutput = 460 outputName: 461 let 462 output = drv.${outputName}; 463 in 464 { 465 name = outputName; 466 value = commonAttrs // { 467 outPath = output.outPath; 468 drvPath = output.drvPath; 469 type = "derivation"; 470 inherit outputName; 471 }; 472 }; 473 474 outputsList = map makeOutput outputs; 475 476 drv' = (head outputsList).value; 477 in 478 if drv == null then null else deepSeq drv' drv'; 479 480 /** 481 Make an attribute set (a "scope") from functions that take arguments from that same attribute set. 482 See [](#ex-makeScope) for how to use it. 483 484 # Inputs 485 486 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`) 487 488 A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output. 489 490 Typical values are `callPackageWith` or the output attribute `newScope`. 491 492 2. `f` (`AttrSet -> AttrSet`) 493 494 A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set. 495 496 This function is used to compute the fixpoint of the resulting scope using `callPackage`. 497 Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`. 498 499 See [](#ex-makeScope) for how to use it. 500 See [](#sec-functions-library-fixedPoints) for details on fixpoint computation. 501 502 # Output 503 504 `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`: 505 506 ``` 507 scope :: { 508 callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a 509 newScope = AttrSet -> scope 510 overrideScope = (scope -> scope -> AttrSet) -> scope 511 packages :: AttrSet -> AttrSet 512 } 513 ``` 514 515 - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`) 516 517 A function that 518 519 1. Takes a function `p`, or a path to a Nix file that contains a function `p`, which takes an attribute set and returns value of arbitrary type `a`, 520 2. Takes an attribute set `args` with explicit attributes to pass to `p`, 521 3. Calls `f` with attributes from the original attribute set `attrs` passed to `newScope` updated with `args`, i.e. `attrs // args`, if they match the attributes in the argument of `p`. 522 523 All such functions `p` will be called with the same value for `attrs`. 524 525 See [](#ex-makeScope-callPackage) for how to use it. 526 527 - `newScope` (`AttrSet -> scope`) 528 529 Takes an attribute set `attrs` and returns a scope that extends the original scope. 530 531 - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`) 532 533 Takes a function `g` of the form `final: prev: { # attributes }` to act as an overlay on `f`, and returns a new scope with values determined by `extends g f`. 534 See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details. 535 536 This allows subsequent modification of the final attribute set in a consistent way, i.e. all functions `p` invoked with `callPackage` will be called with the modified values. 537 538 - `packages` (`AttrSet -> AttrSet`) 539 540 The value of the argument `f` to `makeScope`. 541 542 - final attributes 543 544 The final values returned by `f`. 545 546 # Examples 547 548 :::{#ex-makeScope .example} 549 # Create an interdependent package set on top of `pkgs` 550 551 The functions in `foo.nix` and `bar.nix` can depend on each other, in the sense that `foo.nix` can contain a function that expects `bar` as an attribute in its argument. 552 553 ```nix 554 let 555 pkgs = import <nixpkgs> { }; 556 in 557 pkgs.lib.makeScope pkgs.newScope (self: { 558 foo = self.callPackage ./foo.nix { }; 559 bar = self.callPackage ./bar.nix { }; 560 }) 561 ``` 562 563 evaluates to 564 565 ```nix 566 { 567 callPackage = «lambda»; 568 newScope = «lambda»; 569 overrideScope = «lambda»; 570 packages = «lambda»; 571 foo = «derivation»; 572 bar = «derivation»; 573 } 574 ``` 575 ::: 576 577 :::{#ex-makeScope-callPackage .example} 578 # Using `callPackage` from a scope 579 580 ```nix 581 let 582 pkgs = import <nixpkgs> { }; 583 inherit (pkgs) lib; 584 scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; }); 585 three = scope.callPackage ({ a, b }: a + b) { }; 586 four = scope.callPackage ({ a, b }: a + b) { a = 2; }; 587 in 588 [ three four ] 589 ``` 590 591 evaluates to 592 593 ```nix 594 [ 3 4 ] 595 ``` 596 ::: 597 598 # Type 599 600 ``` 601 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope 602 ``` 603 */ 604 makeScope = 605 newScope: f: 606 let 607 self = f self // { 608 newScope = scope: newScope (self // scope); 609 callPackage = self.newScope { }; 610 overrideScope = g: makeScope newScope (extends g f); 611 packages = f; 612 }; 613 in 614 self; 615 616 /** 617 backward compatibility with old uncurried form; deprecated 618 619 # Inputs 620 621 `splicePackages` 622 623 : 1\. Function argument 624 625 `newScope` 626 627 : 2\. Function argument 628 629 `otherSplices` 630 631 : 3\. Function argument 632 633 `keep` 634 635 : 4\. Function argument 636 637 `extra` 638 639 : 5\. Function argument 640 641 `f` 642 643 : 6\. Function argument 644 */ 645 makeScopeWithSplicing = 646 splicePackages: newScope: otherSplices: keep: extra: f: 647 makeScopeWithSplicing' { inherit splicePackages newScope; } { 648 inherit 649 otherSplices 650 keep 651 extra 652 f 653 ; 654 }; 655 656 /** 657 Like makeScope, but aims to support cross compilation. It's still ugly, but 658 hopefully it helps a little bit. 659 660 # Type 661 662 ``` 663 makeScopeWithSplicing' :: 664 { splicePackages :: Splice -> AttrSet 665 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 666 } 667 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet } 668 -> AttrSet 669 670 Splice :: 671 { pkgsBuildBuild :: AttrSet 672 , pkgsBuildHost :: AttrSet 673 , pkgsBuildTarget :: AttrSet 674 , pkgsHostHost :: AttrSet 675 , pkgsHostTarget :: AttrSet 676 , pkgsTargetTarget :: AttrSet 677 } 678 ``` 679 */ 680 makeScopeWithSplicing' = 681 { 682 splicePackages, 683 newScope, 684 }: 685 { 686 otherSplices, 687 # Attrs from `self` which won't be spliced. 688 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201. 689 # ex: `keep = (self: { inherit (self) aAttr; })` 690 keep ? (_self: { }), 691 # Additional attrs to add to the sets `callPackage`. 692 # When the package is from a subset (but not a subset within a package IS #211340) 693 # within `spliced0` it will be spliced. 694 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`. 695 # If the package is not available within the set or in `pkgs`, such as a package in a let binding, it will not be spliced 696 # ex: 697 # ``` 698 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation 699 # «derivation ...CoreFoundation-11.0.0.drv» 700 # nix-repl> darwin.CoreFoundation 701 # error: attribute 'CoreFoundation' missing 702 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { } 703 # «derivation ...CoreFoundation-11.0.0.drv» 704 # ``` 705 extra ? (_spliced0: { }), 706 f, 707 }: 708 let 709 spliced0 = splicePackages { 710 pkgsBuildBuild = otherSplices.selfBuildBuild; 711 pkgsBuildHost = otherSplices.selfBuildHost; 712 pkgsBuildTarget = otherSplices.selfBuildTarget; 713 pkgsHostHost = otherSplices.selfHostHost; 714 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`; 715 pkgsTargetTarget = otherSplices.selfTargetTarget; 716 }; 717 spliced = extra spliced0 // spliced0 // keep self; 718 self = f self // { 719 newScope = scope: newScope (spliced // scope); 720 callPackage = newScope spliced; # == self.newScope {}; 721 # N.B. the other stages of the package set spliced in are *not* 722 # overridden. 723 overrideScope = 724 g: 725 (makeScopeWithSplicing' { inherit splicePackages newScope; } { 726 inherit otherSplices keep extra; 727 f = extends g f; 728 }); 729 packages = f; 730 }; 731 in 732 self; 733 734 /** 735 Define a `mkDerivation`-like function based on another `mkDerivation`-like function. 736 737 [`stdenv.mkDerivation`](#part-stdenv) gives access to 738 its final set of derivation attributes when it is passed a function, 739 or when it is passed an overlay-style function in `overrideAttrs`. 740 741 Instead of composing new `stdenv.mkDerivation`-like build helpers 742 using normal function composition, 743 `extendMkDerivation` makes sure that the returned build helper 744 supports such first class recursion like `mkDerivation` does. 745 746 `extendMkDerivation` takes an extra attribute set to configure its behaviour. 747 One can optionally specify 748 `transformDrv` to specify a function to apply to the result derivation, 749 or `inheritFunctionArgs` to decide whether to inherit the `__functionArgs` 750 from the base build helper. 751 752 # Inputs 753 754 `extendMkDerivation`-specific configurations 755 : `constructDrv`: Base build helper, the `mkDerivation`-like build helper to extend. 756 : `excludeDrvArgNames`: Argument names not to pass from the input fixed-point arguments to `constructDrv`. Note: It doesn't apply to the updating arguments returned by `extendDrvArgs`. 757 : `extendDrvArgs` : An extension (overlay) of the argument set, like the one taken by [overrideAttrs](#sec-pkg-overrideAttrs) but applied before passing to `constructDrv`. 758 : `inheritFunctionArgs`: Whether to inherit `__functionArgs` from the base build helper (default to `true`). 759 : `transformDrv`: Function to apply to the result derivation (default to `lib.id`). 760 761 # Type 762 763 ``` 764 extendMkDerivation :: 765 { 766 constructDrv :: ((FixedPointArgs | AttrSet) -> a) 767 excludeDrvArgNames :: [ String ], 768 extendDrvArgs :: (AttrSet -> AttrSet -> AttrSet) 769 inheritFunctionArgs :: Bool, 770 transformDrv :: a -> a, 771 } 772 -> (FixedPointArgs | AttrSet) -> a 773 774 FixedPointArgs = AttrSet -> AttrSet 775 a = Derivation when defining a build helper 776 ``` 777 778 # Examples 779 780 :::{.example} 781 ## `lib.customisation.extendMkDerivation` usage example 782 ```nix-repl 783 mkLocalDerivation = lib.extendMkDerivation { 784 constructDrv = pkgs.stdenv.mkDerivation; 785 excludeDrvArgNames = [ "specialArg" ]; 786 extendDrvArgs = 787 finalAttrs: args@{ preferLocalBuild ? true, allowSubstitute ? false, specialArg ? (_: false), ... }: 788 { inherit preferLocalBuild allowSubstitute; passthru = { inherit specialArg; } // args.passthru or { }; }; 789 } 790 791 mkLocalDerivation.__functionArgs 792 => { allowSubstitute = true; preferLocalBuild = true; specialArg = true; } 793 794 mkLocalDerivation { inherit (pkgs.hello) pname version src; specialArg = _: false; } 795 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv» 796 797 mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; specialArg = _: false; }) 798 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv» 799 800 (mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; passthru = { foo = "a"; bar = "${finalAttrs.passthru.foo}b"; }; })).bar 801 => "ab" 802 ``` 803 ::: 804 805 :::{.note} 806 If `transformDrv` is specified, 807 it should take care of existing attributes that perform overriding 808 (e.g., [`overrideAttrs`](#sec-pkg-overrideAttrs)) 809 to ensure that the overriding functionality of the result derivation 810 work as expected. 811 Modifications that breaks the overriding include 812 direct [attribute set update](https://nixos.org/manual/nix/stable/language/operators#update) 813 and [`lib.extendDerivation`](#function-library-lib.customisation.extendDerivation). 814 ::: 815 */ 816 extendMkDerivation = 817 let 818 extendsWithExclusion = 819 excludedNames: g: f: final: 820 let 821 previous = f final; 822 in 823 removeAttrs previous excludedNames // g final previous; 824 in 825 { 826 constructDrv, 827 excludeDrvArgNames ? [ ], 828 extendDrvArgs, 829 inheritFunctionArgs ? true, 830 transformDrv ? id, 831 }: 832 setFunctionArgs 833 # Adds the fixed-point style support 834 ( 835 fpargs: 836 transformDrv ( 837 constructDrv (extendsWithExclusion excludeDrvArgNames extendDrvArgs (toFunction fpargs)) 838 ) 839 ) 840 # Add __functionArgs 841 ( 842 # Inherit the __functionArgs from the base build helper 843 optionalAttrs inheritFunctionArgs (removeAttrs (functionArgs constructDrv) excludeDrvArgNames) 844 # Recover the __functionArgs from the derived build helper 845 // functionArgs (extendDrvArgs { }) 846 ) 847 // { 848 inherit 849 # Expose to the result build helper. 850 constructDrv 851 excludeDrvArgNames 852 extendDrvArgs 853 transformDrv 854 ; 855 }; 856}