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;