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}