at 25.11-pre 25 kB view raw
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 fn + optionalString (pathIsDirectory fn) "/default.nix" 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 { 451 inherit (drv) name system meta; 452 inherit outputs; 453 } 454 // optionalAttrs (drv._hydraAggregate or false) { 455 _hydraAggregate = true; 456 constituents = map hydraJob (flatten drv.constituents); 457 } 458 // (listToAttrs outputsList); 459 460 makeOutput = 461 outputName: 462 let 463 output = drv.${outputName}; 464 in 465 { 466 name = outputName; 467 value = commonAttrs // { 468 outPath = output.outPath; 469 drvPath = output.drvPath; 470 type = "derivation"; 471 inherit outputName; 472 }; 473 }; 474 475 outputsList = map makeOutput outputs; 476 477 drv' = (head outputsList).value; 478 in 479 if drv == null then null else deepSeq drv' drv'; 480 481 /** 482 Make an attribute set (a "scope") from functions that take arguments from that same attribute set. 483 See [](#ex-makeScope) for how to use it. 484 485 # Inputs 486 487 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`) 488 489 A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output. 490 491 Typical values are `callPackageWith` or the output attribute `newScope`. 492 493 2. `f` (`AttrSet -> AttrSet`) 494 495 A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set. 496 497 This function is used to compute the fixpoint of the resulting scope using `callPackage`. 498 Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`. 499 500 See [](#ex-makeScope) for how to use it. 501 See [](#sec-functions-library-fixedPoints) for details on fixpoint computation. 502 503 # Output 504 505 `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`: 506 507 ``` 508 scope :: { 509 callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a 510 newScope = AttrSet -> scope 511 overrideScope = (scope -> scope -> AttrSet) -> scope 512 packages :: AttrSet -> AttrSet 513 } 514 ``` 515 516 - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`) 517 518 A function that 519 520 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`, 521 2. Takes an attribute set `args` with explicit attributes to pass to `p`, 522 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`. 523 524 All such functions `p` will be called with the same value for `attrs`. 525 526 See [](#ex-makeScope-callPackage) for how to use it. 527 528 - `newScope` (`AttrSet -> scope`) 529 530 Takes an attribute set `attrs` and returns a scope that extends the original scope. 531 532 - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`) 533 534 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`. 535 See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details. 536 537 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. 538 539 - `packages` (`AttrSet -> AttrSet`) 540 541 The value of the argument `f` to `makeScope`. 542 543 - final attributes 544 545 The final values returned by `f`. 546 547 # Examples 548 549 :::{#ex-makeScope .example} 550 # Create an interdependent package set on top of `pkgs` 551 552 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. 553 554 ```nix 555 let 556 pkgs = import <nixpkgs> { }; 557 in 558 pkgs.lib.makeScope pkgs.newScope (self: { 559 foo = self.callPackage ./foo.nix { }; 560 bar = self.callPackage ./bar.nix { }; 561 }) 562 ``` 563 564 evaluates to 565 566 ```nix 567 { 568 callPackage = «lambda»; 569 newScope = «lambda»; 570 overrideScope = «lambda»; 571 packages = «lambda»; 572 foo = «derivation»; 573 bar = «derivation»; 574 } 575 ``` 576 ::: 577 578 :::{#ex-makeScope-callPackage .example} 579 # Using `callPackage` from a scope 580 581 ```nix 582 let 583 pkgs = import <nixpkgs> { }; 584 inherit (pkgs) lib; 585 scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; }); 586 three = scope.callPackage ({ a, b }: a + b) { }; 587 four = scope.callPackage ({ a, b }: a + b) { a = 2; }; 588 in 589 [ three four ] 590 ``` 591 592 evaluates to 593 594 ```nix 595 [ 3 4 ] 596 ``` 597 ::: 598 599 # Type 600 601 ``` 602 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope 603 ``` 604 */ 605 makeScope = 606 newScope: f: 607 let 608 self = f self // { 609 newScope = scope: newScope (self // scope); 610 callPackage = self.newScope { }; 611 overrideScope = g: makeScope newScope (extends g f); 612 packages = f; 613 }; 614 in 615 self; 616 617 /** 618 backward compatibility with old uncurried form; deprecated 619 620 # Inputs 621 622 `splicePackages` 623 624 : 1\. Function argument 625 626 `newScope` 627 628 : 2\. Function argument 629 630 `otherSplices` 631 632 : 3\. Function argument 633 634 `keep` 635 636 : 4\. Function argument 637 638 `extra` 639 640 : 5\. Function argument 641 642 `f` 643 644 : 6\. Function argument 645 */ 646 makeScopeWithSplicing = 647 splicePackages: newScope: otherSplices: keep: extra: f: 648 makeScopeWithSplicing' { inherit splicePackages newScope; } { 649 inherit 650 otherSplices 651 keep 652 extra 653 f 654 ; 655 }; 656 657 /** 658 Like makeScope, but aims to support cross compilation. It's still ugly, but 659 hopefully it helps a little bit. 660 661 # Type 662 663 ``` 664 makeScopeWithSplicing' :: 665 { splicePackages :: Splice -> AttrSet 666 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 667 } 668 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet } 669 -> AttrSet 670 671 Splice :: 672 { pkgsBuildBuild :: AttrSet 673 , pkgsBuildHost :: AttrSet 674 , pkgsBuildTarget :: AttrSet 675 , pkgsHostHost :: AttrSet 676 , pkgsHostTarget :: AttrSet 677 , pkgsTargetTarget :: AttrSet 678 } 679 ``` 680 */ 681 makeScopeWithSplicing' = 682 { 683 splicePackages, 684 newScope, 685 }: 686 { 687 otherSplices, 688 # Attrs from `self` which won't be spliced. 689 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201. 690 # ex: `keep = (self: { inherit (self) aAttr; })` 691 keep ? (_self: { }), 692 # Additional attrs to add to the sets `callPackage`. 693 # When the package is from a subset (but not a subset within a package IS #211340) 694 # within `spliced0` it will be spliced. 695 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`. 696 # 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 697 # ex: 698 # ``` 699 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation 700 # «derivation ...CoreFoundation-11.0.0.drv» 701 # nix-repl> darwin.CoreFoundation 702 # error: attribute 'CoreFoundation' missing 703 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { } 704 # «derivation ...CoreFoundation-11.0.0.drv» 705 # ``` 706 extra ? (_spliced0: { }), 707 f, 708 }: 709 let 710 spliced0 = splicePackages { 711 pkgsBuildBuild = otherSplices.selfBuildBuild; 712 pkgsBuildHost = otherSplices.selfBuildHost; 713 pkgsBuildTarget = otherSplices.selfBuildTarget; 714 pkgsHostHost = otherSplices.selfHostHost; 715 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`; 716 pkgsTargetTarget = otherSplices.selfTargetTarget; 717 }; 718 spliced = extra spliced0 // spliced0 // keep self; 719 self = f self // { 720 newScope = scope: newScope (spliced // scope); 721 callPackage = newScope spliced; # == self.newScope {}; 722 # N.B. the other stages of the package set spliced in are *not* 723 # overridden. 724 overrideScope = 725 g: 726 (makeScopeWithSplicing' { inherit splicePackages newScope; } { 727 inherit otherSplices keep extra; 728 f = extends g f; 729 }); 730 packages = f; 731 }; 732 in 733 self; 734 735 /** 736 Define a `mkDerivation`-like function based on another `mkDerivation`-like function. 737 738 [`stdenv.mkDerivation`](#part-stdenv) gives access to 739 its final set of derivation attributes when it is passed a function, 740 or when it is passed an overlay-style function in `overrideAttrs`. 741 742 Instead of composing new `stdenv.mkDerivation`-like build helpers 743 using normal function composition, 744 `extendMkDerivation` makes sure that the returned build helper 745 supports such first class recursion like `mkDerivation` does. 746 747 `extendMkDerivation` takes an extra attribute set to configure its behaviour. 748 One can optionally specify 749 `transformDrv` to specify a function to apply to the result derivation, 750 or `inheritFunctionArgs` to decide whether to inherit the `__functionArgs` 751 from the base build helper. 752 753 # Inputs 754 755 `extendMkDerivation`-specific configurations 756 : `constructDrv`: Base build helper, the `mkDerivation`-like build helper to extend. 757 : `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`. 758 : `extendDrvArgs` : An extension (overlay) of the argument set, like the one taken by [overrideAttrs](#sec-pkg-overrideAttrs) but applied before passing to `constructDrv`. 759 : `inheritFunctionArgs`: Whether to inherit `__functionArgs` from the base build helper (default to `true`). 760 : `transformDrv`: Function to apply to the result derivation (default to `lib.id`). 761 762 # Type 763 764 ``` 765 extendMkDerivation :: 766 { 767 constructDrv :: ((FixedPointArgs | AttrSet) -> a) 768 excludeDrvArgNames :: [ String ], 769 extendDrvArgs :: (AttrSet -> AttrSet -> AttrSet) 770 inheritFunctionArgs :: Bool, 771 transformDrv :: a -> a, 772 } 773 -> (FixedPointArgs | AttrSet) -> a 774 775 FixedPointArgs = AttrSet -> AttrSet 776 a = Derivation when defining a build helper 777 ``` 778 779 # Examples 780 781 :::{.example} 782 ## `lib.customisation.extendMkDerivation` usage example 783 ```nix-repl 784 mkLocalDerivation = lib.extendMkDerivation { 785 constructDrv = pkgs.stdenv.mkDerivation; 786 excludeDrvArgNames = [ "specialArg" ]; 787 extendDrvArgs = 788 finalAttrs: args@{ preferLocalBuild ? true, allowSubstitute ? false, specialArg ? (_: false), ... }: 789 { inherit preferLocalBuild allowSubstitute; passthru = { inherit specialArg; } // args.passthru or { }; }; 790 } 791 792 mkLocalDerivation.__functionArgs 793 => { allowSubstitute = true; preferLocalBuild = true; specialArg = true; } 794 795 mkLocalDerivation { inherit (pkgs.hello) pname version src; specialArg = _: false; } 796 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv» 797 798 mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; specialArg = _: false; }) 799 => «derivation /nix/store/xirl67m60ahg6jmzicx43a81g635g8z8-hello-2.12.1.drv» 800 801 (mkLocalDerivation (finalAttrs: { inherit (pkgs.hello) pname version src; passthru = { foo = "a"; bar = "${finalAttrs.passthru.foo}b"; }; })).bar 802 => "ab" 803 ``` 804 ::: 805 806 :::{.note} 807 If `transformDrv` is specified, 808 it should take care of existing attributes that perform overriding 809 (e.g., [`overrideAttrs`](#sec-pkg-overrideAttrs)) 810 to ensure that the overriding functionality of the result derivation 811 work as expected. 812 Modifications that breaks the overriding include 813 direct [attribute set update](https://nixos.org/manual/nix/stable/language/operators#update) 814 and [`lib.extendDerivation`](#function-library-lib.customisation.extendDerivation). 815 ::: 816 */ 817 extendMkDerivation = 818 let 819 extendsWithExclusion = 820 excludedNames: g: f: final: 821 let 822 previous = f final; 823 in 824 removeAttrs previous excludedNames // g final previous; 825 in 826 { 827 constructDrv, 828 excludeDrvArgNames ? [ ], 829 extendDrvArgs, 830 inheritFunctionArgs ? true, 831 transformDrv ? id, 832 }: 833 setFunctionArgs 834 # Adds the fixed-point style support 835 ( 836 fpargs: 837 transformDrv ( 838 constructDrv (extendsWithExclusion excludeDrvArgNames extendDrvArgs (toFunction fpargs)) 839 ) 840 ) 841 # Add __functionArgs 842 ( 843 # Inherit the __functionArgs from the base build helper 844 optionalAttrs inheritFunctionArgs (removeAttrs (functionArgs constructDrv) excludeDrvArgNames) 845 # Recover the __functionArgs from the derived build helper 846 // functionArgs (extendDrvArgs { }) 847 ) 848 // { 849 inherit 850 # Expose to the result build helper. 851 constructDrv 852 excludeDrvArgNames 853 extendDrvArgs 854 transformDrv 855 ; 856 }; 857}