at 18.03-beta 7.5 kB view raw
1{ lib }: 2let 3 4 inherit (builtins) attrNames; 5 6in 7 8rec { 9 10 11 /* `overrideDerivation drv f' takes a derivation (i.e., the result 12 of a call to the builtin function `derivation') and returns a new 13 derivation in which the attributes of the original are overridden 14 according to the function `f'. The function `f' is called with 15 the original derivation attributes. 16 17 `overrideDerivation' allows certain "ad-hoc" customisation 18 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance, 19 if you want to "patch" the derivation returned by a package 20 function in Nixpkgs to build another version than what the 21 function itself provides, you can do something like this: 22 23 mySed = overrideDerivation pkgs.gnused (oldAttrs: { 24 name = "sed-4.2.2-pre"; 25 src = fetchurl { 26 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2; 27 sha256 = "11nq06d131y4wmf3drm0yk502d2xc6n5qy82cg88rb9nqd2lj41k"; 28 }; 29 patches = []; 30 }); 31 32 For another application, see build-support/vm, where this 33 function is used to build arbitrary derivations inside a QEMU 34 virtual machine. 35 */ 36 overrideDerivation = drv: f: 37 let 38 newDrv = derivation (drv.drvAttrs // (f drv)); 39 in lib.flip (extendDerivation true) newDrv ( 40 { meta = drv.meta or {}; 41 passthru = if drv ? passthru then drv.passthru else {}; 42 } 43 // 44 (drv.passthru or {}) 45 // 46 (if (drv ? crossDrv && drv ? nativeDrv) 47 then { 48 crossDrv = overrideDerivation drv.crossDrv f; 49 nativeDrv = overrideDerivation drv.nativeDrv f; 50 } 51 else { })); 52 53 54 /* `makeOverridable` takes a function from attribute set to attribute set and 55 injects `override` attibute which can be used to override arguments of 56 the function. 57 58 nix-repl> x = {a, b}: { result = a + b; } 59 60 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; } 61 62 nix-repl> y 63 { override = «lambda»; overrideDerivation = «lambda»; result = 3; } 64 65 nix-repl> y.override { a = 10; } 66 { override = «lambda»; overrideDerivation = «lambda»; result = 12; } 67 68 Please refer to "Nixpkgs Contributors Guide" section 69 "<pkg>.overrideDerivation" to learn about `overrideDerivation` and caveats 70 related to its use. 71 */ 72 makeOverridable = f: origArgs: 73 let 74 ff = f origArgs; 75 overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs); 76 in 77 if builtins.isAttrs ff then (ff // { 78 override = newArgs: makeOverridable f (overrideWith newArgs); 79 overrideDerivation = fdrv: 80 makeOverridable (args: overrideDerivation (f args) fdrv) origArgs; 81 ${if ff ? overrideAttrs then "overrideAttrs" else null} = fdrv: 82 makeOverridable (args: (f args).overrideAttrs fdrv) origArgs; 83 }) 84 else if lib.isFunction ff then { 85 override = newArgs: makeOverridable f (overrideWith newArgs); 86 __functor = self: ff; 87 overrideDerivation = throw "overrideDerivation not yet supported for functors"; 88 } 89 else ff; 90 91 92 /* Call the package function in the file `fn' with the required 93 arguments automatically. The function is called with the 94 arguments `args', but any missing arguments are obtained from 95 `autoArgs'. This function is intended to be partially 96 parameterised, e.g., 97 98 callPackage = callPackageWith pkgs; 99 pkgs = { 100 libfoo = callPackage ./foo.nix { }; 101 libbar = callPackage ./bar.nix { }; 102 }; 103 104 If the `libbar' function expects an argument named `libfoo', it is 105 automatically passed as an argument. Overrides or missing 106 arguments can be supplied in `args', e.g. 107 108 libbar = callPackage ./bar.nix { 109 libfoo = null; 110 enableX11 = true; 111 }; 112 */ 113 callPackageWith = autoArgs: fn: args: 114 let 115 f = if lib.isFunction fn then fn else import fn; 116 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs; 117 in makeOverridable f (auto // args); 118 119 120 /* Like callPackage, but for a function that returns an attribute 121 set of derivations. The override function is added to the 122 individual attributes. */ 123 callPackagesWith = autoArgs: fn: args: 124 let 125 f = if lib.isFunction fn then fn else import fn; 126 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs; 127 origArgs = auto // args; 128 pkgs = f origArgs; 129 mkAttrOverridable = name: pkg: makeOverridable (newArgs: (f newArgs).${name}) origArgs; 130 in lib.mapAttrs mkAttrOverridable pkgs; 131 132 133 /* Add attributes to each output of a derivation without changing 134 the derivation itself and check a given condition when evaluating. */ 135 extendDerivation = condition: passthru: drv: 136 let 137 outputs = drv.outputs or [ "out" ]; 138 139 commonAttrs = drv // (builtins.listToAttrs outputsList) // 140 ({ all = map (x: x.value) outputsList; }) // passthru; 141 142 outputToAttrListElement = outputName: 143 { name = outputName; 144 value = commonAttrs // { 145 inherit (drv.${outputName}) type outputName; 146 drvPath = assert condition; drv.${outputName}.drvPath; 147 outPath = assert condition; drv.${outputName}.outPath; 148 }; 149 }; 150 151 outputsList = map outputToAttrListElement outputs; 152 in commonAttrs // { 153 outputUnspecified = true; 154 drvPath = assert condition; drv.drvPath; 155 outPath = assert condition; drv.outPath; 156 }; 157 158 /* Strip a derivation of all non-essential attributes, returning 159 only those needed by hydra-eval-jobs. Also strictly evaluate the 160 result to ensure that there are no thunks kept alive to prevent 161 garbage collection. */ 162 hydraJob = drv: 163 let 164 outputs = drv.outputs or ["out"]; 165 166 commonAttrs = 167 { inherit (drv) name system meta; inherit outputs; } 168 // lib.optionalAttrs (drv._hydraAggregate or false) { 169 _hydraAggregate = true; 170 constituents = map hydraJob (lib.flatten drv.constituents); 171 } 172 // (lib.listToAttrs outputsList); 173 174 makeOutput = outputName: 175 let output = drv.${outputName}; in 176 { name = outputName; 177 value = commonAttrs // { 178 outPath = output.outPath; 179 drvPath = output.drvPath; 180 type = "derivation"; 181 inherit outputName; 182 }; 183 }; 184 185 outputsList = map makeOutput outputs; 186 187 drv' = (lib.head outputsList).value; 188 in lib.deepSeq drv' drv'; 189 190 /* Make a set of packages with a common scope. All packages called 191 with the provided `callPackage' will be evaluated with the same 192 arguments. Any package in the set may depend on any other. The 193 `overrideScope' function allows subsequent modification of the package 194 set in a consistent way, i.e. all packages in the set will be 195 called with the overridden packages. The package sets may be 196 hierarchical: the packages in the set are called with the scope 197 provided by `newScope' and the set provides a `newScope' attribute 198 which can form the parent scope for later package sets. */ 199 makeScope = newScope: f: 200 let self = f self // { 201 newScope = scope: newScope (self // scope); 202 callPackage = self.newScope {}; 203 overrideScope = g: 204 makeScope newScope 205 (self_: let super = f self_; in super // g super self_); 206 packages = f; 207 }; 208 in self; 209 210}