Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
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, you can do something like this: 17 18 mySed = overrideDerivation pkgs.gnused (oldAttrs: { 19 name = "sed-4.2.2-pre"; 20 src = fetchurl { 21 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2; 22 sha256 = "11nq06d131y4wmf3drm0yk502d2xc6n5qy82cg88rb9nqd2lj41k"; 23 }; 24 patches = []; 25 }); 26 27 For another application, see build-support/vm, where this 28 function is used to build arbitrary derivations inside a QEMU 29 virtual machine. 30 */ 31 overrideDerivation = drv: f: 32 let 33 newDrv = derivation (drv.drvAttrs // (f drv)); 34 in lib.flip (extendDerivation true) newDrv ( 35 { meta = drv.meta or {}; 36 passthru = if drv ? passthru then drv.passthru else {}; 37 } 38 // 39 (drv.passthru or {}) 40 // 41 (if (drv ? crossDrv && drv ? nativeDrv) 42 then { 43 crossDrv = overrideDerivation drv.crossDrv f; 44 nativeDrv = overrideDerivation drv.nativeDrv f; 45 } 46 else { })); 47 48 49 /* `makeOverridable` takes a function from attribute set to attribute set and 50 injects `override` attribute which can be used to override arguments of 51 the function. 52 53 nix-repl> x = {a, b}: { result = a + b; } 54 55 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; } 56 57 nix-repl> y 58 { override = «lambda»; overrideDerivation = «lambda»; result = 3; } 59 60 nix-repl> y.override { a = 10; } 61 { override = «lambda»; overrideDerivation = «lambda»; result = 12; } 62 63 Please refer to "Nixpkgs Contributors Guide" section 64 "<pkg>.overrideDerivation" to learn about `overrideDerivation` and caveats 65 related to its use. 66 */ 67 makeOverridable = f: origArgs: 68 let 69 result = f origArgs; 70 71 # Creates a functor with the same arguments as f 72 copyArgs = g: lib.setFunctionArgs g (lib.functionArgs f); 73 # Changes the original arguments with (potentially a function that returns) a set of new attributes 74 overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs); 75 76 # Re-call the function but with different arguments 77 overrideArgs = copyArgs (newArgs: makeOverridable f (overrideWith newArgs)); 78 # Change the result of the function call by applying g to it 79 overrideResult = g: makeOverridable (copyArgs (args: g (f args))) origArgs; 80 in 81 if builtins.isAttrs result then 82 result // { 83 override = overrideArgs; 84 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv); 85 ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv: 86 overrideResult (x: x.overrideAttrs fdrv); 87 } 88 else if lib.isFunction result then 89 # Transform the result into a functor while propagating its arguments 90 lib.setFunctionArgs result (lib.functionArgs result) // { 91 override = overrideArgs; 92 } 93 else result; 94 95 96 /* Call the package function in the file `fn' with the required 97 arguments automatically. The function is called with the 98 arguments `args', but any missing arguments are obtained from 99 `autoArgs'. This function is intended to be partially 100 parameterised, e.g., 101 102 callPackage = callPackageWith pkgs; 103 pkgs = { 104 libfoo = callPackage ./foo.nix { }; 105 libbar = callPackage ./bar.nix { }; 106 }; 107 108 If the `libbar' function expects an argument named `libfoo', it is 109 automatically passed as an argument. Overrides or missing 110 arguments can be supplied in `args', e.g. 111 112 libbar = callPackage ./bar.nix { 113 libfoo = null; 114 enableX11 = true; 115 }; 116 */ 117 callPackageWith = autoArgs: fn: args: 118 let 119 f = if lib.isFunction fn then fn else import fn; 120 fargs = lib.functionArgs f; 121 122 # All arguments that will be passed to the function 123 # This includes automatic ones and ones passed explicitly 124 allArgs = builtins.intersectAttrs fargs autoArgs // args; 125 126 # A list of argument names that the function requires, but 127 # wouldn't be passed to it 128 missingArgs = lib.attrNames 129 # Filter out arguments that have a default value 130 (lib.filterAttrs (name: value: ! value) 131 # Filter out arguments that would be passed 132 (removeAttrs fargs (lib.attrNames allArgs))); 133 134 # Get a list of suggested argument names for a given missing one 135 getSuggestions = arg: lib.pipe (autoArgs // args) [ 136 lib.attrNames 137 # Only use ones that are at most 2 edits away. While mork would work, 138 # levenshteinAtMost is only fast for 2 or less. 139 (lib.filter (lib.strings.levenshteinAtMost 2 arg)) 140 # Put strings with shorter distance first 141 (lib.sort (x: y: lib.strings.levenshtein x arg < lib.strings.levenshtein y arg)) 142 # Only take the first couple results 143 (lib.take 3) 144 # Quote all entries 145 (map (x: "\"" + x + "\"")) 146 ]; 147 148 prettySuggestions = suggestions: 149 if suggestions == [] then "" 150 else if lib.length suggestions == 1 then ", did you mean ${lib.elemAt suggestions 0}?" 151 else ", did you mean ${lib.concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?"; 152 153 errorForArg = arg: 154 let 155 loc = builtins.unsafeGetAttrPos arg fargs; 156 # loc' can be removed once lib/minver.nix is >2.3.4, since that includes 157 # https://github.com/NixOS/nix/pull/3468 which makes loc be non-null 158 loc' = if loc != null then loc.file + ":" + toString loc.line 159 else if ! lib.isFunction fn then 160 toString fn + lib.optionalString (lib.sources.pathIsDirectory fn) "/default.nix" 161 else "<unknown location>"; 162 in "Function called without required argument \"${arg}\" at " 163 + "${loc'}${prettySuggestions (getSuggestions arg)}"; 164 165 # Only show the error for the first missing argument 166 error = errorForArg (lib.head missingArgs); 167 168 in if missingArgs == [] then makeOverridable f allArgs else throw error; 169 170 171 /* Like callPackage, but for a function that returns an attribute 172 set of derivations. The override function is added to the 173 individual attributes. */ 174 callPackagesWith = autoArgs: fn: args: 175 let 176 f = if lib.isFunction fn then fn else import fn; 177 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs; 178 origArgs = auto // args; 179 pkgs = f origArgs; 180 mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs; 181 in 182 if lib.isDerivation pkgs then throw 183 ("function `callPackages` was called on a *single* derivation " 184 + ''"${pkgs.name or "<unknown-name>"}";'' 185 + " did you mean to use `callPackage` instead?") 186 else lib.mapAttrs mkAttrOverridable pkgs; 187 188 189 /* Add attributes to each output of a derivation without changing 190 the derivation itself and check a given condition when evaluating. */ 191 extendDerivation = condition: passthru: drv: 192 let 193 outputs = drv.outputs or [ "out" ]; 194 195 commonAttrs = drv // (builtins.listToAttrs outputsList) // 196 ({ all = map (x: x.value) outputsList; }) // passthru; 197 198 outputToAttrListElement = outputName: 199 { name = outputName; 200 value = commonAttrs // { 201 inherit (drv.${outputName}) type outputName; 202 outputSpecified = true; 203 drvPath = assert condition; drv.${outputName}.drvPath; 204 outPath = assert condition; drv.${outputName}.outPath; 205 }; 206 }; 207 208 outputsList = map outputToAttrListElement outputs; 209 in commonAttrs // { 210 drvPath = assert condition; drv.drvPath; 211 outPath = assert condition; drv.outPath; 212 }; 213 214 /* Strip a derivation of all non-essential attributes, returning 215 only those needed by hydra-eval-jobs. Also strictly evaluate the 216 result to ensure that there are no thunks kept alive to prevent 217 garbage collection. */ 218 hydraJob = drv: 219 let 220 outputs = drv.outputs or ["out"]; 221 222 commonAttrs = 223 { inherit (drv) name system meta; inherit outputs; } 224 // lib.optionalAttrs (drv._hydraAggregate or false) { 225 _hydraAggregate = true; 226 constituents = map hydraJob (lib.flatten drv.constituents); 227 } 228 // (lib.listToAttrs outputsList); 229 230 makeOutput = outputName: 231 let output = drv.${outputName}; in 232 { name = outputName; 233 value = commonAttrs // { 234 outPath = output.outPath; 235 drvPath = output.drvPath; 236 type = "derivation"; 237 inherit outputName; 238 }; 239 }; 240 241 outputsList = map makeOutput outputs; 242 243 drv' = (lib.head outputsList).value; 244 in lib.deepSeq drv' drv'; 245 246 /* Make a set of packages with a common scope. All packages called 247 with the provided `callPackage' will be evaluated with the same 248 arguments. Any package in the set may depend on any other. The 249 `overrideScope'` function allows subsequent modification of the package 250 set in a consistent way, i.e. all packages in the set will be 251 called with the overridden packages. The package sets may be 252 hierarchical: the packages in the set are called with the scope 253 provided by `newScope' and the set provides a `newScope' attribute 254 which can form the parent scope for later package sets. */ 255 makeScope = newScope: f: 256 let self = f self // { 257 newScope = scope: newScope (self // scope); 258 callPackage = self.newScope {}; 259 overrideScope = g: lib.warn 260 "`overrideScope` (from `lib.makeScope`) is deprecated. Do `overrideScope' (self: super: { })` instead of `overrideScope (super: self: { })`. All other overrides have the parameters in that order, including other definitions of `overrideScope`. This was the only definition violating the pattern." 261 (makeScope newScope (lib.fixedPoints.extends (lib.flip g) f)); 262 overrideScope' = g: makeScope newScope (lib.fixedPoints.extends g f); 263 packages = f; 264 }; 265 in self; 266 267 /* Like the above, but aims to support cross compilation. It's still ugly, but 268 hopefully it helps a little bit. */ 269 makeScopeWithSplicing = splicePackages: newScope: otherSplices: keep: extra: f: 270 let 271 spliced0 = splicePackages { 272 pkgsBuildBuild = otherSplices.selfBuildBuild; 273 pkgsBuildHost = otherSplices.selfBuildHost; 274 pkgsBuildTarget = otherSplices.selfBuildTarget; 275 pkgsHostHost = otherSplices.selfHostHost; 276 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`; 277 pkgsTargetTarget = otherSplices.selfTargetTarget; 278 }; 279 spliced = extra spliced0 // spliced0 // keep self; 280 self = f self // { 281 newScope = scope: newScope (spliced // scope); 282 callPackage = newScope spliced; # == self.newScope {}; 283 # N.B. the other stages of the package set spliced in are *not* 284 # overridden. 285 overrideScope = g: makeScopeWithSplicing 286 splicePackages 287 newScope 288 otherSplices 289 keep 290 extra 291 (lib.fixedPoints.extends g f); 292 packages = f; 293 }; 294 in self; 295 296}