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 != null
293 && ((!pkg ? meta.platforms) || any (platformMatch platform) pkg.meta.platforms)
294 && all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or [ ]);
295
296 /**
297 Mapping of SPDX ID to the attributes in lib.licenses.
298
299 For SPDX IDs, see https://spdx.org/licenses.
300 Note that some SPDX licenses might be missing.
301
302 # Examples
303 :::{.example}
304 ## `lib.meta.licensesSpdx` usage example
305
306 ```nix
307 lib.licensesSpdx.MIT == lib.licenses.mit
308 => true
309 lib.licensesSpdx."MY LICENSE"
310 => error: attribute 'MY LICENSE' missing
311 ```
312
313 :::
314 */
315 licensesSpdx = mapAttrs' (_key: license: {
316 name = license.spdxId;
317 value = license;
318 }) (filterAttrs (_key: license: license ? spdxId) lib.licenses);
319
320 /**
321 Get the corresponding attribute in lib.licenses from the SPDX ID
322 or warn and fallback to `{ shortName = <license string>; }`.
323
324 For SPDX IDs, see https://spdx.org/licenses.
325 Note that some SPDX licenses might be missing.
326
327 # Type
328
329 ```
330 getLicenseFromSpdxId :: str -> AttrSet
331 ```
332
333 # Examples
334 :::{.example}
335 ## `lib.meta.getLicenseFromSpdxId` usage example
336
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 ```
346
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 }
355 );
356
357 /**
358 Get the corresponding attribute in lib.licenses from the SPDX ID
359 or fallback to the given default value.
360
361 For SPDX IDs, see https://spdx.org/licenses.
362 Note that some SPDX licenses might be missing.
363
364 # Inputs
365
366 `licstr`
367 : 1\. SPDX ID string to find a matching license
368
369 `default`
370 : 2\. Fallback value when a match is not found
371
372 # Type
373
374 ```
375 getLicenseFromSpdxIdOr :: str -> Any -> Any
376 ```
377
378 # Examples
379 :::{.example}
380 ## `lib.meta.getLicenseFromSpdxIdOr` usage example
381
382 ```nix
383 lib.getLicenseFromSpdxIdOr "MIT" null == lib.licenses.mit
384 => true
385 lib.getLicenseFromSpdxId "mIt" null == lib.licenses.mit
386 => true
387 lib.getLicenseFromSpdxIdOr "MY LICENSE" lib.licenses.free == lib.licenses.free
388 => true
389 lib.getLicenseFromSpdxIdOr "MY LICENSE" null
390 => null
391 lib.getLicenseFromSpdxIdOr "MY LICENSE" (builtins.throw "No SPDX ID matches MY LICENSE")
392 => error: No SPDX ID matches MY LICENSE
393 ```
394 :::
395 */
396 getLicenseFromSpdxIdOr =
397 let
398 lowercaseLicenses = lib.mapAttrs' (name: value: {
399 name = lib.toLower name;
400 inherit value;
401 }) licensesSpdx;
402 in
403 licstr: default: lowercaseLicenses.${lib.toLower licstr} or default;
404
405 /**
406 Get the path to the main program of a package based on meta.mainProgram
407
408 # Inputs
409
410 `x`
411
412 : 1\. Function argument
413
414 # Type
415
416 ```
417 getExe :: package -> string
418 ```
419
420 # Examples
421 :::{.example}
422 ## `lib.meta.getExe` usage example
423
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 ```
430
431 :::
432 */
433 getExe =
434 x:
435 getExe' x (
436 x.meta.mainProgram or (
437 # This could be turned into an error when 23.05 is at end of life
438 lib.warn
439 "getExe: Package ${
440 lib.strings.escapeNixIdentifier x.meta.name or x.pname or x.name
441 } 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\"."
442 lib.getName
443 x
444 )
445 );
446
447 /**
448 Get the path of a program of a derivation.
449
450 # Inputs
451
452 `x`
453
454 : 1\. Function argument
455
456 `y`
457
458 : 2\. Function argument
459
460 # Type
461
462 ```
463 getExe' :: derivation -> string -> string
464 ```
465
466 # Examples
467 :::{.example}
468 ## `lib.meta.getExe'` usage example
469
470 ```nix
471 getExe' pkgs.hello "hello"
472 => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
473 getExe' pkgs.imagemagick "convert"
474 => "/nix/store/5rs48jamq7k6sal98ymj9l4k2bnwq515-imagemagick-7.1.1-15/bin/convert"
475 ```
476
477 :::
478 */
479 getExe' =
480 x: y:
481 assert assertMsg (isDerivation x)
482 "lib.meta.getExe': The first argument is of type ${typeOf x}, but it should be a derivation instead.";
483 assert assertMsg (isString y)
484 "lib.meta.getExe': The second argument is of type ${typeOf y}, but it should be a string instead.";
485 assert assertMsg (match ".*/.*" y == null)
486 "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.";
487 "${getBin x}/bin/${y}";
488}