typioca: 2.7.0 -> 2.8.0
[NixPkgs.git] / lib / customisation.nix
blob08fc5db0614de1ed49adadc574e68a9dbdb303f5
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:
80     let
81       # Creates a functor with the same arguments as f
82       mirrorArgs = lib.mirrorFunctionArgs f;
83     in
84     mirrorArgs (origArgs:
85     let
86       result = f origArgs;
88       # Changes the original arguments with (potentially a function that returns) a set of new attributes
89       overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
91       # Re-call the function but with different arguments
92       overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs));
93       # Change the result of the function call by applying g to it
94       overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
95     in
96       if builtins.isAttrs result then
97         result // {
98           override = overrideArgs;
99           overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
100           ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
101             overrideResult (x: x.overrideAttrs fdrv);
102         }
103       else if lib.isFunction result then
104         # Transform the result into a functor while propagating its arguments
105         lib.setFunctionArgs result (lib.functionArgs result) // {
106           override = overrideArgs;
107         }
108       else result);
111   /* Call the package function in the file `fn` with the required
112     arguments automatically.  The function is called with the
113     arguments `args`, but any missing arguments are obtained from
114     `autoArgs`.  This function is intended to be partially
115     parameterised, e.g.,
117       ```nix
118       callPackage = callPackageWith pkgs;
119       pkgs = {
120         libfoo = callPackage ./foo.nix { };
121         libbar = callPackage ./bar.nix { };
122       };
123       ```
125     If the `libbar` function expects an argument named `libfoo`, it is
126     automatically passed as an argument.  Overrides or missing
127     arguments can be supplied in `args`, e.g.
129       ```nix
130       libbar = callPackage ./bar.nix {
131         libfoo = null;
132         enableX11 = true;
133       };
134       ```
136     <!-- TODO: Apply "Example:" tag to the examples above -->
138     Type:
139       callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
140   */
141   callPackageWith = autoArgs: fn: args:
142     let
143       f = if lib.isFunction fn then fn else import fn;
144       fargs = lib.functionArgs f;
146       # All arguments that will be passed to the function
147       # This includes automatic ones and ones passed explicitly
148       allArgs = builtins.intersectAttrs fargs autoArgs // args;
150       # a list of argument names that the function requires, but
151       # wouldn't be passed to it
152       missingArgs = lib.attrNames
153         # Filter out arguments that have a default value
154         (lib.filterAttrs (name: value: ! value)
155         # Filter out arguments that would be passed
156         (removeAttrs fargs (lib.attrNames allArgs)));
158       # Get a list of suggested argument names for a given missing one
159       getSuggestions = arg: lib.pipe (autoArgs // args) [
160         lib.attrNames
161         # Only use ones that are at most 2 edits away. While mork would work,
162         # levenshteinAtMost is only fast for 2 or less.
163         (lib.filter (lib.strings.levenshteinAtMost 2 arg))
164         # Put strings with shorter distance first
165         (lib.sort (x: y: lib.strings.levenshtein x arg < lib.strings.levenshtein y arg))
166         # Only take the first couple results
167         (lib.take 3)
168         # Quote all entries
169         (map (x: "\"" + x + "\""))
170       ];
172       prettySuggestions = suggestions:
173         if suggestions == [] then ""
174         else if lib.length suggestions == 1 then ", did you mean ${lib.elemAt suggestions 0}?"
175         else ", did you mean ${lib.concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
177       errorForArg = arg:
178         let
179           loc = builtins.unsafeGetAttrPos arg fargs;
180           # loc' can be removed once lib/minver.nix is >2.3.4, since that includes
181           # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null
182           loc' = if loc != null then loc.file + ":" + toString loc.line
183             else if ! lib.isFunction fn then
184               toString fn + lib.optionalString (lib.sources.pathIsDirectory fn) "/default.nix"
185             else "<unknown location>";
186         in "Function called without required argument \"${arg}\" at "
187         + "${loc'}${prettySuggestions (getSuggestions arg)}";
189       # Only show the error for the first missing argument
190       error = errorForArg (lib.head missingArgs);
192     in if missingArgs == [] then makeOverridable f allArgs else abort error;
195   /* Like callPackage, but for a function that returns an attribute
196      set of derivations. The override function is added to the
197      individual attributes.
199      Type:
200        callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet
201   */
202   callPackagesWith = autoArgs: fn: args:
203     let
204       f = if lib.isFunction fn then fn else import fn;
205       auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
206       origArgs = auto // args;
207       pkgs = f origArgs;
208       mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
209     in
210       if lib.isDerivation pkgs then throw
211         ("function `callPackages` was called on a *single* derivation "
212           + ''"${pkgs.name or "<unknown-name>"}";''
213           + " did you mean to use `callPackage` instead?")
214       else lib.mapAttrs mkAttrOverridable pkgs;
217   /* Add attributes to each output of a derivation without changing
218      the derivation itself and check a given condition when evaluating.
220      Type:
221        extendDerivation :: Bool -> Any -> Derivation -> Derivation
222   */
223   extendDerivation = condition: passthru: drv:
224     let
225       outputs = drv.outputs or [ "out" ];
227       commonAttrs = drv // (builtins.listToAttrs outputsList) //
228         ({ all = map (x: x.value) outputsList; }) // passthru;
230       outputToAttrListElement = outputName:
231         { name = outputName;
232           value = commonAttrs // {
233             inherit (drv.${outputName}) type outputName;
234             outputSpecified = true;
235             drvPath = assert condition; drv.${outputName}.drvPath;
236             outPath = assert condition; drv.${outputName}.outPath;
237           } //
238             # TODO: give the derivation control over the outputs.
239             #       `overrideAttrs` may not be the only attribute that needs
240             #       updating when switching outputs.
241             lib.optionalAttrs (passthru?overrideAttrs) {
242               # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
243               overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
244             };
245         };
247       outputsList = map outputToAttrListElement outputs;
248     in commonAttrs // {
249       drvPath = assert condition; drv.drvPath;
250       outPath = assert condition; drv.outPath;
251     };
253   /* Strip a derivation of all non-essential attributes, returning
254      only those needed by hydra-eval-jobs. Also strictly evaluate the
255      result to ensure that there are no thunks kept alive to prevent
256      garbage collection.
258      Type:
259        hydraJob :: (Derivation | Null) -> (Derivation | Null)
260   */
261   hydraJob = drv:
262     let
263       outputs = drv.outputs or ["out"];
265       commonAttrs =
266         { inherit (drv) name system meta; inherit outputs; }
267         // lib.optionalAttrs (drv._hydraAggregate or false) {
268           _hydraAggregate = true;
269           constituents = map hydraJob (lib.flatten drv.constituents);
270         }
271         // (lib.listToAttrs outputsList);
273       makeOutput = outputName:
274         let output = drv.${outputName}; in
275         { name = outputName;
276           value = commonAttrs // {
277             outPath = output.outPath;
278             drvPath = output.drvPath;
279             type = "derivation";
280             inherit outputName;
281           };
282         };
284       outputsList = map makeOutput outputs;
286       drv' = (lib.head outputsList).value;
287     in if drv == null then null else
288       lib.deepSeq drv' drv';
290   /* Make a set of packages with a common scope. All packages called
291      with the provided `callPackage` will be evaluated with the same
292      arguments. Any package in the set may depend on any other. The
293      `overrideScope'` function allows subsequent modification of the package
294      set in a consistent way, i.e. all packages in the set will be
295      called with the overridden packages. The package sets may be
296      hierarchical: the packages in the set are called with the scope
297      provided by `newScope` and the set provides a `newScope` attribute
298      which can form the parent scope for later package sets.
300      Type:
301        makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> AttrSet
302   */
303   makeScope = newScope: f:
304     let self = f self // {
305           newScope = scope: newScope (self // scope);
306           callPackage = self.newScope {};
307           overrideScope = g: makeScope newScope (lib.fixedPoints.extends g f);
308           # Remove after 24.11 is released.
309           overrideScope' = g: lib.warnIf (lib.isInOldestRelease 2311)
310             "`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`."
311             (makeScope newScope (lib.fixedPoints.extends g f));
312           packages = f;
313         };
314     in self;
316   /* backward compatibility with old uncurried form; deprecated */
317   makeScopeWithSplicing =
318     splicePackages: newScope: otherSplices: keep: extra: f:
319     makeScopeWithSplicing'
320     { inherit splicePackages newScope; }
321     { inherit otherSplices keep extra f; };
323   /* Like makeScope, but aims to support cross compilation. It's still ugly, but
324      hopefully it helps a little bit.
326      Type:
327        makeScopeWithSplicing' ::
328          { splicePackages :: Splice -> AttrSet
329          , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
330          }
331          -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet }
332          -> AttrSet
334        Splice ::
335          { pkgsBuildBuild :: AttrSet
336          , pkgsBuildHost :: AttrSet
337          , pkgsBuildTarget :: AttrSet
338          , pkgsHostHost :: AttrSet
339          , pkgsHostTarget :: AttrSet
340          , pkgsTargetTarget :: AttrSet
341          }
342   */
343   makeScopeWithSplicing' =
344     { splicePackages
345     , newScope
346     }:
347     { otherSplices
348     # Attrs from `self` which won't be spliced.
349     # Avoid using keep, it's only used for a python hook workaround, added in PR #104201.
350     # ex: `keep = (self: { inherit (self) aAttr; })`
351     , keep ? (_self: {})
352     # Additional attrs to add to the sets `callPackage`.
353     # When the package is from a subset (but not a subset within a package IS #211340)
354     # within `spliced0` it will be spliced.
355     # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`.
356     # 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
357     # ex:
358     # ```
359     # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation
360     #   «derivation ...CoreFoundation-11.0.0.drv»
361     # nix-repl> darwin.CoreFoundation
362     #   error: attribute 'CoreFoundation' missing
363     # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { }
364     #   «derivation ...CoreFoundation-11.0.0.drv»
365     # ```
366     , extra ? (_spliced0: {})
367     , f
368     }:
369     let
370       spliced0 = splicePackages {
371         pkgsBuildBuild = otherSplices.selfBuildBuild;
372         pkgsBuildHost = otherSplices.selfBuildHost;
373         pkgsBuildTarget = otherSplices.selfBuildTarget;
374         pkgsHostHost = otherSplices.selfHostHost;
375         pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`;
376         pkgsTargetTarget = otherSplices.selfTargetTarget;
377       };
378       spliced = extra spliced0 // spliced0 // keep self;
379       self = f self // {
380         newScope = scope: newScope (spliced // scope);
381         callPackage = newScope spliced; # == self.newScope {};
382         # N.B. the other stages of the package set spliced in are *not*
383         # overridden.
384         overrideScope = g: (makeScopeWithSplicing'
385           { inherit splicePackages newScope; }
386           { inherit otherSplices keep extra;
387             f = lib.fixedPoints.extends g f;
388           });
389         packages = f;
390       };
391     in self;