typos: 1.16.22 -> 1.16.23
[NixPkgs.git] / lib / customisation.nix
blobc7d40339d05f5548eb36463a4bb6ae02371e15e7
1 { lib }:
3 rec {
6   /* `overrideDerivation drv f` takes a derivation (i.e., the result
7      of a call to the builtin function `derivation`) and returns a new
8      derivation in which the attributes of the original are overridden
9      according to the function `f`.  The function `f` is called with
10      the original derivation attributes.
12      `overrideDerivation` allows certain "ad-hoc" customisation
13      scenarios (e.g. in ~/.config/nixpkgs/config.nix).  For instance,
14      if you want to "patch" the derivation returned by a package
15      function in Nixpkgs to build another version than what the
16      function itself provides.
18      For another application, see build-support/vm, where this
19      function is used to build arbitrary derivations inside a QEMU
20      virtual machine.
22      Note that in order to preserve evaluation errors, the new derivation's
23      outPath depends on the old one's, which means that this function cannot
24      be used in circular situations when the old derivation also depends on the
25      new one.
27      You should in general prefer `drv.overrideAttrs` over this function;
28      see the nixpkgs manual for more information on overriding.
30      Example:
31        mySed = overrideDerivation pkgs.gnused (oldAttrs: {
32          name = "sed-4.2.2-pre";
33          src = fetchurl {
34            url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
35            hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY=";
36          };
37          patches = [];
38        });
40      Type:
41        overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation
42   */
43   overrideDerivation = drv: f:
44     let
45       newDrv = derivation (drv.drvAttrs // (f drv));
46     in lib.flip (extendDerivation (builtins.seq drv.drvPath true)) newDrv (
47       { meta = drv.meta or {};
48         passthru = if drv ? passthru then drv.passthru else {};
49       }
50       //
51       (drv.passthru or {})
52       //
53       lib.optionalAttrs (drv ? __spliced) {
54         __spliced = {} // (lib.mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced);
55       });
58   /* `makeOverridable` takes a function from attribute set to attribute set and
59      injects `override` attribute which can be used to override arguments of
60      the function.
62      Please refer to  documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats
63      related to its use.
65      Example:
66        nix-repl> x = {a, b}: { result = a + b; }
68        nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
70        nix-repl> y
71        { override = «lambda»; overrideDerivation = «lambda»; result = 3; }
73        nix-repl> y.override { a = 10; }
74        { override = «lambda»; overrideDerivation = «lambda»; result = 12; }
76      Type:
77        makeOverridable :: (AttrSet -> a) -> AttrSet -> a
78   */
79   makeOverridable = f: lib.setFunctionArgs
80     (origArgs: let
81       result = f origArgs;
83       # Creates a functor with the same arguments as f
84       copyArgs = g: lib.setFunctionArgs g (lib.functionArgs f);
85       # Changes the original arguments with (potentially a function that returns) a set of new attributes
86       overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
88       # Re-call the function but with different arguments
89       overrideArgs = copyArgs (newArgs: makeOverridable f (overrideWith newArgs));
90       # Change the result of the function call by applying g to it
91       overrideResult = g: makeOverridable (copyArgs (args: g (f args))) origArgs;
92     in
93       if builtins.isAttrs result then
94         result // {
95           override = overrideArgs;
96           overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
97           ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
98             overrideResult (x: x.overrideAttrs fdrv);
99         }
100       else if lib.isFunction result then
101         # Transform the result into a functor while propagating its arguments
102         lib.setFunctionArgs result (lib.functionArgs result) // {
103           override = overrideArgs;
104         }
105       else result)
106     (lib.functionArgs f);
109   /* Call the package function in the file `fn` with the required
110     arguments automatically.  The function is called with the
111     arguments `args`, but any missing arguments are obtained from
112     `autoArgs`.  This function is intended to be partially
113     parameterised, e.g.,
115       ```nix
116       callPackage = callPackageWith pkgs;
117       pkgs = {
118         libfoo = callPackage ./foo.nix { };
119         libbar = callPackage ./bar.nix { };
120       };
121       ```
123     If the `libbar` function expects an argument named `libfoo`, it is
124     automatically passed as an argument.  Overrides or missing
125     arguments can be supplied in `args`, e.g.
127       ```nix
128       libbar = callPackage ./bar.nix {
129         libfoo = null;
130         enableX11 = true;
131       };
132       ```
134     <!-- TODO: Apply "Example:" tag to the examples above -->
136     Type:
137       callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
138   */
139   callPackageWith = autoArgs: fn: args:
140     let
141       f = if lib.isFunction fn then fn else import fn;
142       fargs = lib.functionArgs f;
144       # All arguments that will be passed to the function
145       # This includes automatic ones and ones passed explicitly
146       allArgs = builtins.intersectAttrs fargs autoArgs // args;
148       # a list of argument names that the function requires, but
149       # wouldn't be passed to it
150       missingArgs = lib.attrNames
151         # Filter out arguments that have a default value
152         (lib.filterAttrs (name: value: ! value)
153         # Filter out arguments that would be passed
154         (removeAttrs fargs (lib.attrNames allArgs)));
156       # Get a list of suggested argument names for a given missing one
157       getSuggestions = arg: lib.pipe (autoArgs // args) [
158         lib.attrNames
159         # Only use ones that are at most 2 edits away. While mork would work,
160         # levenshteinAtMost is only fast for 2 or less.
161         (lib.filter (lib.strings.levenshteinAtMost 2 arg))
162         # Put strings with shorter distance first
163         (lib.sort (x: y: lib.strings.levenshtein x arg < lib.strings.levenshtein y arg))
164         # Only take the first couple results
165         (lib.take 3)
166         # Quote all entries
167         (map (x: "\"" + x + "\""))
168       ];
170       prettySuggestions = suggestions:
171         if suggestions == [] then ""
172         else if lib.length suggestions == 1 then ", did you mean ${lib.elemAt suggestions 0}?"
173         else ", did you mean ${lib.concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
175       errorForArg = arg:
176         let
177           loc = builtins.unsafeGetAttrPos arg fargs;
178           # loc' can be removed once lib/minver.nix is >2.3.4, since that includes
179           # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null
180           loc' = if loc != null then loc.file + ":" + toString loc.line
181             else if ! lib.isFunction fn then
182               toString fn + lib.optionalString (lib.sources.pathIsDirectory fn) "/default.nix"
183             else "<unknown location>";
184         in "Function called without required argument \"${arg}\" at "
185         + "${loc'}${prettySuggestions (getSuggestions arg)}";
187       # Only show the error for the first missing argument
188       error = errorForArg (lib.head missingArgs);
190     in if missingArgs == [] then makeOverridable f allArgs else abort error;
193   /* Like callPackage, but for a function that returns an attribute
194      set of derivations. The override function is added to the
195      individual attributes.
197      Type:
198        callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet
199   */
200   callPackagesWith = autoArgs: fn: args:
201     let
202       f = if lib.isFunction fn then fn else import fn;
203       auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
204       origArgs = auto // args;
205       pkgs = f origArgs;
206       mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
207     in
208       if lib.isDerivation pkgs then throw
209         ("function `callPackages` was called on a *single* derivation "
210           + ''"${pkgs.name or "<unknown-name>"}";''
211           + " did you mean to use `callPackage` instead?")
212       else lib.mapAttrs mkAttrOverridable pkgs;
215   /* Add attributes to each output of a derivation without changing
216      the derivation itself and check a given condition when evaluating.
218      Type:
219        extendDerivation :: Bool -> Any -> Derivation -> Derivation
220   */
221   extendDerivation = condition: passthru: drv:
222     let
223       outputs = drv.outputs or [ "out" ];
225       commonAttrs = drv // (builtins.listToAttrs outputsList) //
226         ({ all = map (x: x.value) outputsList; }) // passthru;
228       outputToAttrListElement = outputName:
229         { name = outputName;
230           value = commonAttrs // {
231             inherit (drv.${outputName}) type outputName;
232             outputSpecified = true;
233             drvPath = assert condition; drv.${outputName}.drvPath;
234             outPath = assert condition; drv.${outputName}.outPath;
235           } //
236             # TODO: give the derivation control over the outputs.
237             #       `overrideAttrs` may not be the only attribute that needs
238             #       updating when switching outputs.
239             lib.optionalAttrs (passthru?overrideAttrs) {
240               # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
241               overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
242             };
243         };
245       outputsList = map outputToAttrListElement outputs;
246     in commonAttrs // {
247       drvPath = assert condition; drv.drvPath;
248       outPath = assert condition; drv.outPath;
249     };
251   /* Strip a derivation of all non-essential attributes, returning
252      only those needed by hydra-eval-jobs. Also strictly evaluate the
253      result to ensure that there are no thunks kept alive to prevent
254      garbage collection.
256      Type:
257        hydraJob :: (Derivation | Null) -> (Derivation | Null)
258   */
259   hydraJob = drv:
260     let
261       outputs = drv.outputs or ["out"];
263       commonAttrs =
264         { inherit (drv) name system meta; inherit outputs; }
265         // lib.optionalAttrs (drv._hydraAggregate or false) {
266           _hydraAggregate = true;
267           constituents = map hydraJob (lib.flatten drv.constituents);
268         }
269         // (lib.listToAttrs outputsList);
271       makeOutput = outputName:
272         let output = drv.${outputName}; in
273         { name = outputName;
274           value = commonAttrs // {
275             outPath = output.outPath;
276             drvPath = output.drvPath;
277             type = "derivation";
278             inherit outputName;
279           };
280         };
282       outputsList = map makeOutput outputs;
284       drv' = (lib.head outputsList).value;
285     in if drv == null then null else
286       lib.deepSeq drv' drv';
288   /* Make a set of packages with a common scope. All packages called
289      with the provided `callPackage` will be evaluated with the same
290      arguments. Any package in the set may depend on any other. The
291      `overrideScope'` function allows subsequent modification of the package
292      set in a consistent way, i.e. all packages in the set will be
293      called with the overridden packages. The package sets may be
294      hierarchical: the packages in the set are called with the scope
295      provided by `newScope` and the set provides a `newScope` attribute
296      which can form the parent scope for later package sets.
298      Type:
299        makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> AttrSet
300   */
301   makeScope = newScope: f:
302     let self = f self // {
303           newScope = scope: newScope (self // scope);
304           callPackage = self.newScope {};
305           overrideScope = g: makeScope newScope (lib.fixedPoints.extends g f);
306           # Remove after 24.11 is released.
307           overrideScope' = g: lib.warnIf (lib.isInOldestRelease 2311)
308             "`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`."
309             (makeScope newScope (lib.fixedPoints.extends g f));
310           packages = f;
311         };
312     in self;
314   /* backward compatibility with old uncurried form; deprecated */
315   makeScopeWithSplicing =
316     splicePackages: newScope: otherSplices: keep: extra: f:
317     makeScopeWithSplicing'
318     { inherit splicePackages newScope; }
319     { inherit otherSplices keep extra f; };
321   /* Like makeScope, but aims to support cross compilation. It's still ugly, but
322      hopefully it helps a little bit.
324      Type:
325        makeScopeWithSplicing' ::
326          { splicePackages :: Splice -> AttrSet
327          , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
328          }
329          -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet }
330          -> AttrSet
332        Splice ::
333          { pkgsBuildBuild :: AttrSet
334          , pkgsBuildHost :: AttrSet
335          , pkgsBuildTarget :: AttrSet
336          , pkgsHostHost :: AttrSet
337          , pkgsHostTarget :: AttrSet
338          , pkgsTargetTarget :: AttrSet
339          }
340   */
341   makeScopeWithSplicing' =
342     { splicePackages
343     , newScope
344     }:
345     { otherSplices
346     # Attrs from `self` which won't be spliced.
347     # Avoid using keep, it's only used for a python hook workaround, added in PR #104201.
348     # ex: `keep = (self: { inherit (self) aAttr; })`
349     , keep ? (_self: {})
350     # Additional attrs to add to the sets `callPackage`.
351     # When the package is from a subset (but not a subset within a package IS #211340)
352     # within `spliced0` it will be spliced.
353     # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`.
354     # 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
355     # ex:
356     # ```
357     # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation
358     #   «derivation ...CoreFoundation-11.0.0.drv»
359     # nix-repl> darwin.CoreFoundation
360     #   error: attribute 'CoreFoundation' missing
361     # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { }
362     #   «derivation ...CoreFoundation-11.0.0.drv»
363     # ```
364     , extra ? (_spliced0: {})
365     , f
366     }:
367     let
368       spliced0 = splicePackages {
369         pkgsBuildBuild = otherSplices.selfBuildBuild;
370         pkgsBuildHost = otherSplices.selfBuildHost;
371         pkgsBuildTarget = otherSplices.selfBuildTarget;
372         pkgsHostHost = otherSplices.selfHostHost;
373         pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`;
374         pkgsTargetTarget = otherSplices.selfTargetTarget;
375       };
376       spliced = extra spliced0 // spliced0 // keep self;
377       self = f self // {
378         newScope = scope: newScope (spliced // scope);
379         callPackage = newScope spliced; # == self.newScope {};
380         # N.B. the other stages of the package set spliced in are *not*
381         # overridden.
382         overrideScope = g: (makeScopeWithSplicing'
383           { inherit splicePackages newScope; }
384           { inherit otherSplices keep extra;
385             f = lib.fixedPoints.extends g f;
386           });
387         packages = f;
388       };
389     in self;