at master 15 kB view raw
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}