diff --git a/doc/functions.xml b/doc/functions.xml
index 2a9cc44d5c5bb..f6c82b021c222 100644
--- a/doc/functions.xml
+++ b/doc/functions.xml
@@ -169,6 +169,71 @@
+
+ <pkg>.override
+
+
+ The function overrideWithScope is usually available for all the
+ derivations in the nixpkgs expression (pkgs).
+
+
+
+ It is used to override the arguments passed to a function, by extracting the
+ arguments from a larger set, similar to the default argument provided by the
+ callPackage function.
+
+
+
+ This function is useful to deeply override a package within a set of
+ packages, such as making compilation stages or to build packages which rely
+ on having the same interpreter (i-e: python, haskell, emacs, …).
+
+
+
+ Example usages:
+pkgs.foo.overrideWithScope pkgs.fooDependencies
+import pkgs.path { overlays = [
+ (self: super: {
+ # The interpreter would be overriden in the following packages too.
+ myInterpreterPackages = super.lib.mapAttrs (n: v: v.overrideWithScope self.myInterpreterPackages) {
+ interpreter = super.interpreter.overrideDerivation (prev: { ... });
+ inherit (super) foo bar baz qux;
+ };
+ })
+ (self: super: {
+ # baz changes would be visible by all packages within myInterpreterPackages set.
+ myInterpreterPackages = super.myInterpreterPackages // {
+ baz = super.myInterpreterPackages.baz.override { ... };
+ };
+ })
+ ]};
+
+
+
+ In the first example, pkgs.foo is the result of a
+ function call with some default arguments, usually a derivation. Using
+ pkgs.foo.overrideWithScope will call the same function
+ with the given new arguments. This is similar to how
+ pkgs.foo.override would behave, except that
+ overrideWithScope will not raise an error if an argument
+ is given, but not expected by the package.
+
+
+
+ In the second example, two overlays are added. The first overlay create a
+ custom version of an interpreter, and replaces it in all packages included
+ in the myInterpreterPackages set, as well as replacing
+ foo in myInterpreterPackages.bar. The
+ second overlay replaces baz in all packages under
+ myInterpreterPackages, such as
+ myInterpreterPackages.qux. Note, the second overlay did
+ not had a re-use overrideWithScope as the argument of it
+ in the first overlay is the fix-point result of
+ myInterpreterSet, which includes the custom
+ baz.
+
+
+
lib.makeOverridable
diff --git a/lib/customisation.nix b/lib/customisation.nix
index 480280428909d..781de3789c0f2 100644
--- a/lib/customisation.nix
+++ b/lib/customisation.nix
@@ -46,9 +46,10 @@ rec {
else { }));
- /* `makeOverridable` takes a function from attribute set to attribute set and
- injects `override` attibute which can be used to override arguments of
- the function.
+ /* `makeOverridable` takes a function from attribute set to attribute set, a
+ list of expected arguments and injects `override`, `overrideWithScope` and
+ `overrideDerivation` attibutes in the result of the function which can be
+ used to re-call the function with an overrided set of arguments.
nix-repl> x = {a, b}: { result = a + b; }
@@ -64,20 +65,25 @@ rec {
".overrideDerivation" to learn about `overrideDerivation` and caveats
related to its use.
*/
- makeOverridable = f: origArgs:
+ makeOverridable = f: origArgs: makeOverridableWithArgs f (lib.functionArgs f) origArgs;
+ makeOverridableWithArgs = f: fnArgs: origArgs:
let
ff = f origArgs;
overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
+ intersectArgs = if fnArgs != {} then builtins.intersectAttrs fnArgs else (a: a);
+ overrideWithScope = newScope: overrideWith (intersectArgs newScope);
in
if builtins.isAttrs ff then (ff // {
- override = newArgs: makeOverridable f (overrideWith newArgs);
+ override = newArgs: makeOverridableWithArgs f fnArgs (overrideWith newArgs);
+ overrideWithScope = newScope: makeOverridableWithArgs f fnArgs (overrideWithScope newScope);
overrideDerivation = fdrv:
- makeOverridable (args: overrideDerivation (f args) fdrv) origArgs;
+ makeOverridableWithArgs (args: overrideDerivation (f args) fdrv) fnArgs origArgs;
${if ff ? overrideAttrs then "overrideAttrs" else null} = fdrv:
- makeOverridable (args: (f args).overrideAttrs fdrv) origArgs;
+ makeOverridableWithArgs (args: (f args).overrideAttrs fdrv) fnArgs origArgs;
})
else if lib.isFunction ff then {
- override = newArgs: makeOverridable f (overrideWith newArgs);
+ override = newArgs: makeOverridableWithArgs f fnArgs (overrideWith newArgs);
+ overrideWithScope = newScope: makeOverridableWithArgs f fnArgs (overrideWithScope newScope);
__functor = self: ff;
overrideDerivation = throw "overrideDerivation not yet supported for functors";
}
@@ -108,8 +114,9 @@ rec {
callPackageWith = autoArgs: fn: args:
let
f = if lib.isFunction fn then fn else import fn;
- auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
- in makeOverridable f (auto // args);
+ fnArgs = lib.functionArgs f;
+ auto = builtins.intersectAttrs fnArgs autoArgs;
+ in makeOverridableWithArgs f fnArgs (auto // args);
/* Like callPackage, but for a function that returns an attribute
@@ -118,10 +125,11 @@ rec {
callPackagesWith = autoArgs: fn: args:
let
f = if lib.isFunction fn then fn else import fn;
- auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
+ fnArgs = lib.functionArgs f;
+ auto = builtins.intersectAttrs fnArgs autoArgs;
origArgs = auto // args;
pkgs = f origArgs;
- mkAttrOverridable = name: pkg: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
+ mkAttrOverridable = name: pkg: makeOverridableWithArgs (newArgs: (f newArgs).${name}) fnArgs origArgs;
in lib.mapAttrs mkAttrOverridable pkgs;