nixos/tests/forgejo: fix after git v2.47 bump
[NixPkgs.git] / lib / meta.nix
blob798e7e74918cc058662bf5f86e422ad8549a9293
1 /**
2   Some functions for manipulating meta attributes, as well as the
3   name attribute.
4 */
6 { lib }:
8 let
9   inherit (lib) matchAttrs any all isDerivation getBin assertMsg;
10   inherit (lib.attrsets) mapAttrs' filterAttrs;
11   inherit (builtins) isString match typeOf;
14 rec {
17   /**
18     Add to or override the meta attributes of the given
19     derivation.
21     # Inputs
23     `newAttrs`
25     : 1\. Function argument
27     `drv`
29     : 2\. Function argument
32     # Examples
33     :::{.example}
34     ## `lib.meta.addMetaAttrs` usage example
36     ```nix
37     addMetaAttrs {description = "Bla blah";} somePkg
38     ```
40     :::
41   */
42   addMetaAttrs = newAttrs: drv:
43     drv // { meta = (drv.meta or {}) // newAttrs; };
46   /**
47     Disable Hydra builds of given derivation.
49     # Inputs
51     `drv`
53     : 1\. Function argument
54   */
55   dontDistribute = drv: addMetaAttrs { hydraPlatforms = []; } drv;
58   /**
59     Change the [symbolic name of a derivation](https://nixos.org/manual/nix/stable/language/derivations.html#attr-name).
61     :::{.warning}
62     Dependent derivations will be rebuilt when the symbolic name is changed.
63     :::
65     # Inputs
67     `name`
69     : 1\. Function argument
71     `drv`
73     : 2\. Function argument
74   */
75   setName = name: drv: drv // {inherit name;};
78   /**
79     Like `setName`, but takes the previous name as an argument.
81     # Inputs
83     `updater`
85     : 1\. Function argument
87     `drv`
89     : 2\. Function argument
92     # Examples
93     :::{.example}
94     ## `lib.meta.updateName` usage example
96     ```nix
97     updateName (oldName: oldName + "-experimental") somePkg
98     ```
100     :::
101   */
102   updateName = updater: drv: drv // {name = updater (drv.name);};
105   /**
106     Append a suffix to the name of a package (before the version
107     part).
109     # Inputs
111     `suffix`
113     : 1\. Function argument
114   */
115   appendToName = suffix: updateName (name:
116     let x = builtins.parseDrvName name; in "${x.name}-${suffix}-${x.version}");
119   /**
120     Apply a function to each derivation and only to derivations in an attrset.
123     # Inputs
125     `f`
127     : 1\. Function argument
129     `set`
131     : 2\. Function argument
132   */
133   mapDerivationAttrset = f: set: lib.mapAttrs (name: pkg: if lib.isDerivation pkg then (f pkg) else pkg) set;
135   /**
136     The default priority of packages in Nix. See `defaultPriority` in [`src/nix/profile.cc`](https://github.com/NixOS/nix/blob/master/src/nix/profile.cc#L47).
137    */
138   defaultPriority = 5;
140   /**
141     Set the nix-env priority of the package. Note that higher values are lower priority, and vice versa.
143     # Inputs
145     `priority`
146     : 1\. The priority to set.
148     `drv`
149     : 2\. Function argument
150   */
151   setPrio = priority: addMetaAttrs { inherit priority; };
153   /**
154     Decrease the nix-env priority of the package, i.e., other
155     versions/variants of the package will be preferred.
157     # Inputs
159     `drv`
161     : 1\. Function argument
163   */
164   lowPrio = setPrio 10;
166   /**
167     Apply lowPrio to an attrset with derivations.
169     # Inputs
171     `set`
173     : 1\. Function argument
174   */
175   lowPrioSet = set: mapDerivationAttrset lowPrio set;
178   /**
179     Increase the nix-env priority of the package, i.e., this
180     version/variant of the package will be preferred.
182     # Inputs
184     `drv`
186     : 1\. Function argument
187   */
188   hiPrio = setPrio (-10);
190   /**
191     Apply hiPrio to an attrset with derivations.
193     # Inputs
195     `set`
197     : 1\. Function argument
198   */
199   hiPrioSet = set: mapDerivationAttrset hiPrio set;
202   /**
203     Check to see if a platform is matched by the given `meta.platforms`
204     element.
206     A `meta.platform` pattern is either
208     1. (legacy) a system string.
210     2. (modern) a pattern for the entire platform structure (see `lib.systems.inspect.platformPatterns`).
212     3. (modern) a pattern for the platform `parsed` field (see `lib.systems.inspect.patterns`).
214     We can inject these into a pattern for the whole of a structured platform,
215     and then match that.
218     # Inputs
220     `platform`
222     : 1\. Function argument
224     `elem`
226     : 2\. Function argument
229     # Examples
230     :::{.example}
231     ## `lib.meta.platformMatch` usage example
233     ```nix
234     lib.meta.platformMatch { system = "aarch64-darwin"; } "aarch64-darwin"
235     => true
236     ```
238     :::
239   */
240   platformMatch = platform: elem: (
241     # Check with simple string comparison if elem was a string.
242     #
243     # The majority of comparisons done with this function will be against meta.platforms
244     # which contains a simple platform string.
245     #
246     # Avoiding an attrset allocation results in significant  performance gains (~2-30) across the board in OfBorg
247     # because this is a hot path for nixpkgs.
248     if isString elem then platform ? system && elem == platform.system
249     else matchAttrs (
250       # Normalize platform attrset.
251       if elem ? parsed then elem
252       else { parsed = elem; }
253     ) platform
254   );
256   /**
257     Check if a package is available on a given platform.
259     A package is available on a platform if both
261     1. One of `meta.platforms` pattern matches the given
262         platform, or `meta.platforms` is not present.
264     2. None of `meta.badPlatforms` pattern matches the given platform.
267     # Inputs
269     `platform`
271     : 1\. Function argument
273     `pkg`
275     : 2\. Function argument
278     # Examples
279     :::{.example}
280     ## `lib.meta.availableOn` usage example
282     ```nix
283     lib.meta.availableOn { system = "aarch64-darwin"; } pkg.zsh
284     => true
285     ```
287     :::
288   */
289   availableOn = platform: pkg:
290     ((!pkg?meta.platforms) || any (platformMatch platform) pkg.meta.platforms) &&
291     all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or []);
293   /**
294     Mapping of SPDX ID to the attributes in lib.licenses.
296     For SPDX IDs, see https://spdx.org/licenses.
297     Note that some SPDX licenses might be missing.
299     # Examples
300     :::{.example}
301     ## `lib.meta.licensesSpdx` usage example
303     ```nix
304     lib.licensesSpdx.MIT == lib.licenses.mit
305     => true
306     lib.licensesSpdx."MY LICENSE"
307     => error: attribute 'MY LICENSE' missing
308     ```
310     :::
311   */
312   licensesSpdx =
313     mapAttrs'
314     (_key: license: {
315       name = license.spdxId;
316       value = license;
317     })
318     (filterAttrs (_key: license: license ? spdxId) lib.licenses);
320   /**
321     Get the corresponding attribute in lib.licenses from the SPDX ID
322     or warn and fallback to `{ shortName = <license string>; }`.
324     For SPDX IDs, see https://spdx.org/licenses.
325     Note that some SPDX licenses might be missing.
327     # Type
329     ```
330     getLicenseFromSpdxId :: str -> AttrSet
331     ```
333     # Examples
334     :::{.example}
335     ## `lib.meta.getLicenseFromSpdxId` usage example
337     ```nix
338     lib.getLicenseFromSpdxId "MIT" == lib.licenses.mit
339     => true
340     lib.getLicenseFromSpdxId "mIt" == lib.licenses.mit
341     => true
342     lib.getLicenseFromSpdxId "MY LICENSE"
343     => trace: warning: getLicenseFromSpdxId: No license matches the given SPDX ID: MY LICENSE
344     => { shortName = "MY LICENSE"; }
345     ```
347     :::
348   */
349   getLicenseFromSpdxId =
350     licstr:
351       getLicenseFromSpdxIdOr licstr (
352         lib.warn "getLicenseFromSpdxId: No license matches the given SPDX ID: ${licstr}"
353         { shortName = licstr; }
354       );
356   /**
357     Get the corresponding attribute in lib.licenses from the SPDX ID
358     or fallback to the given default value.
360     For SPDX IDs, see https://spdx.org/licenses.
361     Note that some SPDX licenses might be missing.
363     # Inputs
365     `licstr`
366     : 1\. SPDX ID string to find a matching license
368     `default`
369     : 2\. Fallback value when a match is not found
371     # Type
373     ```
374     getLicenseFromSpdxIdOr :: str -> Any -> Any
375     ```
377     # Examples
378     :::{.example}
379     ## `lib.meta.getLicenseFromSpdxIdOr` usage example
381     ```nix
382     lib.getLicenseFromSpdxIdOr "MIT" null == lib.licenses.mit
383     => true
384     lib.getLicenseFromSpdxId "mIt" null == lib.licenses.mit
385     => true
386     lib.getLicenseFromSpdxIdOr "MY LICENSE" lib.licenses.free == lib.licenses.free
387     => true
388     lib.getLicenseFromSpdxIdOr "MY LICENSE" null
389     => null
390     lib.getLicenseFromSpdxIdOr "MY LICENSE" (builtins.throw "No SPDX ID matches MY LICENSE")
391     => error: No SPDX ID matches MY LICENSE
392     ```
393     :::
394   */
395   getLicenseFromSpdxIdOr =
396     let
397       lowercaseLicenses = lib.mapAttrs' (name: value: {
398         name = lib.toLower name;
399         inherit value;
400       }) licensesSpdx;
401     in licstr: default:
402       lowercaseLicenses.${ lib.toLower licstr } or default;
404   /**
405     Get the path to the main program of a package based on meta.mainProgram
408     # Inputs
410     `x`
412     : 1\. Function argument
414     # Type
416     ```
417     getExe :: package -> string
418     ```
420     # Examples
421     :::{.example}
422     ## `lib.meta.getExe` usage example
424     ```nix
425     getExe pkgs.hello
426     => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
427     getExe pkgs.mustache-go
428     => "/nix/store/am9ml4f4ywvivxnkiaqwr0hyxka1xjsf-mustache-go-1.3.0/bin/mustache"
429     ```
431     :::
432   */
433   getExe = x: getExe' x (x.meta.mainProgram or (
434     # This could be turned into an error when 23.05 is at end of life
435     lib.warn "getExe: Package ${lib.strings.escapeNixIdentifier x.meta.name or x.pname or x.name} does not have the meta.mainProgram attribute. We'll assume that the main program has the same name for now, but this behavior is deprecated, because it leads to surprising errors when the assumption does not hold. If the package has a main program, please set `meta.mainProgram` in its definition to make this warning go away. Otherwise, if the package does not have a main program, or if you don't control its definition, use getExe' to specify the name to the program, such as lib.getExe' foo \"bar\"."
436     lib.getName
437     x
438   ));
440   /**
441     Get the path of a program of a derivation.
444     # Inputs
446     `x`
448     : 1\. Function argument
450     `y`
452     : 2\. Function argument
454     # Type
456     ```
457     getExe' :: derivation -> string -> string
458     ```
460     # Examples
461     :::{.example}
462     ## `lib.meta.getExe'` usage example
464     ```nix
465     getExe' pkgs.hello "hello"
466     => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
467     getExe' pkgs.imagemagick "convert"
468     => "/nix/store/5rs48jamq7k6sal98ymj9l4k2bnwq515-imagemagick-7.1.1-15/bin/convert"
469     ```
471     :::
472   */
473   getExe' = x: y:
474     assert assertMsg (isDerivation x)
475       "lib.meta.getExe': The first argument is of type ${typeOf x}, but it should be a derivation instead.";
476     assert assertMsg (isString y)
477       "lib.meta.getExe': The second argument is of type ${typeOf y}, but it should be a string instead.";
478     assert assertMsg (match ".*\/.*" y == null)
479       "lib.meta.getExe': The second argument \"${y}\" is a nested path with a \"/\" character, but it should just be the name of the executable instead.";
480     "${getBin x}/bin/${y}";