1/**
2 Some functions for manipulating meta attributes, as well as the
3 name attribute.
4*/
5
6{ lib }:
7
8let
9 inherit (lib)
10 matchAttrs
11 any
12 all
13 isDerivation
14 getBin
15 assertMsg
16 ;
17 inherit (lib.attrsets) mapAttrs' filterAttrs;
18 inherit (builtins) isString match typeOf;
19
20in
21rec {
22
23 /**
24 Add to or override the meta attributes of the given
25 derivation.
26
27 # Inputs
28
29 `newAttrs`
30
31 : 1\. Function argument
32
33 `drv`
34
35 : 2\. Function argument
36
37 # Examples
38 :::{.example}
39 ## `lib.meta.addMetaAttrs` usage example
40
41 ```nix
42 addMetaAttrs {description = "Bla blah";} somePkg
43 ```
44
45 :::
46 */
47 addMetaAttrs = newAttrs: drv: drv // { meta = (drv.meta or { }) // newAttrs; };
48
49 /**
50 Disable Hydra builds of given derivation.
51
52 # Inputs
53
54 `drv`
55
56 : 1\. Function argument
57 */
58 dontDistribute = drv: addMetaAttrs { hydraPlatforms = [ ]; } drv;
59
60 /**
61 Change the [symbolic name of a derivation](https://nixos.org/manual/nix/stable/language/derivations.html#attr-name).
62
63 :::{.warning}
64 Dependent derivations will be rebuilt when the symbolic name is changed.
65 :::
66
67 # Inputs
68
69 `name`
70
71 : 1\. Function argument
72
73 `drv`
74
75 : 2\. Function argument
76 */
77 setName = name: drv: drv // { inherit name; };
78
79 /**
80 Like `setName`, but takes the previous name as an argument.
81
82 # Inputs
83
84 `updater`
85
86 : 1\. Function argument
87
88 `drv`
89
90 : 2\. Function argument
91
92 # Examples
93 :::{.example}
94 ## `lib.meta.updateName` usage example
95
96 ```nix
97 updateName (oldName: oldName + "-experimental") somePkg
98 ```
99
100 :::
101 */
102 updateName = updater: drv: drv // { name = updater (drv.name); };
103
104 /**
105 Append a suffix to the name of a package (before the version
106 part).
107
108 # Inputs
109
110 `suffix`
111
112 : 1\. Function argument
113 */
114 appendToName =
115 suffix:
116 updateName (
117 name:
118 let
119 x = builtins.parseDrvName name;
120 in
121 "${x.name}-${suffix}-${x.version}"
122 );
123
124 /**
125 Apply a function to each derivation and only to derivations in an attrset.
126
127 # Inputs
128
129 `f`
130
131 : 1\. Function argument
132
133 `set`
134
135 : 2\. Function argument
136 */
137 mapDerivationAttrset =
138 f: set: lib.mapAttrs (name: pkg: if lib.isDerivation pkg then (f pkg) else pkg) set;
139
140 /**
141 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).
142 */
143 defaultPriority = 5;
144
145 /**
146 Set the nix-env priority of the package. Note that higher values are lower priority, and vice versa.
147
148 # Inputs
149
150 `priority`
151 : 1\. The priority to set.
152
153 `drv`
154 : 2\. Function argument
155 */
156 setPrio = priority: addMetaAttrs { inherit priority; };
157
158 /**
159 Decrease the nix-env priority of the package, i.e., other
160 versions/variants of the package will be preferred.
161
162 # Inputs
163
164 `drv`
165
166 : 1\. Function argument
167 */
168 lowPrio = setPrio 10;
169
170 /**
171 Apply lowPrio to an attrset with derivations.
172
173 # Inputs
174
175 `set`
176
177 : 1\. Function argument
178 */
179 lowPrioSet = set: mapDerivationAttrset lowPrio set;
180
181 /**
182 Increase the nix-env priority of the package, i.e., this
183 version/variant of the package will be preferred.
184
185 # Inputs
186
187 `drv`
188
189 : 1\. Function argument
190 */
191 hiPrio = setPrio (-10);
192
193 /**
194 Apply hiPrio to an attrset with derivations.
195
196 # Inputs
197
198 `set`
199
200 : 1\. Function argument
201 */
202 hiPrioSet = set: mapDerivationAttrset hiPrio set;
203
204 /**
205 Check to see if a platform is matched by the given `meta.platforms`
206 element.
207
208 A `meta.platform` pattern is either
209
210 1. (legacy) a system string.
211
212 2. (modern) a pattern for the entire platform structure (see `lib.systems.inspect.platformPatterns`).
213
214 3. (modern) a pattern for the platform `parsed` field (see `lib.systems.inspect.patterns`).
215
216 We can inject these into a pattern for the whole of a structured platform,
217 and then match that.
218
219 # Inputs
220
221 `platform`
222
223 : 1\. Function argument
224
225 `elem`
226
227 : 2\. Function argument
228
229 # Examples
230 :::{.example}
231 ## `lib.meta.platformMatch` usage example
232
233 ```nix
234 lib.meta.platformMatch { system = "aarch64-darwin"; } "aarch64-darwin"
235 => true
236 ```
237
238 :::
239 */
240 platformMatch =
241 platform: elem:
242 (
243 # Check with simple string comparison if elem was a string.
244 #
245 # The majority of comparisons done with this function will be against meta.platforms
246 # which contains a simple platform string.
247 #
248 # Avoiding an attrset allocation results in significant performance gains (~2-30) across the board in OfBorg
249 # because this is a hot path for nixpkgs.
250 if isString elem then
251 platform ? system && elem == platform.system
252 else
253 matchAttrs (
254 # Normalize platform attrset.
255 if elem ? parsed then elem else { parsed = elem; }
256 ) platform
257 );
258
259 /**
260 Check if a package is available on a given platform.
261
262 A package is available on a platform if both
263
264 1. One of `meta.platforms` pattern matches the given
265 platform, or `meta.platforms` is not present.
266
267 2. None of `meta.badPlatforms` pattern matches the given platform.
268
269 # Inputs
270
271 `platform`
272
273 : 1\. Function argument
274
275 `pkg`
276
277 : 2\. Function argument
278
279 # Examples
280 :::{.example}
281 ## `lib.meta.availableOn` usage example
282
283 ```nix
284 lib.meta.availableOn { system = "aarch64-darwin"; } pkg.zsh
285 => true
286 ```
287
288 :::
289 */
290 availableOn =
291 platform: pkg:
292 ((!pkg ? meta.platforms) || any (platformMatch platform) pkg.meta.platforms)
293 && all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or [ ]);
294
295 /**
296 Mapping of SPDX ID to the attributes in lib.licenses.
297
298 For SPDX IDs, see https://spdx.org/licenses.
299 Note that some SPDX licenses might be missing.
300
301 # Examples
302 :::{.example}
303 ## `lib.meta.licensesSpdx` usage example
304
305 ```nix
306 lib.licensesSpdx.MIT == lib.licenses.mit
307 => true
308 lib.licensesSpdx."MY LICENSE"
309 => error: attribute 'MY LICENSE' missing
310 ```
311
312 :::
313 */
314 licensesSpdx = mapAttrs' (_key: license: {
315 name = license.spdxId;
316 value = license;
317 }) (filterAttrs (_key: license: license ? spdxId) lib.licenses);
318
319 /**
320 Get the corresponding attribute in lib.licenses from the SPDX ID
321 or warn and fallback to `{ shortName = <license string>; }`.
322
323 For SPDX IDs, see https://spdx.org/licenses.
324 Note that some SPDX licenses might be missing.
325
326 # Type
327
328 ```
329 getLicenseFromSpdxId :: str -> AttrSet
330 ```
331
332 # Examples
333 :::{.example}
334 ## `lib.meta.getLicenseFromSpdxId` usage example
335
336 ```nix
337 lib.getLicenseFromSpdxId "MIT" == lib.licenses.mit
338 => true
339 lib.getLicenseFromSpdxId "mIt" == lib.licenses.mit
340 => true
341 lib.getLicenseFromSpdxId "MY LICENSE"
342 => trace: warning: getLicenseFromSpdxId: No license matches the given SPDX ID: MY LICENSE
343 => { shortName = "MY LICENSE"; }
344 ```
345
346 :::
347 */
348 getLicenseFromSpdxId =
349 licstr:
350 getLicenseFromSpdxIdOr licstr (
351 lib.warn "getLicenseFromSpdxId: No license matches the given SPDX ID: ${licstr}" {
352 shortName = licstr;
353 }
354 );
355
356 /**
357 Get the corresponding attribute in lib.licenses from the SPDX ID
358 or fallback to the given default value.
359
360 For SPDX IDs, see https://spdx.org/licenses.
361 Note that some SPDX licenses might be missing.
362
363 # Inputs
364
365 `licstr`
366 : 1\. SPDX ID string to find a matching license
367
368 `default`
369 : 2\. Fallback value when a match is not found
370
371 # Type
372
373 ```
374 getLicenseFromSpdxIdOr :: str -> Any -> Any
375 ```
376
377 # Examples
378 :::{.example}
379 ## `lib.meta.getLicenseFromSpdxIdOr` usage example
380
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
402 licstr: default: lowercaseLicenses.${lib.toLower licstr} or default;
403
404 /**
405 Get the path to the main program of a package based on meta.mainProgram
406
407 # Inputs
408
409 `x`
410
411 : 1\. Function argument
412
413 # Type
414
415 ```
416 getExe :: package -> string
417 ```
418
419 # Examples
420 :::{.example}
421 ## `lib.meta.getExe` usage example
422
423 ```nix
424 getExe pkgs.hello
425 => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
426 getExe pkgs.mustache-go
427 => "/nix/store/am9ml4f4ywvivxnkiaqwr0hyxka1xjsf-mustache-go-1.3.0/bin/mustache"
428 ```
429
430 :::
431 */
432 getExe =
433 x:
434 getExe' x (
435 x.meta.mainProgram or (
436 # This could be turned into an error when 23.05 is at end of life
437 lib.warn
438 "getExe: Package ${
439 lib.strings.escapeNixIdentifier x.meta.name or x.pname or x.name
440 } 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\"."
441 lib.getName
442 x
443 )
444 );
445
446 /**
447 Get the path of a program of a derivation.
448
449 # Inputs
450
451 `x`
452
453 : 1\. Function argument
454
455 `y`
456
457 : 2\. Function argument
458
459 # Type
460
461 ```
462 getExe' :: derivation -> string -> string
463 ```
464
465 # Examples
466 :::{.example}
467 ## `lib.meta.getExe'` usage example
468
469 ```nix
470 getExe' pkgs.hello "hello"
471 => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
472 getExe' pkgs.imagemagick "convert"
473 => "/nix/store/5rs48jamq7k6sal98ymj9l4k2bnwq515-imagemagick-7.1.1-15/bin/convert"
474 ```
475
476 :::
477 */
478 getExe' =
479 x: y:
480 assert assertMsg (isDerivation x)
481 "lib.meta.getExe': The first argument is of type ${typeOf x}, but it should be a derivation instead.";
482 assert assertMsg (isString y)
483 "lib.meta.getExe': The second argument is of type ${typeOf y}, but it should be a string instead.";
484 assert assertMsg (match ".*/.*" y == null)
485 "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.";
486 "${getBin x}/bin/${y}";
487}