at 23.11-beta 15 kB view raw
1{ lib }: 2 3rec { 4 5 6 /* `overrideDerivation drv f` takes a derivation (i.e., the result 7 of a call to the builtin function `derivation`) and returns a new 8 derivation in which the attributes of the original are overridden 9 according to the function `f`. The function `f` is called with 10 the original derivation attributes. 11 12 `overrideDerivation` allows certain "ad-hoc" customisation 13 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance, 14 if you want to "patch" the derivation returned by a package 15 function in Nixpkgs to build another version than what the 16 function itself provides. 17 18 For another application, see build-support/vm, where this 19 function is used to build arbitrary derivations inside a QEMU 20 virtual machine. 21 22 Note that in order to preserve evaluation errors, the new derivation's 23 outPath depends on the old one's, which means that this function cannot 24 be used in circular situations when the old derivation also depends on the 25 new one. 26 27 You should in general prefer `drv.overrideAttrs` over this function; 28 see the nixpkgs manual for more information on overriding. 29 30 Example: 31 mySed = overrideDerivation pkgs.gnused (oldAttrs: { 32 name = "sed-4.2.2-pre"; 33 src = fetchurl { 34 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2; 35 hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY="; 36 }; 37 patches = []; 38 }); 39 40 Type: 41 overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation 42 */ 43 overrideDerivation = drv: f: 44 let 45 newDrv = derivation (drv.drvAttrs // (f drv)); 46 in lib.flip (extendDerivation (builtins.seq drv.drvPath true)) newDrv ( 47 { meta = drv.meta or {}; 48 passthru = if drv ? passthru then drv.passthru else {}; 49 } 50 // 51 (drv.passthru or {}) 52 // 53 lib.optionalAttrs (drv ? __spliced) { 54 __spliced = {} // (lib.mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced); 55 }); 56 57 58 /* `makeOverridable` takes a function from attribute set to attribute set and 59 injects `override` attribute which can be used to override arguments of 60 the function. 61 62 Please refer to documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats 63 related to its use. 64 65 Example: 66 nix-repl> x = {a, b}: { result = a + b; } 67 68 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; } 69 70 nix-repl> y 71 { override = «lambda»; overrideDerivation = «lambda»; result = 3; } 72 73 nix-repl> y.override { a = 10; } 74 { override = «lambda»; overrideDerivation = «lambda»; result = 12; } 75 76 Type: 77 makeOverridable :: (AttrSet -> a) -> AttrSet -> a 78 */ 79 makeOverridable = f: 80 let 81 # Creates a functor with the same arguments as f 82 mirrorArgs = lib.mirrorFunctionArgs f; 83 in 84 mirrorArgs (origArgs: 85 let 86 result = f origArgs; 87 88 # Changes the original arguments with (potentially a function that returns) a set of new attributes 89 overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs); 90 91 # Re-call the function but with different arguments 92 overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs)); 93 # Change the result of the function call by applying g to it 94 overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs; 95 in 96 if builtins.isAttrs result then 97 result // { 98 override = overrideArgs; 99 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv); 100 ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv: 101 overrideResult (x: x.overrideAttrs fdrv); 102 } 103 else if lib.isFunction result then 104 # Transform the result into a functor while propagating its arguments 105 lib.setFunctionArgs result (lib.functionArgs result) // { 106 override = overrideArgs; 107 } 108 else result); 109 110 111 /* Call the package function in the file `fn` with the required 112 arguments automatically. The function is called with the 113 arguments `args`, but any missing arguments are obtained from 114 `autoArgs`. This function is intended to be partially 115 parameterised, e.g., 116 117 ```nix 118 callPackage = callPackageWith pkgs; 119 pkgs = { 120 libfoo = callPackage ./foo.nix { }; 121 libbar = callPackage ./bar.nix { }; 122 }; 123 ``` 124 125 If the `libbar` function expects an argument named `libfoo`, it is 126 automatically passed as an argument. Overrides or missing 127 arguments can be supplied in `args`, e.g. 128 129 ```nix 130 libbar = callPackage ./bar.nix { 131 libfoo = null; 132 enableX11 = true; 133 }; 134 ``` 135 136 <!-- TODO: Apply "Example:" tag to the examples above --> 137 138 Type: 139 callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 140 */ 141 callPackageWith = autoArgs: fn: args: 142 let 143 f = if lib.isFunction fn then fn else import fn; 144 fargs = lib.functionArgs f; 145 146 # All arguments that will be passed to the function 147 # This includes automatic ones and ones passed explicitly 148 allArgs = builtins.intersectAttrs fargs autoArgs // args; 149 150 # a list of argument names that the function requires, but 151 # wouldn't be passed to it 152 missingArgs = lib.attrNames 153 # Filter out arguments that have a default value 154 (lib.filterAttrs (name: value: ! value) 155 # Filter out arguments that would be passed 156 (removeAttrs fargs (lib.attrNames allArgs))); 157 158 # Get a list of suggested argument names for a given missing one 159 getSuggestions = arg: lib.pipe (autoArgs // args) [ 160 lib.attrNames 161 # Only use ones that are at most 2 edits away. While mork would work, 162 # levenshteinAtMost is only fast for 2 or less. 163 (lib.filter (lib.strings.levenshteinAtMost 2 arg)) 164 # Put strings with shorter distance first 165 (lib.sort (x: y: lib.strings.levenshtein x arg < lib.strings.levenshtein y arg)) 166 # Only take the first couple results 167 (lib.take 3) 168 # Quote all entries 169 (map (x: "\"" + x + "\"")) 170 ]; 171 172 prettySuggestions = suggestions: 173 if suggestions == [] then "" 174 else if lib.length suggestions == 1 then ", did you mean ${lib.elemAt suggestions 0}?" 175 else ", did you mean ${lib.concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?"; 176 177 errorForArg = arg: 178 let 179 loc = builtins.unsafeGetAttrPos arg fargs; 180 # loc' can be removed once lib/minver.nix is >2.3.4, since that includes 181 # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null 182 loc' = if loc != null then loc.file + ":" + toString loc.line 183 else if ! lib.isFunction fn then 184 toString fn + lib.optionalString (lib.sources.pathIsDirectory fn) "/default.nix" 185 else "<unknown location>"; 186 in "Function called without required argument \"${arg}\" at " 187 + "${loc'}${prettySuggestions (getSuggestions arg)}"; 188 189 # Only show the error for the first missing argument 190 error = errorForArg (lib.head missingArgs); 191 192 in if missingArgs == [] then makeOverridable f allArgs else abort error; 193 194 195 /* Like callPackage, but for a function that returns an attribute 196 set of derivations. The override function is added to the 197 individual attributes. 198 199 Type: 200 callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet 201 */ 202 callPackagesWith = autoArgs: fn: args: 203 let 204 f = if lib.isFunction fn then fn else import fn; 205 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs; 206 origArgs = auto // args; 207 pkgs = f origArgs; 208 mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs; 209 in 210 if lib.isDerivation pkgs then throw 211 ("function `callPackages` was called on a *single* derivation " 212 + ''"${pkgs.name or "<unknown-name>"}";'' 213 + " did you mean to use `callPackage` instead?") 214 else lib.mapAttrs mkAttrOverridable pkgs; 215 216 217 /* Add attributes to each output of a derivation without changing 218 the derivation itself and check a given condition when evaluating. 219 220 Type: 221 extendDerivation :: Bool -> Any -> Derivation -> Derivation 222 */ 223 extendDerivation = condition: passthru: drv: 224 let 225 outputs = drv.outputs or [ "out" ]; 226 227 commonAttrs = drv // (builtins.listToAttrs outputsList) // 228 ({ all = map (x: x.value) outputsList; }) // passthru; 229 230 outputToAttrListElement = outputName: 231 { name = outputName; 232 value = commonAttrs // { 233 inherit (drv.${outputName}) type outputName; 234 outputSpecified = true; 235 drvPath = assert condition; drv.${outputName}.drvPath; 236 outPath = assert condition; drv.${outputName}.outPath; 237 } // 238 # TODO: give the derivation control over the outputs. 239 # `overrideAttrs` may not be the only attribute that needs 240 # updating when switching outputs. 241 lib.optionalAttrs (passthru?overrideAttrs) { 242 # TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing. 243 overrideAttrs = f: (passthru.overrideAttrs f).${outputName}; 244 }; 245 }; 246 247 outputsList = map outputToAttrListElement outputs; 248 in commonAttrs // { 249 drvPath = assert condition; drv.drvPath; 250 outPath = assert condition; drv.outPath; 251 }; 252 253 /* Strip a derivation of all non-essential attributes, returning 254 only those needed by hydra-eval-jobs. Also strictly evaluate the 255 result to ensure that there are no thunks kept alive to prevent 256 garbage collection. 257 258 Type: 259 hydraJob :: (Derivation | Null) -> (Derivation | Null) 260 */ 261 hydraJob = drv: 262 let 263 outputs = drv.outputs or ["out"]; 264 265 commonAttrs = 266 { inherit (drv) name system meta; inherit outputs; } 267 // lib.optionalAttrs (drv._hydraAggregate or false) { 268 _hydraAggregate = true; 269 constituents = map hydraJob (lib.flatten drv.constituents); 270 } 271 // (lib.listToAttrs outputsList); 272 273 makeOutput = outputName: 274 let output = drv.${outputName}; in 275 { name = outputName; 276 value = commonAttrs // { 277 outPath = output.outPath; 278 drvPath = output.drvPath; 279 type = "derivation"; 280 inherit outputName; 281 }; 282 }; 283 284 outputsList = map makeOutput outputs; 285 286 drv' = (lib.head outputsList).value; 287 in if drv == null then null else 288 lib.deepSeq drv' drv'; 289 290 /* Make a set of packages with a common scope. All packages called 291 with the provided `callPackage` will be evaluated with the same 292 arguments. Any package in the set may depend on any other. The 293 `overrideScope'` function allows subsequent modification of the package 294 set in a consistent way, i.e. all packages in the set will be 295 called with the overridden packages. The package sets may be 296 hierarchical: the packages in the set are called with the scope 297 provided by `newScope` and the set provides a `newScope` attribute 298 which can form the parent scope for later package sets. 299 300 Type: 301 makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> AttrSet 302 */ 303 makeScope = newScope: f: 304 let self = f self // { 305 newScope = scope: newScope (self // scope); 306 callPackage = self.newScope {}; 307 overrideScope = g: makeScope newScope (lib.fixedPoints.extends g f); 308 # Remove after 24.11 is released. 309 overrideScope' = g: lib.warnIf (lib.isInOldestRelease 2311) 310 "`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`." 311 (makeScope newScope (lib.fixedPoints.extends g f)); 312 packages = f; 313 }; 314 in self; 315 316 /* backward compatibility with old uncurried form; deprecated */ 317 makeScopeWithSplicing = 318 splicePackages: newScope: otherSplices: keep: extra: f: 319 makeScopeWithSplicing' 320 { inherit splicePackages newScope; } 321 { inherit otherSplices keep extra f; }; 322 323 /* Like makeScope, but aims to support cross compilation. It's still ugly, but 324 hopefully it helps a little bit. 325 326 Type: 327 makeScopeWithSplicing' :: 328 { splicePackages :: Splice -> AttrSet 329 , newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a 330 } 331 -> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet } 332 -> AttrSet 333 334 Splice :: 335 { pkgsBuildBuild :: AttrSet 336 , pkgsBuildHost :: AttrSet 337 , pkgsBuildTarget :: AttrSet 338 , pkgsHostHost :: AttrSet 339 , pkgsHostTarget :: AttrSet 340 , pkgsTargetTarget :: AttrSet 341 } 342 */ 343 makeScopeWithSplicing' = 344 { splicePackages 345 , newScope 346 }: 347 { otherSplices 348 # Attrs from `self` which won't be spliced. 349 # Avoid using keep, it's only used for a python hook workaround, added in PR #104201. 350 # ex: `keep = (self: { inherit (self) aAttr; })` 351 , keep ? (_self: {}) 352 # Additional attrs to add to the sets `callPackage`. 353 # When the package is from a subset (but not a subset within a package IS #211340) 354 # within `spliced0` it will be spliced. 355 # When using an package outside the set but it's available from `pkgs`, use the package from `pkgs.__splicedPackages`. 356 # 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 357 # ex: 358 # ``` 359 # nix-repl> darwin.apple_sdk.frameworks.CoreFoundation 360 # «derivation ...CoreFoundation-11.0.0.drv» 361 # nix-repl> darwin.CoreFoundation 362 # error: attribute 'CoreFoundation' missing 363 # nix-repl> darwin.callPackage ({ CoreFoundation }: CoreFoundation) { } 364 # «derivation ...CoreFoundation-11.0.0.drv» 365 # ``` 366 , extra ? (_spliced0: {}) 367 , f 368 }: 369 let 370 spliced0 = splicePackages { 371 pkgsBuildBuild = otherSplices.selfBuildBuild; 372 pkgsBuildHost = otherSplices.selfBuildHost; 373 pkgsBuildTarget = otherSplices.selfBuildTarget; 374 pkgsHostHost = otherSplices.selfHostHost; 375 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`; 376 pkgsTargetTarget = otherSplices.selfTargetTarget; 377 }; 378 spliced = extra spliced0 // spliced0 // keep self; 379 self = f self // { 380 newScope = scope: newScope (spliced // scope); 381 callPackage = newScope spliced; # == self.newScope {}; 382 # N.B. the other stages of the package set spliced in are *not* 383 # overridden. 384 overrideScope = g: (makeScopeWithSplicing' 385 { inherit splicePackages newScope; } 386 { inherit otherSplices keep extra; 387 f = lib.fixedPoints.extends g f; 388 }); 389 packages = f; 390 }; 391 in self; 392 393}