1{ lib }:
2
3let
4 inherit (builtins)
5 intersectAttrs;
6 inherit (lib)
7 functionArgs isFunction mirrorFunctionArgs isAttrs setFunctionArgs
8 optionalAttrs attrNames filter elemAt concatStringsSep sortOn take length
9 filterAttrs optionalString flip pathIsDirectory head pipe isDerivation listToAttrs
10 mapAttrs seq flatten deepSeq warnIf isInOldestRelease extends
11 ;
12 inherit (lib.strings) levenshtein levenshteinAtMost;
13
14in
15rec {
16
17
18 /**
19 `overrideDerivation drv f` takes a derivation (i.e., the result
20 of a call to the builtin function `derivation`) and returns a new
21 derivation in which the attributes of the original are overridden
22 according to the function `f`. The function `f` is called with
23 the original derivation attributes.
24
25 `overrideDerivation` allows certain "ad-hoc" customisation
26 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance,
27 if you want to "patch" the derivation returned by a package
28 function in Nixpkgs to build another version than what the
29 function itself provides.
30
31 For another application, see build-support/vm, where this
32 function is used to build arbitrary derivations inside a QEMU
33 virtual machine.
34
35 Note that in order to preserve evaluation errors, the new derivation's
36 outPath depends on the old one's, which means that this function cannot
37 be used in circular situations when the old derivation also depends on the
38 new one.
39
40 You should in general prefer `drv.overrideAttrs` over this function;
41 see the nixpkgs manual for more information on overriding.
42
43
44 # Inputs
45
46 `drv`
47
48 : 1\. Function argument
49
50 `f`
51
52 : 2\. Function argument
53
54 # Type
55
56 ```
57 overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation
58 ```
59
60 # Examples
61 :::{.example}
62 ## `lib.customisation.overrideDerivation` usage example
63
64 ```nix
65 mySed = overrideDerivation pkgs.gnused (oldAttrs: {
66 name = "sed-4.2.2-pre";
67 src = fetchurl {
68 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
69 hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY=";
70 };
71 patches = [];
72 });
73 ```
74
75 :::
76 */
77 overrideDerivation = drv: f:
78 let
79 newDrv = derivation (drv.drvAttrs // (f drv));
80 in flip (extendDerivation (seq drv.drvPath true)) newDrv (
81 { meta = drv.meta or {};
82 passthru = if drv ? passthru then drv.passthru else {};
83 }
84 //
85 (drv.passthru or {})
86 //
87 optionalAttrs (drv ? __spliced) {
88 __spliced = {} // (mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced);
89 });
90
91
92 /**
93 `makeOverridable` takes a function from attribute set to attribute set and
94 injects `override` attribute which can be used to override arguments of
95 the function.
96
97 Please refer to documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats
98 related to its use.
99
100
101 # Inputs
102
103 `f`
104
105 : 1\. Function argument
106
107 # Type
108
109 ```
110 makeOverridable :: (AttrSet -> a) -> AttrSet -> a
111 ```
112
113 # Examples
114 :::{.example}
115 ## `lib.customisation.makeOverridable` usage example
116
117 ```nix
118 nix-repl> x = {a, b}: { result = a + b; }
119
120 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
121
122 nix-repl> y
123 { override = «lambda»; overrideDerivation = «lambda»; result = 3; }
124
125 nix-repl> y.override { a = 10; }
126 { override = «lambda»; overrideDerivation = «lambda»; result = 12; }
127 ```
128
129 :::
130 */
131 makeOverridable = f:
132 let
133 # Creates a functor with the same arguments as f
134 mirrorArgs = mirrorFunctionArgs f;
135 in
136 mirrorArgs (origArgs:
137 let
138 result = f origArgs;
139
140 # Changes the original arguments with (potentially a function that returns) a set of new attributes
141 overrideWith = newArgs: origArgs // (if isFunction newArgs then newArgs origArgs else newArgs);
142
143 # Re-call the function but with different arguments
144 overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs));
145 # Change the result of the function call by applying g to it
146 overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
147 in
148 if isAttrs result then
149 result // {
150 override = overrideArgs;
151 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
152 ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
153 overrideResult (x: x.overrideAttrs fdrv);
154 }
155 else if isFunction result then
156 # Transform the result into a functor while propagating its arguments
157 setFunctionArgs result (functionArgs result) // {
158 override = overrideArgs;
159 }
160 else result);
161
162
163 /**
164 Call the package function in the file `fn` with the required
165 arguments automatically. The function is called with the
166 arguments `args`, but any missing arguments are obtained from
167 `autoArgs`. This function is intended to be partially
168 parameterised, e.g.,
169
170 ```nix
171 callPackage = callPackageWith pkgs;
172 pkgs = {
173 libfoo = callPackage ./foo.nix { };
174 libbar = callPackage ./bar.nix { };
175 };
176 ```
177
178 If the `libbar` function expects an argument named `libfoo`, it is
179 automatically passed as an argument. Overrides or missing
180 arguments can be supplied in `args`, e.g.
181
182 ```nix
183 libbar = callPackage ./bar.nix {
184 libfoo = null;
185 enableX11 = true;
186 };
187 ```
188
189 <!-- TODO: Apply "Example:" tag to the examples above -->
190
191
192 # Inputs
193
194 `autoArgs`
195
196 : 1\. Function argument
197
198 `fn`
199
200 : 2\. Function argument
201
202 `args`
203
204 : 3\. Function argument
205
206 # Type
207
208 ```
209 callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
210 ```
211 */
212 callPackageWith = autoArgs: fn: args:
213 let
214 f = if isFunction fn then fn else import fn;
215 fargs = functionArgs f;
216
217 # All arguments that will be passed to the function
218 # This includes automatic ones and ones passed explicitly
219 allArgs = intersectAttrs fargs autoArgs // args;
220
221 # a list of argument names that the function requires, but
222 # wouldn't be passed to it
223 missingArgs =
224 # Filter out arguments that have a default value
225 (filterAttrs (name: value: ! value)
226 # Filter out arguments that would be passed
227 (removeAttrs fargs (attrNames allArgs)));
228
229 # Get a list of suggested argument names for a given missing one
230 getSuggestions = arg: pipe (autoArgs // args) [
231 attrNames
232 # Only use ones that are at most 2 edits away. While mork would work,
233 # levenshteinAtMost is only fast for 2 or less.
234 (filter (levenshteinAtMost 2 arg))
235 # Put strings with shorter distance first
236 (sortOn (levenshtein arg))
237 # Only take the first couple results
238 (take 3)
239 # Quote all entries
240 (map (x: "\"" + x + "\""))
241 ];
242
243 prettySuggestions = suggestions:
244 if suggestions == [] then ""
245 else if length suggestions == 1 then ", did you mean ${elemAt suggestions 0}?"
246 else ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
247
248 errorForArg = arg:
249 let
250 loc = builtins.unsafeGetAttrPos arg fargs;
251 # loc' can be removed once lib/minver.nix is >2.3.4, since that includes
252 # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null
253 loc' = if loc != null then loc.file + ":" + toString loc.line
254 else if ! isFunction fn then
255 toString fn + optionalString (pathIsDirectory fn) "/default.nix"
256 else "<unknown location>";
257 in "Function called without required argument \"${arg}\" at "
258 + "${loc'}${prettySuggestions (getSuggestions arg)}";
259
260 # Only show the error for the first missing argument
261 error = errorForArg (head (attrNames missingArgs));
262
263 in if missingArgs == {}
264 then makeOverridable f allArgs
265 # This needs to be an abort so it can't be caught with `builtins.tryEval`,
266 # which is used by nix-env and ofborg to filter out packages that don't evaluate.
267 # This way we're forced to fix such errors in Nixpkgs,
268 # which is especially relevant with allowAliases = false
269 else abort "lib.customisation.callPackageWith: ${error}";
270
271
272 /**
273 Like callPackage, but for a function that returns an attribute
274 set of derivations. The override function is added to the
275 individual attributes.
276
277
278 # Inputs
279
280 `autoArgs`
281
282 : 1\. Function argument
283
284 `fn`
285
286 : 2\. Function argument
287
288 `args`
289
290 : 3\. Function argument
291
292 # Type
293
294 ```
295 callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet
296 ```
297 */
298 callPackagesWith = autoArgs: fn: args:
299 let
300 f = if isFunction fn then fn else import fn;
301 auto = intersectAttrs (functionArgs f) autoArgs;
302 mirrorArgs = mirrorFunctionArgs f;
303 origArgs = auto // args;
304 pkgs = f origArgs;
305 mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs;
306 in
307 if isDerivation pkgs then throw
308 ("function `callPackages` was called on a *single* derivation "
309 + ''"${pkgs.name or "<unknown-name>"}";''
310 + " did you mean to use `callPackage` instead?")
311 else mapAttrs mkAttrOverridable pkgs;
312
313
314 /**
315 Add attributes to each output of a derivation without changing
316 the derivation itself and check a given condition when evaluating.
317
318
319 # Inputs
320
321 `condition`
322
323 : 1\. Function argument
324
325 `passthru`
326
327 : 2\. Function argument
328
329 `drv`
330
331 : 3\. Function argument
332
333 # Type
334
335 ```
336 extendDerivation :: Bool -> Any -> Derivation -> Derivation
337 ```
338 */
339 extendDerivation = condition: passthru: drv:
340 let
341 outputs = drv.outputs or [ "out" ];
342
343 commonAttrs = drv // (listToAttrs outputsList) //
344 ({ all = map (x: x.value) outputsList; }) // passthru;
345
346 outputToAttrListElement = outputName:
347 { name = outputName;
348 value = commonAttrs // {
349 inherit (drv.${outputName}) type outputName;
350 outputSpecified = true;
351 drvPath = assert condition; drv.${outputName}.drvPath;
352 outPath = assert condition; drv.${outputName}.outPath;
353 } //
354 # TODO: give the derivation control over the outputs.
355 # `overrideAttrs` may not be the only attribute that needs
356 # updating when switching outputs.
357 optionalAttrs (passthru?overrideAttrs) {
358 # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
359 overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
360 };
361 };
362
363 outputsList = map outputToAttrListElement outputs;
364 in commonAttrs // {
365 drvPath = assert condition; drv.drvPath;
366 outPath = assert condition; drv.outPath;
367 };
368
369 /**
370 Strip a derivation of all non-essential attributes, returning
371 only those needed by hydra-eval-jobs. Also strictly evaluate the
372 result to ensure that there are no thunks kept alive to prevent
373 garbage collection.
374
375
376 # Inputs
377
378 `drv`
379
380 : 1\. Function argument
381
382 # Type
383
384 ```
385 hydraJob :: (Derivation | Null) -> (Derivation | Null)
386 ```
387 */
388 hydraJob = drv:
389 let
390 outputs = drv.outputs or ["out"];
391
392 commonAttrs =
393 { inherit (drv) name system meta; inherit outputs; }
394 // optionalAttrs (drv._hydraAggregate or false) {
395 _hydraAggregate = true;
396 constituents = map hydraJob (flatten drv.constituents);
397 }
398 // (listToAttrs outputsList);
399
400 makeOutput = outputName:
401 let output = drv.${outputName}; in
402 { name = outputName;
403 value = commonAttrs // {
404 outPath = output.outPath;
405 drvPath = output.drvPath;
406 type = "derivation";
407 inherit outputName;
408 };
409 };
410
411 outputsList = map makeOutput outputs;
412
413 drv' = (head outputsList).value;
414 in if drv == null then null else
415 deepSeq drv' drv';
416
417 /**
418 Make an attribute set (a "scope") from functions that take arguments from that same attribute set.
419 See [](#ex-makeScope) for how to use it.
420
421 # Inputs
422
423 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`)
424
425 A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output.
426
427 Typical values are `callPackageWith` or the output attribute `newScope`.
428
429 2. `f` (`AttrSet -> AttrSet`)
430
431 A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set.
432
433 This function is used to compute the fixpoint of the resulting scope using `callPackage`.
434 Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`.
435
436 See [](#ex-makeScope) for how to use it.
437 See [](#sec-functions-library-fixedPoints) for details on fixpoint computation.
438
439 # Output
440
441 `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`:
442
443 ```
444 scope :: {
445 callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a
446 newScope = AttrSet -> scope
447 overrideScope = (scope -> scope -> AttrSet) -> scope
448 packages :: AttrSet -> AttrSet
449 }
450 ```
451
452 - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`)
453
454 A function that
455
456 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`,
457 2. Takes an attribute set `args` with explicit attributes to pass to `p`,
458 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`.
459
460 All such functions `p` will be called with the same value for `attrs`.
461
462 See [](#ex-makeScope-callPackage) for how to use it.
463
464 - `newScope` (`AttrSet -> scope`)
465
466 Takes an attribute set `attrs` and returns a scope that extends the original scope.
467
468 - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`)
469
470 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`.
471 See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details.
472
473 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.
474
475 - `packages` (`AttrSet -> AttrSet`)
476
477 The value of the argument `f` to `makeScope`.
478
479 - final attributes
480
481 The final values returned by `f`.
482
483 # Examples
484
485 :::{#ex-makeScope .example}
486 # Create an interdependent package set on top of `pkgs`
487
488 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.
489
490 ```nix
491 let
492 pkgs = import <nixpkgs> { };
493 in
494 pkgs.lib.makeScope pkgs.newScope (self: {
495 foo = self.callPackage ./foo.nix { };
496 bar = self.callPackage ./bar.nix { };
497 })
498 ```
499
500 evaluates to
501
502 ```nix
503 {
504 callPackage = «lambda»;
505 newScope = «lambda»;
506 overrideScope = «lambda»;
507 packages = «lambda»;
508 foo = «derivation»;
509 bar = «derivation»;
510 }
511 ```
512 :::
513
514 :::{#ex-makeScope-callPackage .example}
515 # Using `callPackage` from a scope
516
517 ```nix
518 let
519 pkgs = import <nixpkgs> { };
520 inherit (pkgs) lib;
521 scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; });
522 three = scope.callPackage ({ a, b }: a + b) { };
523 four = scope.callPackage ({ a, b }: a + b) { a = 2; };
524 in
525 [ three four ]
526 ```
527
528 evaluates to
529
530 ```nix
531 [ 3 4 ]
532 ```
533 :::
534
535 # Type
536
537 ```
538 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope
539 ```
540 */
541 makeScope = newScope: f:
542 let self = f self // {
543 newScope = scope: newScope (self // scope);
544 callPackage = self.newScope {};
545 overrideScope = g: makeScope newScope (extends g f);
546 # Remove after 24.11 is released.
547 overrideScope' = g: warnIf (isInOldestRelease 2311)
548 "`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`."
549 (makeScope newScope (extends g f));
550 packages = f;
551 };
552 in self;
553
554 /**
555 backward compatibility with old uncurried form; deprecated
556
557
558 # Inputs
559
560 `splicePackages`
561
562 : 1\. Function argument
563
564 `newScope`
565
566 : 2\. Function argument
567
568 `otherSplices`
569
570 : 3\. Function argument
571
572 `keep`
573
574 : 4\. Function argument
575
576 `extra`
577
578 : 5\. Function argument
579
580 `f`
581
582 : 6\. Function argument
583 */
584 makeScopeWithSplicing =
585 splicePackages: newScope: otherSplices: keep: extra: f:
586 makeScopeWithSplicing'
587 { inherit splicePackages newScope; }
588 { inherit otherSplices keep extra f; };
589
590 /**
591 Like makeScope, but aims to support cross compilation. It's still ugly, but
592 hopefully it helps a little bit.
593
594 # Type
595
596 ```
597 makeScopeWithSplicing' ::
598 { splicePackages :: Splice -> AttrSet
599 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
600 }
601 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet }
602 -> AttrSet
603
604 Splice ::
605 { pkgsBuildBuild :: AttrSet
606 , pkgsBuildHost :: AttrSet
607 , pkgsBuildTarget :: AttrSet
608 , pkgsHostHost :: AttrSet
609 , pkgsHostTarget :: AttrSet
610 , pkgsTargetTarget :: AttrSet
611 }
612 ```
613 */
614 makeScopeWithSplicing' =
615 { splicePackages
616 , newScope
617 }:
618 { otherSplices
619 # Attrs from `self` which won't be spliced.
620 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201.
621 # ex: `keep = (self: { inherit (self) aAttr; })`
622 , keep ? (_self: {})
623 # Additional attrs to add to the sets `callPackage`.
624 # When the package is from a subset (but not a subset within a package IS #211340)
625 # within `spliced0` it will be spliced.
626 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`.
627 # 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
628 # ex:
629 # ```
630 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation
631 # «derivation ...CoreFoundation-11.0.0.drv»
632 # nix-repl> darwin.CoreFoundation
633 # error: attribute 'CoreFoundation' missing
634 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { }
635 # «derivation ...CoreFoundation-11.0.0.drv»
636 # ```
637 , extra ? (_spliced0: {})
638 , f
639 }:
640 let
641 spliced0 = splicePackages {
642 pkgsBuildBuild = otherSplices.selfBuildBuild;
643 pkgsBuildHost = otherSplices.selfBuildHost;
644 pkgsBuildTarget = otherSplices.selfBuildTarget;
645 pkgsHostHost = otherSplices.selfHostHost;
646 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`;
647 pkgsTargetTarget = otherSplices.selfTargetTarget;
648 };
649 spliced = extra spliced0 // spliced0 // keep self;
650 self = f self // {
651 newScope = scope: newScope (spliced // scope);
652 callPackage = newScope spliced; # == self.newScope {};
653 # N.B. the other stages of the package set spliced in are *not*
654 # overridden.
655 overrideScope = g: (makeScopeWithSplicing'
656 { inherit splicePackages newScope; }
657 { inherit otherSplices keep extra;
658 f = extends g f;
659 });
660 packages = f;
661 };
662 in self;
663
664}