98860f429d
With multiple outputs, adding attributes to a derivation without changing the {drv,out}Path is no longer as trivial as simply using the `//' operator, as we usually want to add the attribute to _each_ output, and even if we only care about one that one output can be reached via multiple paths. For stdenv.mkDerivation, we already had code in place to add passthru and meta attributes to derivations. This commit simply factors part of that code out into a lib function addPassthru, which takes a derivation and an attribute set and appends the attribute set to each output of the derivation. Signed-off-by: Shea Levy <shea@shealevy.com>
120 lines
4.4 KiB
Nix
120 lines
4.4 KiB
Nix
let lib = import ./default.nix;
|
|
inherit (builtins) getAttr attrNames isFunction;
|
|
|
|
in
|
|
|
|
rec {
|
|
|
|
|
|
/* `overrideDerivation drv f' takes a derivation (i.e., the result
|
|
of a call to the builtin function `derivation') and returns a new
|
|
derivation in which the attributes of the original are overriden
|
|
according to the function `f'. The function `f' is called with
|
|
the original derivation attributes.
|
|
|
|
`overrideDerivation' allows certain "ad-hoc" customisation
|
|
scenarios (e.g. in ~/.nixpkgs/config.nix). For instance, if you
|
|
want to "patch" the derivation returned by a package function in
|
|
Nixpkgs to build another version than what the function itself
|
|
provides, you can do something like this:
|
|
|
|
mySed = overrideDerivation pkgs.gnused (oldAttrs: {
|
|
name = "sed-4.2.2-pre";
|
|
src = fetchurl {
|
|
url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
|
|
sha256 = "11nq06d131y4wmf3drm0yk502d2xc6n5qy82cg88rb9nqd2lj41k";
|
|
};
|
|
patches = [];
|
|
});
|
|
|
|
For another application, see build-support/vm, where this
|
|
function is used to build arbitrary derivations inside a QEMU
|
|
virtual machine. */
|
|
|
|
overrideDerivation = drv: f:
|
|
let
|
|
# Filter out special attributes.
|
|
drop = [ "meta" "passthru" "outPath" "drvPath" "crossDrv" "nativeDrv" "type" "override" "deepOverride" "origArgs" "drvAttrs" "outputName" "all" "out" ]
|
|
# also drop functions such as .merge .override etc
|
|
++ lib.filter (n: isFunction (getAttr n drv)) (attrNames drv);
|
|
attrs = removeAttrs drv drop;
|
|
newDrv = derivation (attrs // (f drv));
|
|
in newDrv //
|
|
{ meta = if drv ? meta then drv.meta else {};
|
|
passthru = if drv ? passthru then drv.passthru else {};
|
|
}
|
|
//
|
|
(if (drv ? crossDrv && drv ? nativeDrv)
|
|
then {
|
|
crossDrv = overrideDerivation drv.crossDrv f;
|
|
nativeDrv = overrideDerivation drv.nativeDrv f;
|
|
}
|
|
else { });
|
|
|
|
|
|
# usage: (you can use override multiple times)
|
|
# let d = makeOverridable stdenv.mkDerivation { name = ..; buildInputs; }
|
|
# noBuildInputs = d.override { buildInputs = []; }
|
|
# additionalBuildInputs = d.override ( args : args // { buildInputs = args.buildInputs ++ [ additional ]; } )
|
|
makeOverridable = f: origArgs:
|
|
let
|
|
ff = f origArgs;
|
|
in
|
|
if builtins.isAttrs ff then (ff //
|
|
{ override = newArgs:
|
|
makeOverridable f (origArgs // (if builtins.isFunction newArgs then newArgs origArgs else newArgs));
|
|
deepOverride = newArgs:
|
|
makeOverridable f (lib.overrideExisting (lib.mapAttrs (deepOverrider newArgs) origArgs) newArgs);
|
|
})
|
|
else ff;
|
|
|
|
deepOverrider = newArgs: name: x: if builtins.isAttrs x then (
|
|
if x ? deepOverride then (x.deepOverride newArgs) else
|
|
if x ? override then (x.override newArgs) else
|
|
x) else x;
|
|
|
|
|
|
/* Call the package function in the file `fn' with the required
|
|
arguments automatically. The function is called with the
|
|
arguments `args', but any missing arguments are obtained from
|
|
`autoArgs'. This function is intended to be partially
|
|
parameterised, e.g.,
|
|
|
|
callPackage = callPackageWith pkgs;
|
|
pkgs = {
|
|
libfoo = callPackage ./foo.nix { };
|
|
libbar = callPackage ./bar.nix { };
|
|
};
|
|
|
|
If the `libbar' function expects an argument named `libfoo', it is
|
|
automatically passed as an argument. Overrides or missing
|
|
arguments can be supplied in `args', e.g.
|
|
|
|
libbar = callPackage ./bar.nix {
|
|
libfoo = null;
|
|
enableX11 = true;
|
|
};
|
|
*/
|
|
callPackageWith = autoArgs: fn: args:
|
|
let f = if builtins.isFunction fn then fn else import fn; in
|
|
makeOverridable f ((builtins.intersectAttrs (builtins.functionArgs f) autoArgs) // args);
|
|
|
|
/* Add attributes to each output of a derivation without changing the derivation itself */
|
|
addPassthru = drv: passthru:
|
|
let
|
|
outputs = drv.outputs or [ "out" ];
|
|
|
|
commonAttrs = drv // (builtins.listToAttrs outputsList) //
|
|
({ all = map (x: x.value) outputsList; }) // passthru;
|
|
|
|
outputToAttrListElement = outputName:
|
|
{ name = outputName;
|
|
value = commonAttrs // {
|
|
inherit (builtins.getAttr outputName drv) outPath drvPath type outputName;
|
|
};
|
|
};
|
|
|
|
outputsList = map outputToAttrListElement outputs;
|
|
in builtins.getAttr drv.outputName commonAttrs;
|
|
}
|