at 22.05-pre 9.7 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, 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 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs; 121 in makeOverridable f (auto // args); 122 123 124 /* Like callPackage, but for a function that returns an attribute 125 set of derivations. The override function is added to the 126 individual attributes. */ 127 callPackagesWith = autoArgs: fn: args: 128 let 129 f = if lib.isFunction fn then fn else import fn; 130 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs; 131 origArgs = auto // args; 132 pkgs = f origArgs; 133 mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs; 134 in 135 if lib.isDerivation pkgs then throw 136 ("function `callPackages` was called on a *single* derivation " 137 + ''"${pkgs.name or "<unknown-name>"}";'' 138 + " did you mean to use `callPackage` instead?") 139 else lib.mapAttrs mkAttrOverridable pkgs; 140 141 142 /* Add attributes to each output of a derivation without changing 143 the derivation itself and check a given condition when evaluating. */ 144 extendDerivation = condition: passthru: drv: 145 let 146 outputs = drv.outputs or [ "out" ]; 147 148 commonAttrs = drv // (builtins.listToAttrs outputsList) // 149 ({ all = map (x: x.value) outputsList; }) // passthru; 150 151 outputToAttrListElement = outputName: 152 { name = outputName; 153 value = commonAttrs // { 154 inherit (drv.${outputName}) type outputName; 155 outputSpecified = true; 156 drvPath = assert condition; drv.${outputName}.drvPath; 157 outPath = assert condition; drv.${outputName}.outPath; 158 }; 159 }; 160 161 outputsList = map outputToAttrListElement outputs; 162 in commonAttrs // { 163 drvPath = assert condition; drv.drvPath; 164 outPath = assert condition; drv.outPath; 165 }; 166 167 /* Strip a derivation of all non-essential attributes, returning 168 only those needed by hydra-eval-jobs. Also strictly evaluate the 169 result to ensure that there are no thunks kept alive to prevent 170 garbage collection. */ 171 hydraJob = drv: 172 let 173 outputs = drv.outputs or ["out"]; 174 175 commonAttrs = 176 { inherit (drv) name system meta; inherit outputs; } 177 // lib.optionalAttrs (drv._hydraAggregate or false) { 178 _hydraAggregate = true; 179 constituents = map hydraJob (lib.flatten drv.constituents); 180 } 181 // (lib.listToAttrs outputsList); 182 183 makeOutput = outputName: 184 let output = drv.${outputName}; in 185 { name = outputName; 186 value = commonAttrs // { 187 outPath = output.outPath; 188 drvPath = output.drvPath; 189 type = "derivation"; 190 inherit outputName; 191 }; 192 }; 193 194 outputsList = map makeOutput outputs; 195 196 drv' = (lib.head outputsList).value; 197 in lib.deepSeq drv' drv'; 198 199 /* Make a set of packages with a common scope. All packages called 200 with the provided `callPackage' will be evaluated with the same 201 arguments. Any package in the set may depend on any other. The 202 `overrideScope'` function allows subsequent modification of the package 203 set in a consistent way, i.e. all packages in the set will be 204 called with the overridden packages. The package sets may be 205 hierarchical: the packages in the set are called with the scope 206 provided by `newScope' and the set provides a `newScope' attribute 207 which can form the parent scope for later package sets. */ 208 makeScope = newScope: f: 209 let self = f self // { 210 newScope = scope: newScope (self // scope); 211 callPackage = self.newScope {}; 212 overrideScope = g: lib.warn 213 "`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." 214 (makeScope newScope (lib.fixedPoints.extends (lib.flip g) f)); 215 overrideScope' = g: makeScope newScope (lib.fixedPoints.extends g f); 216 packages = f; 217 }; 218 in self; 219 220 /* Like the above, but aims to support cross compilation. It's still ugly, but 221 hopefully it helps a little bit. */ 222 makeScopeWithSplicing = splicePackages: newScope: otherSplices: keep: extra: f: 223 let 224 spliced0 = splicePackages { 225 pkgsBuildBuild = otherSplices.selfBuildBuild; 226 pkgsBuildHost = otherSplices.selfBuildHost; 227 pkgsBuildTarget = otherSplices.selfBuildTarget; 228 pkgsHostHost = otherSplices.selfHostHost; 229 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`; 230 pkgsTargetTarget = otherSplices.selfTargetTarget; 231 }; 232 spliced = extra spliced0 // spliced0 // keep self; 233 self = f self // { 234 newScope = scope: newScope (spliced // scope); 235 callPackage = newScope spliced; # == self.newScope {}; 236 # N.B. the other stages of the package set spliced in are *not* 237 # overridden. 238 overrideScope = g: makeScopeWithSplicing 239 splicePackages 240 newScope 241 otherSplices 242 keep 243 extra 244 (lib.fixedPoints.extends g f); 245 packages = f; 246 }; 247 in self; 248 249}