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)
19 isString
20 match
21 typeOf
22 elemAt
23 ;
24
25in
26rec {
27
28 /**
29 Add to or override the meta attributes of the given
30 derivation.
31
32 # Inputs
33
34 `newAttrs`
35
36 : 1\. Function argument
37
38 `drv`
39
40 : 2\. Function argument
41
42 # Examples
43 :::{.example}
44 ## `lib.meta.addMetaAttrs` usage example
45
46 ```nix
47 addMetaAttrs {description = "Bla blah";} somePkg
48 ```
49
50 :::
51 */
52 addMetaAttrs =
53 newAttrs: drv:
54 if drv ? overrideAttrs then
55 drv.overrideAttrs (old: {
56 meta = (old.meta or { }) // newAttrs;
57 })
58 else
59 drv // { meta = (drv.meta or { }) // newAttrs; };
60
61 /**
62 Disable Hydra builds of given derivation.
63
64 # Inputs
65
66 `drv`
67
68 : 1\. Function argument
69 */
70 dontDistribute = drv: addMetaAttrs { hydraPlatforms = [ ]; } drv;
71
72 /**
73 Change the [symbolic name of a derivation](https://nixos.org/manual/nix/stable/language/derivations.html#attr-name).
74
75 :::{.warning}
76 Dependent derivations will be rebuilt when the symbolic name is changed.
77 :::
78
79 # Inputs
80
81 `name`
82
83 : 1\. Function argument
84
85 `drv`
86
87 : 2\. Function argument
88 */
89 setName = name: drv: drv // { inherit name; };
90
91 /**
92 Like `setName`, but takes the previous name as an argument.
93
94 # Inputs
95
96 `updater`
97
98 : 1\. Function argument
99
100 `drv`
101
102 : 2\. Function argument
103
104 # Examples
105 :::{.example}
106 ## `lib.meta.updateName` usage example
107
108 ```nix
109 updateName (oldName: oldName + "-experimental") somePkg
110 ```
111
112 :::
113 */
114 updateName = updater: drv: drv // { name = updater (drv.name); };
115
116 /**
117 Append a suffix to the name of a package (before the version
118 part).
119
120 # Inputs
121
122 `suffix`
123
124 : 1\. Function argument
125 */
126 appendToName =
127 suffix:
128 updateName (
129 name:
130 let
131 x = builtins.parseDrvName name;
132 in
133 "${x.name}-${suffix}-${x.version}"
134 );
135
136 /**
137 Apply a function to each derivation and only to derivations in an attrset.
138
139 # Inputs
140
141 `f`
142
143 : 1\. Function argument
144
145 `set`
146
147 : 2\. Function argument
148 */
149 mapDerivationAttrset =
150 f: set: lib.mapAttrs (name: pkg: if lib.isDerivation pkg then (f pkg) else pkg) set;
151
152 /**
153 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).
154 */
155 defaultPriority = 5;
156
157 /**
158 Set the nix-env priority of the package. Note that higher values are lower priority, and vice versa.
159
160 # Inputs
161
162 `priority`
163 : 1\. The priority to set.
164
165 `drv`
166 : 2\. Function argument
167 */
168 setPrio = priority: addMetaAttrs { inherit priority; };
169
170 /**
171 Decrease the nix-env priority of the package, i.e., other
172 versions/variants of the package will be preferred.
173
174 # Inputs
175
176 `drv`
177
178 : 1\. Function argument
179 */
180 lowPrio = setPrio 10;
181
182 /**
183 Apply lowPrio to an attrset with derivations.
184
185 # Inputs
186
187 `set`
188
189 : 1\. Function argument
190 */
191 lowPrioSet = set: mapDerivationAttrset lowPrio set;
192
193 /**
194 Increase the nix-env priority of the package, i.e., this
195 version/variant of the package will be preferred.
196
197 # Inputs
198
199 `drv`
200
201 : 1\. Function argument
202 */
203 hiPrio = setPrio (-10);
204
205 /**
206 Apply hiPrio to an attrset with derivations.
207
208 # Inputs
209
210 `set`
211
212 : 1\. Function argument
213 */
214 hiPrioSet = set: mapDerivationAttrset hiPrio set;
215
216 /**
217 Check to see if a platform is matched by the given `meta.platforms`
218 element.
219
220 A `meta.platform` pattern is either
221
222 1. (legacy) a system string.
223
224 2. (modern) a pattern for the entire platform structure (see `lib.systems.inspect.platformPatterns`).
225
226 3. (modern) a pattern for the platform `parsed` field (see `lib.systems.inspect.patterns`).
227
228 We can inject these into a pattern for the whole of a structured platform,
229 and then match that.
230
231 # Inputs
232
233 `platform`
234
235 : 1\. Function argument
236
237 `elem`
238
239 : 2\. Function argument
240
241 # Examples
242 :::{.example}
243 ## `lib.meta.platformMatch` usage example
244
245 ```nix
246 lib.meta.platformMatch { system = "aarch64-darwin"; } "aarch64-darwin"
247 => true
248 ```
249
250 :::
251 */
252 platformMatch =
253 platform: elem:
254 (
255 # Check with simple string comparison if elem was a string.
256 #
257 # The majority of comparisons done with this function will be against meta.platforms
258 # which contains a simple platform string.
259 #
260 # Avoiding an attrset allocation results in significant performance gains (~2-30) across the board in OfBorg
261 # because this is a hot path for nixpkgs.
262 if isString elem then
263 platform ? system && elem == platform.system
264 else
265 matchAttrs (
266 # Normalize platform attrset.
267 if elem ? parsed then elem else { parsed = elem; }
268 ) platform
269 );
270
271 /**
272 Check if a package is available on a given platform.
273
274 A package is available on a platform if both
275
276 1. One of `meta.platforms` pattern matches the given
277 platform, or `meta.platforms` is not present.
278
279 2. None of `meta.badPlatforms` pattern matches the given platform.
280
281 # Inputs
282
283 `platform`
284
285 : 1\. Function argument
286
287 `pkg`
288
289 : 2\. Function argument
290
291 # Examples
292 :::{.example}
293 ## `lib.meta.availableOn` usage example
294
295 ```nix
296 lib.meta.availableOn { system = "aarch64-darwin"; } pkg.zsh
297 => true
298 ```
299
300 :::
301 */
302 availableOn =
303 platform: pkg:
304 ((!pkg ? meta.platforms) || any (platformMatch platform) pkg.meta.platforms)
305 && all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or [ ]);
306
307 /**
308 Mapping of SPDX ID to the attributes in lib.licenses.
309
310 For SPDX IDs, see https://spdx.org/licenses.
311 Note that some SPDX licenses might be missing.
312
313 # Examples
314 :::{.example}
315 ## `lib.meta.licensesSpdx` usage example
316
317 ```nix
318 lib.licensesSpdx.MIT == lib.licenses.mit
319 => true
320 lib.licensesSpdx."MY LICENSE"
321 => error: attribute 'MY LICENSE' missing
322 ```
323
324 :::
325 */
326 licensesSpdx = mapAttrs' (_key: license: {
327 name = license.spdxId;
328 value = license;
329 }) (filterAttrs (_key: license: license ? spdxId) lib.licenses);
330
331 /**
332 Get the corresponding attribute in lib.licenses from the SPDX ID
333 or warn and fallback to `{ shortName = <license string>; }`.
334
335 For SPDX IDs, see https://spdx.org/licenses.
336 Note that some SPDX licenses might be missing.
337
338 # Type
339
340 ```
341 getLicenseFromSpdxId :: str -> AttrSet
342 ```
343
344 # Examples
345 :::{.example}
346 ## `lib.meta.getLicenseFromSpdxId` usage example
347
348 ```nix
349 lib.getLicenseFromSpdxId "MIT" == lib.licenses.mit
350 => true
351 lib.getLicenseFromSpdxId "mIt" == lib.licenses.mit
352 => true
353 lib.getLicenseFromSpdxId "MY LICENSE"
354 => trace: warning: getLicenseFromSpdxId: No license matches the given SPDX ID: MY LICENSE
355 => { shortName = "MY LICENSE"; }
356 ```
357
358 :::
359 */
360 getLicenseFromSpdxId =
361 licstr:
362 getLicenseFromSpdxIdOr licstr (
363 lib.warn "getLicenseFromSpdxId: No license matches the given SPDX ID: ${licstr}" {
364 shortName = licstr;
365 }
366 );
367
368 /**
369 Get the corresponding attribute in lib.licenses from the SPDX ID
370 or fallback to the given default value.
371
372 For SPDX IDs, see https://spdx.org/licenses.
373 Note that some SPDX licenses might be missing.
374
375 # Inputs
376
377 `licstr`
378 : 1\. SPDX ID string to find a matching license
379
380 `default`
381 : 2\. Fallback value when a match is not found
382
383 # Type
384
385 ```
386 getLicenseFromSpdxIdOr :: str -> Any -> Any
387 ```
388
389 # Examples
390 :::{.example}
391 ## `lib.meta.getLicenseFromSpdxIdOr` usage example
392
393 ```nix
394 lib.getLicenseFromSpdxIdOr "MIT" null == lib.licenses.mit
395 => true
396 lib.getLicenseFromSpdxId "mIt" null == lib.licenses.mit
397 => true
398 lib.getLicenseFromSpdxIdOr "MY LICENSE" lib.licenses.free == lib.licenses.free
399 => true
400 lib.getLicenseFromSpdxIdOr "MY LICENSE" null
401 => null
402 lib.getLicenseFromSpdxIdOr "MY LICENSE" (throw "No SPDX ID matches MY LICENSE")
403 => error: No SPDX ID matches MY LICENSE
404 ```
405 :::
406 */
407 getLicenseFromSpdxIdOr =
408 let
409 lowercaseLicenses = lib.mapAttrs' (name: value: {
410 name = lib.toLower name;
411 inherit value;
412 }) licensesSpdx;
413 in
414 licstr: default: lowercaseLicenses.${lib.toLower licstr} or default;
415
416 /**
417 Get the path to the main program of a package based on meta.mainProgram
418
419 # Inputs
420
421 `x`
422
423 : 1\. Function argument
424
425 # Type
426
427 ```
428 getExe :: package -> string
429 ```
430
431 # Examples
432 :::{.example}
433 ## `lib.meta.getExe` usage example
434
435 ```nix
436 getExe pkgs.hello
437 => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
438 getExe pkgs.mustache-go
439 => "/nix/store/am9ml4f4ywvivxnkiaqwr0hyxka1xjsf-mustache-go-1.3.0/bin/mustache"
440 ```
441
442 :::
443 */
444 getExe =
445 x:
446 getExe' x (
447 x.meta.mainProgram or (
448 # This could be turned into an error when 23.05 is at end of life
449 lib.warn
450 "getExe: Package ${
451 lib.strings.escapeNixIdentifier x.meta.name or x.pname or x.name
452 } 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\"."
453 lib.getName
454 x
455 )
456 );
457
458 /**
459 Get the path of a program of a derivation.
460
461 # Inputs
462
463 `x`
464
465 : 1\. Function argument
466
467 `y`
468
469 : 2\. Function argument
470
471 # Type
472
473 ```
474 getExe' :: derivation -> string -> string
475 ```
476
477 # Examples
478 :::{.example}
479 ## `lib.meta.getExe'` usage example
480
481 ```nix
482 getExe' pkgs.hello "hello"
483 => "/nix/store/g124820p9hlv4lj8qplzxw1c44dxaw1k-hello-2.12/bin/hello"
484 getExe' pkgs.imagemagick "convert"
485 => "/nix/store/5rs48jamq7k6sal98ymj9l4k2bnwq515-imagemagick-7.1.1-15/bin/convert"
486 ```
487
488 :::
489 */
490 getExe' =
491 x: y:
492 assert assertMsg (isDerivation x)
493 "lib.meta.getExe': The first argument is of type ${typeOf x}, but it should be a derivation instead.";
494 assert assertMsg (isString y)
495 "lib.meta.getExe': The second argument is of type ${typeOf y}, but it should be a string instead.";
496 assert assertMsg (match ".*/.*" y == null)
497 "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.";
498 "${getBin x}/bin/${y}";
499
500 /**
501 Generate [CPE parts](#var-meta-identifiers-cpeParts) from inputs. Copies `vendor` and `version` to the output, and sets `update` to `*`.
502
503 # Inputs
504
505 `vendor`
506
507 : package's vendor
508
509 `version`
510
511 : package's version
512
513 # Type
514
515 ```
516 cpeFullVersionWithVendor :: string -> string -> AttrSet
517 ```
518
519 # Examples
520 :::{.example}
521 ## `lib.meta.cpeFullVersionWithVendor` usage example
522
523 ```nix
524 lib.meta.cpeFullVersionWithVendor "gnu" "1.2.3"
525 => {
526 vendor = "gnu";
527 version = "1.2.3";
528 update = "*";
529 }
530 ```
531
532 :::
533 :::{.example}
534 ## `lib.meta.cpeFullVersionWithVendor` usage in derivations
535
536 ```nix
537 mkDerivation rec {
538 version = "1.2.3";
539 # ...
540 meta = {
541 # ...
542 identifiers.cpeParts = lib.meta.cpeFullVersionWithVendor "gnu" version;
543 };
544 }
545 ```
546 :::
547 */
548 cpeFullVersionWithVendor = vendor: version: {
549 inherit vendor version;
550 update = "*";
551 };
552
553 /**
554 Alternate version of [`lib.meta.cpePatchVersionInUpdateWithVendor`](#function-library-lib.meta.cpePatchVersionInUpdateWithVendor).
555 If `cpePatchVersionInUpdateWithVendor` succeeds, returns an attribute set with `success` set to `true` and `value` set to the result.
556 Otherwise, `success` is set to `false` and `error` is set to the string representation of the error.
557
558 # Inputs
559
560 `vendor`
561
562 : package's vendor
563
564 `version`
565
566 : package's version
567
568 # Type
569
570 ```
571 tryCPEPatchVersionInUpdateWithVendor :: string -> string -> AttrSet
572 ```
573
574 # Examples
575 :::{.example}
576 ## `lib.meta.tryCPEPatchVersionInUpdateWithVendor` usage example
577
578 ```nix
579 lib.meta.tryCPEPatchVersionInUpdateWithVendor "gnu" "1.2.3"
580 => {
581 success = true;
582 value = {
583 vendor = "gnu";
584 version = "1.2";
585 update = "3";
586 };
587 }
588 ```
589
590 :::
591 :::{.example}
592 ## `lib.meta.cpePatchVersionInUpdateWithVendor` error example
593
594 ```nix
595 lib.meta.tryCPEPatchVersionInUpdateWithVendor "gnu" "5.3p0"
596 => {
597 success = false;
598 error = "version 5.3p0 doesn't match regex `([0-9]+\\.[0-9]+)\\.([0-9]+)`";
599 }
600 ```
601
602 :::
603 */
604 tryCPEPatchVersionInUpdateWithVendor =
605 vendor: version:
606 let
607 regex = "([0-9]+\\.[0-9]+)\\.([0-9]+)";
608 # we have to call toString here in case version is an attrset with __toString attribute
609 versionMatch = builtins.match regex (toString version);
610 in
611 if versionMatch == null then
612 {
613 success = false;
614 error = "version ${version} doesn't match regex `${regex}`";
615 }
616 else
617 {
618 success = true;
619 value = {
620 inherit vendor;
621 version = elemAt versionMatch 0;
622 update = elemAt versionMatch 1;
623 };
624 };
625
626 /**
627 Generate [CPE parts](#var-meta-identifiers-cpeParts) from inputs. Copies `vendor` to the result. When `version` matches `X.Y.Z` where all parts are numerical, sets `version` and `update` fields to `X.Y` and `Z`. Throws an error if the version doesn't match the expected template.
628
629 # Inputs
630
631 `vendor`
632
633 : package's vendor
634
635 `version`
636
637 : package's version
638
639 # Type
640
641 ```
642 cpePatchVersionInUpdateWithVendor :: string -> string -> AttrSet
643 ```
644
645 # Examples
646 :::{.example}
647 ## `lib.meta.cpePatchVersionInUpdateWithVendor` usage example
648
649 ```nix
650 lib.meta.cpePatchVersionInUpdateWithVendor "gnu" "1.2.3"
651 => {
652 vendor = "gnu";
653 version = "1.2";
654 update = "3";
655 }
656 ```
657
658 :::
659 :::{.example}
660 ## `lib.meta.cpePatchVersionInUpdateWithVendor` usage in derivations
661
662 ```nix
663 mkDerivation rec {
664 version = "1.2.3";
665 # ...
666 meta = {
667 # ...
668 identifiers.cpeParts = lib.meta.cpePatchVersionInUpdateWithVendor "gnu" version;
669 };
670 }
671 ```
672
673 :::
674 */
675 cpePatchVersionInUpdateWithVendor =
676 vendor: version:
677 let
678 result = tryCPEPatchVersionInUpdateWithVendor vendor version;
679 in
680 if result.success then result.value else throw result.error;
681}