evillimiter: modernize (#352969)
[NixPkgs.git] / lib / customisation.nix
blobbcdc94f3c4c304c0caba7fead8f668436fefa0a8
1 { lib }:
3 let
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;
15 rec {
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.
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.
31     For another application, see build-support/vm, where this
32     function is used to build arbitrary derivations inside a QEMU
33     virtual machine.
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.
40     You should in general prefer `drv.overrideAttrs` over this function;
41     see the nixpkgs manual for more information on overriding.
44     # Inputs
46     `drv`
48     : 1\. Function argument
50     `f`
52     : 2\. Function argument
54     # Type
56     ```
57     overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation
58     ```
60     # Examples
61     :::{.example}
62     ## `lib.customisation.overrideDerivation` usage example
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     ```
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       });
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.
97     Please refer to  documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats
98     related to its use.
101     # Inputs
103     `f`
105     : 1\. Function argument
107     # Type
109     ```
110     makeOverridable :: (AttrSet -> a) -> AttrSet -> a
111     ```
113     # Examples
114     :::{.example}
115     ## `lib.customisation.makeOverridable` usage example
117     ```nix
118     nix-repl> x = {a, b}: { result = a + b; }
120     nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
122     nix-repl> y
123     { override = «lambda»; overrideDerivation = «lambda»; result = 3; }
125     nix-repl> y.override { a = 10; }
126     { override = «lambda»; overrideDerivation = «lambda»; result = 12; }
127     ```
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;
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);
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);
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.,
170       ```nix
171       callPackage = callPackageWith pkgs;
172       pkgs = {
173         libfoo = callPackage ./foo.nix { };
174         libbar = callPackage ./bar.nix { };
175       };
176       ```
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.
182       ```nix
183       libbar = callPackage ./bar.nix {
184         libfoo = null;
185         enableX11 = true;
186       };
187       ```
189     <!-- TODO: Apply "Example:" tag to the examples above -->
192     # Inputs
194     `autoArgs`
196     : 1\. Function argument
198     `fn`
200     : 2\. Function argument
202     `args`
204     : 3\. Function argument
206     # Type
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;
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;
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)));
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       ];
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}?";
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)}";
260       # Only show the error for the first missing argument
261       error = errorForArg (head (attrNames missingArgs));
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}";
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.
278     # Inputs
280     `autoArgs`
282     : 1\. Function argument
284     `fn`
286     : 2\. Function argument
288     `args`
290     : 3\. Function argument
292     # Type
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;
314   /**
315     Add attributes to each output of a derivation without changing
316     the derivation itself and check a given condition when evaluating.
319     # Inputs
321     `condition`
323     : 1\. Function argument
325     `passthru`
327     : 2\. Function argument
329     `drv`
331     : 3\. Function argument
333     # Type
335     ```
336     extendDerivation :: Bool -> Any -> Derivation -> Derivation
337     ```
338   */
339   extendDerivation = condition: passthru: drv:
340     let
341       outputs = drv.outputs or [ "out" ];
343       commonAttrs = drv // (listToAttrs outputsList) //
344         ({ all = map (x: x.value) outputsList; }) // passthru;
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         };
363       outputsList = map outputToAttrListElement outputs;
364     in commonAttrs // {
365       drvPath = assert condition; drv.drvPath;
366       outPath = assert condition; drv.outPath;
367     };
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.
376     # Inputs
378     `drv`
380     : 1\. Function argument
382     # Type
384     ```
385     hydraJob :: (Derivation | Null) -> (Derivation | Null)
386     ```
387   */
388   hydraJob = drv:
389     let
390       outputs = drv.outputs or ["out"];
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);
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         };
411       outputsList = map makeOutput outputs;
413       drv' = (head outputsList).value;
414     in if drv == null then null else
415       deepSeq drv' drv';
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.
421     # Inputs
423     1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`)
425        A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output.
427        Typical values are `callPackageWith` or the output attribute `newScope`.
429     2. `f` (`AttrSet -> AttrSet`)
431        A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set.
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`.
436        See [](#ex-makeScope) for how to use it.
437        See [](#sec-functions-library-fixedPoints) for details on fixpoint computation.
439     # Output
441     `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`:
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     ```
452     - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`)
454       A function that
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`.
460       All such functions `p` will be called with the same value for `attrs`.
462       See [](#ex-makeScope-callPackage) for how to use it.
464     - `newScope` (`AttrSet -> scope`)
466       Takes an attribute set `attrs` and returns a scope that extends the original scope.
468     - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`)
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.
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.
475     - `packages` (`AttrSet -> AttrSet`)
477       The value of the argument `f` to `makeScope`.
479     - final attributes
481       The final values returned by `f`.
483     # Examples
485     :::{#ex-makeScope .example}
486     # Create an interdependent package set on top of `pkgs`
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.
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     ```
500     evaluates to
502     ```nix
503     {
504       callPackage = «lambda»;
505       newScope = «lambda»;
506       overrideScope = «lambda»;
507       packages = «lambda»;
508       foo = «derivation»;
509       bar = «derivation»;
510     }
511     ```
512     :::
514     :::{#ex-makeScope-callPackage .example}
515     # Using `callPackage` from a scope
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     ```
528     evaluates to
530     ```nix
531     [ 3 4 ]
532     ```
533     :::
535     # Type
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;
554   /**
555     backward compatibility with old uncurried form; deprecated
558     # Inputs
560     `splicePackages`
562     : 1\. Function argument
564     `newScope`
566     : 2\. Function argument
568     `otherSplices`
570     : 3\. Function argument
572     `keep`
574     : 4\. Function argument
576     `extra`
578     : 5\. Function argument
580     `f`
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; };
590   /**
591     Like makeScope, but aims to support cross compilation. It's still ugly, but
592     hopefully it helps a little bit.
594     # Type
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
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;