From e4cd45a30c92a19a240df835cdaf6da5f76ea9fc Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 12 Oct 2016 15:14:49 -0400 Subject: [PATCH] top-level: Make `overridePackages` extend rather than replace existing overrides --- doc/functions.xml | 14 +++++ lib/trivial.nix | 8 ++- pkgs/top-level/all-packages.nix | 14 ----- pkgs/top-level/default.nix | 105 +++++++++++++++++--------------- 4 files changed, 77 insertions(+), 64 deletions(-) diff --git a/doc/functions.xml b/doc/functions.xml index 908e9571ed6..e767d01d843 100644 --- a/doc/functions.xml +++ b/doc/functions.xml @@ -52,6 +52,20 @@ in ... It's equivalent to pkgs in the above example. + + Note that in previous versions of nixpkgs, this method replaced any changes from config.packageOverrides, + along with that from previous calls if this function was called repeatedly. + Now those previous changes will be preserved so this function can be "chained" meaningfully. + To recover the old behavior, make sure config.packageOverrides is unset, + and call this only once off a "freshly" imported nixpkgs: + + let + pkgs = import <nixpkgs> { config: {}; }; + newpkgs = pkgs.overridePackages ...; +in ... + +
diff --git a/lib/trivial.nix b/lib/trivial.nix index a0c31757ba7..acf1ccab879 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -69,9 +69,13 @@ rec { # # nix-repl> obj # { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } - makeExtensible = rattrs: + makeExtensible = makeExtensibleWithCustomName "extend"; + + # Same as `makeExtensible` but the name of the extending attribute is + # customized. + makeExtensibleWithCustomName = extenderName: rattrs: fix' rattrs // { - extend = f: makeExtensible (extends f rattrs); + ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); }; # Flip the order of the arguments of a binary function. diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e6e1b94a2a6..967876e926b 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -6,7 +6,6 @@ * Hint: ### starts category names. */ { system, bootStdenv, noSysDirs, config, crossSystem, platform, lib -, pkgsWithOverrides , ... }: self: pkgs: @@ -35,19 +34,6 @@ in newScope = extra: lib.callPackageWith (defaultScope // extra); - # Easily override this package set. - # Warning: this function is very expensive and must not be used - # from within the nixpkgs repository. - # - # Example: - # pkgs.overridePackages (self: super: { - # foo = super.foo.override { ... }; - # } - # - # The result is `pkgs' where all the derivations depending on `foo' - # will use the new version. - overridePackages = f: pkgsWithOverrides f; - # Override system. This is useful to build i686 packages on x86_64-linux. forceSystem = system: kernel: (import ../..) { inherit system; diff --git a/pkgs/top-level/default.nix b/pkgs/top-level/default.nix index 2eb7fb34b4d..d0dc231650c 100644 --- a/pkgs/top-level/default.nix +++ b/pkgs/top-level/default.nix @@ -61,6 +61,35 @@ let inherit system bootStdenv noSysDirs config crossSystem platform lib; }; + stdenvAdapters = self: super: + let res = import ../stdenv/adapters.nix self; in res // { + stdenvAdapters = res; + }; + + trivialBuilders = self: super: + (import ../build-support/trivial-builders.nix { + inherit lib; inherit (self) stdenv stdenvNoCC; inherit (self.xorg) lndir; + }); + + stdenvDefault = self: super: (import ./stdenv.nix topLevelArguments) {} pkgs; + + allPackages = self: super: + let res = import ./all-packages.nix topLevelArguments res self; + in res; + + aliases = self: super: import ./aliases.nix super; + + # stdenvOverrides is used to avoid circular dependencies for building + # the standard build environment. This mechanism uses the override + # mechanism to implement some staged compilation of the stdenv. + # + # We don't want stdenv overrides in the case of cross-building, or + # otherwise the basic overridden packages will not be built with the + # crossStdenv adapter. + stdenvOverrides = self: super: + lib.optionalAttrs (crossSystem == null && super.stdenv ? overrides) + (super.stdenv.overrides super); + # Allow packages to be overridden globally via the `packageOverrides' # configuration option, which must be a function that takes `pkgs' # as an argument and returns a set of new or overridden packages. @@ -68,54 +97,34 @@ let # (un-overridden) set of packages, allowing packageOverrides # attributes to refer to the original attributes (e.g. "foo = # ... pkgs.foo ..."). - pkgs = pkgsWithOverrides (self: config.packageOverrides or (super: {})); + configOverrides = self: super: + lib.optionalAttrs (bootStdenv == null) + ((config.packageOverrides or (super: {})) super); - # Return the complete set of packages, after applying the overrides - # returned by the `overrider' function (see above). Warning: this - # function is very expensive! - pkgsWithOverrides = overrider: - let - stdenvAdapters = self: super: - let res = import ../stdenv/adapters.nix self; in res // { - stdenvAdapters = res; - }; + # The complete chain of package set builders, applied from bottom to top + toFix = lib.fold lib.extends (self: {}) [ + configOverrides + stdenvOverrides + aliases + allPackages + stdenvDefault + trivialBuilders + stdenvAdapters + ]; - trivialBuilders = self: super: - (import ../build-support/trivial-builders.nix { - inherit lib; inherit (self) stdenv stdenvNoCC; inherit (self.xorg) lndir; - }); + # Use `overridePackages` to easily override this package set. + # Warning: this function is very expensive and must not be used + # from within the nixpkgs repository. + # + # Example: + # pkgs.overridePackages (self: super: { + # foo = super.foo.override { ... }; + # } + # + # The result is `pkgs' where all the derivations depending on `foo' + # will use the new version. - stdenvDefault = self: super: (import ./stdenv.nix topLevelArguments) {} pkgs; - - allPackagesArgs = topLevelArguments // { inherit pkgsWithOverrides; }; - allPackages = self: super: - let res = import ./all-packages.nix allPackagesArgs res self; - in res; - - aliases = self: super: import ./aliases.nix super; - - # stdenvOverrides is used to avoid circular dependencies for building - # the standard build environment. This mechanism uses the override - # mechanism to implement some staged compilation of the stdenv. - # - # We don't want stdenv overrides in the case of cross-building, or - # otherwise the basic overridden packages will not be built with the - # crossStdenv adapter. - stdenvOverrides = self: super: - lib.optionalAttrs (crossSystem == null && super.stdenv ? overrides) - (super.stdenv.overrides super); - - customOverrides = self: super: - lib.optionalAttrs (bootStdenv == null) (overrider self super); - in - lib.fix' ( - lib.extends customOverrides ( - lib.extends stdenvOverrides ( - lib.extends aliases ( - lib.extends allPackages ( - lib.extends stdenvDefault ( - lib.extends trivialBuilders ( - lib.extends stdenvAdapters ( - self: {})))))))); -in - pkgs + # Return the complete set of packages. Warning: this function is very + # expensive! + pkgs = lib.makeExtensibleWithCustomName "overridePackages" toFix; +in pkgs