at 24.11-pre 20 kB view raw
1{ lib }: 2 3let 4 inherit (builtins) 5 intersectAttrs; 6 inherit (lib) 7 functionArgs isFunction mirrorFunctionArgs isAttrs setFunctionArgs 8 optionalAttrs attrNames filter elemAt concatStringsSep sortOn take length 9 filterAttrs optionalString flip pathIsDirectory head pipe isDerivation listToAttrs 10 mapAttrs seq flatten deepSeq warnIf isInOldestRelease extends 11 ; 12 inherit (lib.strings) levenshtein levenshteinAtMost; 13 14in 15rec { 16 17 18 /** 19 `overrideDerivation drv f` takes a derivation (i.e., the result 20 of a call to the builtin function `derivation`) and returns a new 21 derivation in which the attributes of the original are overridden 22 according to the function `f`. The function `f` is called with 23 the original derivation attributes. 24 25 `overrideDerivation` allows certain "ad-hoc" customisation 26 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance, 27 if you want to "patch" the derivation returned by a package 28 function in Nixpkgs to build another version than what the 29 function itself provides. 30 31 For another application, see build-support/vm, where this 32 function is used to build arbitrary derivations inside a QEMU 33 virtual machine. 34 35 Note that in order to preserve evaluation errors, the new derivation's 36 outPath depends on the old one's, which means that this function cannot 37 be used in circular situations when the old derivation also depends on the 38 new one. 39 40 You should in general prefer `drv.overrideAttrs` over this function; 41 see the nixpkgs manual for more information on overriding. 42 43 44 # Inputs 45 46 `drv` 47 48 : 1\. Function argument 49 50 `f` 51 52 : 2\. Function argument 53 54 # Type 55 56 ``` 57 overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation 58 ``` 59 60 # Examples 61 :::{.example} 62 ## `lib.customisation.overrideDerivation` usage example 63 64 ```nix 65 mySed = overrideDerivation pkgs.gnused (oldAttrs: { 66 name = "sed-4.2.2-pre"; 67 src = fetchurl { 68 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2; 69 hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY="; 70 }; 71 patches = []; 72 }); 73 ``` 74 75 ::: 76 */ 77 overrideDerivation = drv: f: 78 let 79 newDrv = derivation (drv.drvAttrs // (f drv)); 80 in flip (extendDerivation (seq drv.drvPath true)) newDrv ( 81 { meta = drv.meta or {}; 82 passthru = if drv ? passthru then drv.passthru else {}; 83 } 84 // 85 (drv.passthru or {}) 86 // 87 optionalAttrs (drv ? __spliced) { 88 __spliced = {} // (mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced); 89 }); 90 91 92 /** 93 `makeOverridable` takes a function from attribute set to attribute set and 94 injects `override` attribute which can be used to override arguments of 95 the function. 96 97 Please refer to documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats 98 related to its use. 99 100 101 # Inputs 102 103 `f` 104 105 : 1\. Function argument 106 107 # Type 108 109 ``` 110 makeOverridable :: (AttrSet -> a) -> AttrSet -> a 111 ``` 112 113 # Examples 114 :::{.example} 115 ## `lib.customisation.makeOverridable` usage example 116 117 ```nix 118 nix-repl> x = {a, b}: { result = a + b; } 119 120 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; } 121 122 nix-repl> y 123 { override = «lambda»; overrideDerivation = «lambda»; result = 3; } 124 125 nix-repl> y.override { a = 10; } 126 { override = «lambda»; overrideDerivation = «lambda»; result = 12; } 127 ``` 128 129 ::: 130 */ 131 makeOverridable = f: 132 let 133 # Creates a functor with the same arguments as f 134 mirrorArgs = mirrorFunctionArgs f; 135 in 136 mirrorArgs (origArgs: 137 let 138 result = f origArgs; 139 140 # Changes the original arguments with (potentially a function that returns) a set of new attributes 141 overrideWith = newArgs: origArgs // (if isFunction newArgs then newArgs origArgs else newArgs); 142 143 # Re-call the function but with different arguments 144 overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs)); 145 # Change the result of the function call by applying g to it 146 overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs; 147 in 148 if isAttrs result then 149 result // { 150 override = overrideArgs; 151 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv); 152 ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv: 153 overrideResult (x: x.overrideAttrs fdrv); 154 } 155 else if isFunction result then 156 # Transform the result into a functor while propagating its arguments 157 setFunctionArgs result (functionArgs result) // { 158 override = overrideArgs; 159 } 160 else result); 161 162 163 /** 164 Call the package function in the file `fn` with the required 165 arguments automatically. The function is called with the 166 arguments `args`, but any missing arguments are obtained from 167 `autoArgs`. This function is intended to be partially 168 parameterised, e.g., 169 170 ```nix 171 callPackage = callPackageWith pkgs; 172 pkgs = { 173 libfoo = callPackage ./foo.nix { }; 174 libbar = callPackage ./bar.nix { }; 175 }; 176 ``` 177 178 If the `libbar` function expects an argument named `libfoo`, it is 179 automatically passed as an argument. Overrides or missing 180 arguments can be supplied in `args`, e.g. 181 182 ```nix 183 libbar = callPackage ./bar.nix { 184 libfoo = null; 185 enableX11 = true; 186 }; 187 ``` 188 189 <!-- TODO: Apply "Example:" tag to the examples above --> 190 191 192 # Inputs 193 194 `autoArgs` 195 196 : 1\. Function argument 197 198 `fn` 199 200 : 2\. Function argument 201 202 `args` 203 204 : 3\. Function argument 205 206 # Type 207 208 ``` 209 callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 210 ``` 211 */ 212 callPackageWith = autoArgs: fn: args: 213 let 214 f = if isFunction fn then fn else import fn; 215 fargs = functionArgs f; 216 217 # All arguments that will be passed to the function 218 # This includes automatic ones and ones passed explicitly 219 allArgs = intersectAttrs fargs autoArgs // args; 220 221 # a list of argument names that the function requires, but 222 # wouldn't be passed to it 223 missingArgs = 224 # Filter out arguments that have a default value 225 (filterAttrs (name: value: ! value) 226 # Filter out arguments that would be passed 227 (removeAttrs fargs (attrNames allArgs))); 228 229 # Get a list of suggested argument names for a given missing one 230 getSuggestions = arg: pipe (autoArgs // args) [ 231 attrNames 232 # Only use ones that are at most 2 edits away. While mork would work, 233 # levenshteinAtMost is only fast for 2 or less. 234 (filter (levenshteinAtMost 2 arg)) 235 # Put strings with shorter distance first 236 (sortOn (levenshtein arg)) 237 # Only take the first couple results 238 (take 3) 239 # Quote all entries 240 (map (x: "\"" + x + "\"")) 241 ]; 242 243 prettySuggestions = suggestions: 244 if suggestions == [] then "" 245 else if length suggestions == 1 then ", did you mean ${elemAt suggestions 0}?" 246 else ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?"; 247 248 errorForArg = arg: 249 let 250 loc = builtins.unsafeGetAttrPos arg fargs; 251 # loc' can be removed once lib/minver.nix is >2.3.4, since that includes 252 # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null 253 loc' = if loc != null then loc.file + ":" + toString loc.line 254 else if ! isFunction fn then 255 toString fn + optionalString (pathIsDirectory fn) "/default.nix" 256 else "<unknown location>"; 257 in "Function called without required argument \"${arg}\" at " 258 + "${loc'}${prettySuggestions (getSuggestions arg)}"; 259 260 # Only show the error for the first missing argument 261 error = errorForArg (head (attrNames missingArgs)); 262 263 in if missingArgs == {} 264 then makeOverridable f allArgs 265 # This needs to be an abort so it can't be caught with `builtins.tryEval`, 266 # which is used by nix-env and ofborg to filter out packages that don't evaluate. 267 # This way we're forced to fix such errors in Nixpkgs, 268 # which is especially relevant with allowAliases = false 269 else abort "lib.customisation.callPackageWith: ${error}"; 270 271 272 /** 273 Like callPackage, but for a function that returns an attribute 274 set of derivations. The override function is added to the 275 individual attributes. 276 277 278 # Inputs 279 280 `autoArgs` 281 282 : 1\. Function argument 283 284 `fn` 285 286 : 2\. Function argument 287 288 `args` 289 290 : 3\. Function argument 291 292 # Type 293 294 ``` 295 callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet 296 ``` 297 */ 298 callPackagesWith = autoArgs: fn: args: 299 let 300 f = if isFunction fn then fn else import fn; 301 auto = intersectAttrs (functionArgs f) autoArgs; 302 mirrorArgs = mirrorFunctionArgs f; 303 origArgs = auto // args; 304 pkgs = f origArgs; 305 mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs; 306 in 307 if isDerivation pkgs then throw 308 ("function `callPackages` was called on a *single* derivation " 309 + ''"${pkgs.name or "<unknown-name>"}";'' 310 + " did you mean to use `callPackage` instead?") 311 else mapAttrs mkAttrOverridable pkgs; 312 313 314 /** 315 Add attributes to each output of a derivation without changing 316 the derivation itself and check a given condition when evaluating. 317 318 319 # Inputs 320 321 `condition` 322 323 : 1\. Function argument 324 325 `passthru` 326 327 : 2\. Function argument 328 329 `drv` 330 331 : 3\. Function argument 332 333 # Type 334 335 ``` 336 extendDerivation :: Bool -> Any -> Derivation -> Derivation 337 ``` 338 */ 339 extendDerivation = condition: passthru: drv: 340 let 341 outputs = drv.outputs or [ "out" ]; 342 343 commonAttrs = drv // (listToAttrs outputsList) // 344 ({ all = map (x: x.value) outputsList; }) // passthru; 345 346 outputToAttrListElement = outputName: 347 { name = outputName; 348 value = commonAttrs // { 349 inherit (drv.${outputName}) type outputName; 350 outputSpecified = true; 351 drvPath = assert condition; drv.${outputName}.drvPath; 352 outPath = assert condition; drv.${outputName}.outPath; 353 } // 354 # TODO: give the derivation control over the outputs. 355 # `overrideAttrs` may not be the only attribute that needs 356 # updating when switching outputs. 357 optionalAttrs (passthru?overrideAttrs) { 358 # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing. 359 overrideAttrs = f: (passthru.overrideAttrs f).${outputName}; 360 }; 361 }; 362 363 outputsList = map outputToAttrListElement outputs; 364 in commonAttrs // { 365 drvPath = assert condition; drv.drvPath; 366 outPath = assert condition; drv.outPath; 367 }; 368 369 /** 370 Strip a derivation of all non-essential attributes, returning 371 only those needed by hydra-eval-jobs. Also strictly evaluate the 372 result to ensure that there are no thunks kept alive to prevent 373 garbage collection. 374 375 376 # Inputs 377 378 `drv` 379 380 : 1\. Function argument 381 382 # Type 383 384 ``` 385 hydraJob :: (Derivation | Null) -> (Derivation | Null) 386 ``` 387 */ 388 hydraJob = drv: 389 let 390 outputs = drv.outputs or ["out"]; 391 392 commonAttrs = 393 { inherit (drv) name system meta; inherit outputs; } 394 // optionalAttrs (drv._hydraAggregate or false) { 395 _hydraAggregate = true; 396 constituents = map hydraJob (flatten drv.constituents); 397 } 398 // (listToAttrs outputsList); 399 400 makeOutput = outputName: 401 let output = drv.${outputName}; in 402 { name = outputName; 403 value = commonAttrs // { 404 outPath = output.outPath; 405 drvPath = output.drvPath; 406 type = "derivation"; 407 inherit outputName; 408 }; 409 }; 410 411 outputsList = map makeOutput outputs; 412 413 drv' = (head outputsList).value; 414 in if drv == null then null else 415 deepSeq drv' drv'; 416 417 /** 418 Make an attribute set (a "scope") from functions that take arguments from that same attribute set. 419 See [](#ex-makeScope) for how to use it. 420 421 # Inputs 422 423 1. `newScope` (`AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a`) 424 425 A function that takes an attribute set `attrs` and returns what ends up as `callPackage` in the output. 426 427 Typical values are `callPackageWith` or the output attribute `newScope`. 428 429 2. `f` (`AttrSet -> AttrSet`) 430 431 A function that takes an attribute set as returned by `makeScope newScope f` (a "scope") and returns any attribute set. 432 433 This function is used to compute the fixpoint of the resulting scope using `callPackage`. 434 Its argument is the lazily evaluated reference to the value of that fixpoint, and is typically called `self` or `final`. 435 436 See [](#ex-makeScope) for how to use it. 437 See [](#sec-functions-library-fixedPoints) for details on fixpoint computation. 438 439 # Output 440 441 `makeScope` returns an attribute set of a form called `scope`, which also contains the final attributes produced by `f`: 442 443 ``` 444 scope :: { 445 callPackage :: ((AttrSet -> a) | Path) -> AttrSet -> a 446 newScope = AttrSet -> scope 447 overrideScope = (scope -> scope -> AttrSet) -> scope 448 packages :: AttrSet -> AttrSet 449 } 450 ``` 451 452 - `callPackage` (`((AttrSet -> a) | Path) -> AttrSet -> a`) 453 454 A function that 455 456 1. Takes a function `p`, or a path to a Nix file that contains a function `p`, which takes an attribute set and returns value of arbitrary type `a`, 457 2. Takes an attribute set `args` with explicit attributes to pass to `p`, 458 3. Calls `f` with attributes from the original attribute set `attrs` passed to `newScope` updated with `args, i.e. `attrs // args`, if they match the attributes in the argument of `p`. 459 460 All such functions `p` will be called with the same value for `attrs`. 461 462 See [](#ex-makeScope-callPackage) for how to use it. 463 464 - `newScope` (`AttrSet -> scope`) 465 466 Takes an attribute set `attrs` and returns a scope that extends the original scope. 467 468 - `overrideScope` (`(scope -> scope -> AttrSet) -> scope`) 469 470 Takes a function `g` of the form `final: prev: { # attributes }` to act as an overlay on `f`, and returns a new scope with values determined by `extends g f`. 471 See [](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.fixedPoints.extends) for details. 472 473 This allows subsequent modification of the final attribute set in a consistent way, i.e. all functions `p` invoked with `callPackage` will be called with the modified values. 474 475 - `packages` (`AttrSet -> AttrSet`) 476 477 The value of the argument `f` to `makeScope`. 478 479 - final attributes 480 481 The final values returned by `f`. 482 483 # Examples 484 485 :::{#ex-makeScope .example} 486 # Create an interdependent package set on top of `pkgs` 487 488 The functions in `foo.nix` and `bar.nix` can depend on each other, in the sense that `foo.nix` can contain a function that expects `bar` as an attribute in its argument. 489 490 ```nix 491 let 492 pkgs = import <nixpkgs> { }; 493 in 494 pkgs.lib.makeScope pkgs.newScope (self: { 495 foo = self.callPackage ./foo.nix { }; 496 bar = self.callPackage ./bar.nix { }; 497 }) 498 ``` 499 500 evaluates to 501 502 ```nix 503 { 504 callPackage = «lambda»; 505 newScope = «lambda»; 506 overrideScope = «lambda»; 507 packages = «lambda»; 508 foo = «derivation»; 509 bar = «derivation»; 510 } 511 ``` 512 ::: 513 514 :::{#ex-makeScope-callPackage .example} 515 # Using `callPackage` from a scope 516 517 ```nix 518 let 519 pkgs = import <nixpkgs> { }; 520 inherit (pkgs) lib; 521 scope = lib.makeScope lib.callPackageWith (self: { a = 1; b = 2; }); 522 three = scope.callPackage ({ a, b }: a + b) { }; 523 four = scope.callPackage ({ a, b }: a + b) { a = 2; }; 524 in 525 [ three four ] 526 ``` 527 528 evaluates to 529 530 ```nix 531 [ 3 4 ] 532 ``` 533 ::: 534 535 # Type 536 537 ``` 538 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> scope 539 ``` 540 */ 541 makeScope = newScope: f: 542 let self = f self // { 543 newScope = scope: newScope (self // scope); 544 callPackage = self.newScope {}; 545 overrideScope = g: makeScope newScope (extends g f); 546 # Remove after 24.11 is released. 547 overrideScope' = g: warnIf (isInOldestRelease 2311) 548 "`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`." 549 (makeScope newScope (extends g f)); 550 packages = f; 551 }; 552 in self; 553 554 /** 555 backward compatibility with old uncurried form; deprecated 556 557 558 # Inputs 559 560 `splicePackages` 561 562 : 1\. Function argument 563 564 `newScope` 565 566 : 2\. Function argument 567 568 `otherSplices` 569 570 : 3\. Function argument 571 572 `keep` 573 574 : 4\. Function argument 575 576 `extra` 577 578 : 5\. Function argument 579 580 `f` 581 582 : 6\. Function argument 583 */ 584 makeScopeWithSplicing = 585 splicePackages: newScope: otherSplices: keep: extra: f: 586 makeScopeWithSplicing' 587 { inherit splicePackages newScope; } 588 { inherit otherSplices keep extra f; }; 589 590 /** 591 Like makeScope, but aims to support cross compilation. It's still ugly, but 592 hopefully it helps a little bit. 593 594 # Type 595 596 ``` 597 makeScopeWithSplicing' :: 598 { splicePackages :: Splice -> AttrSet 599 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 600 } 601 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet } 602 -> AttrSet 603 604 Splice :: 605 { pkgsBuildBuild :: AttrSet 606 , pkgsBuildHost :: AttrSet 607 , pkgsBuildTarget :: AttrSet 608 , pkgsHostHost :: AttrSet 609 , pkgsHostTarget :: AttrSet 610 , pkgsTargetTarget :: AttrSet 611 } 612 ``` 613 */ 614 makeScopeWithSplicing' = 615 { splicePackages 616 , newScope 617 }: 618 { otherSplices 619 # Attrs from `self` which won't be spliced. 620 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201. 621 # ex: `keep = (self: { inherit (self) aAttr; })` 622 , keep ? (_self: {}) 623 # Additional attrs to add to the sets `callPackage`. 624 # When the package is from a subset (but not a subset within a package IS #211340) 625 # within `spliced0` it will be spliced. 626 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`. 627 # If the package is not available within the set or in `pkgs`, such as a package in a let binding, it will not be spliced 628 # ex: 629 # ``` 630 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation 631 # «derivation ...CoreFoundation-11.0.0.drv» 632 # nix-repl> darwin.CoreFoundation 633 # error: attribute 'CoreFoundation' missing 634 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { } 635 # «derivation ...CoreFoundation-11.0.0.drv» 636 # ``` 637 , extra ? (_spliced0: {}) 638 , f 639 }: 640 let 641 spliced0 = splicePackages { 642 pkgsBuildBuild = otherSplices.selfBuildBuild; 643 pkgsBuildHost = otherSplices.selfBuildHost; 644 pkgsBuildTarget = otherSplices.selfBuildTarget; 645 pkgsHostHost = otherSplices.selfHostHost; 646 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`; 647 pkgsTargetTarget = otherSplices.selfTargetTarget; 648 }; 649 spliced = extra spliced0 // spliced0 // keep self; 650 self = f self // { 651 newScope = scope: newScope (spliced // scope); 652 callPackage = newScope spliced; # == self.newScope {}; 653 # N.B. the other stages of the package set spliced in are *not* 654 # overridden. 655 overrideScope = g: (makeScopeWithSplicing' 656 { inherit splicePackages newScope; } 657 { inherit otherSplices keep extra; 658 f = extends g f; 659 }); 660 packages = f; 661 }; 662 in self; 663 664}