diff --git a/lib/customisation.nix b/lib/customisation.nix index 68062dd0daf0a..daf92fe88f082 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -192,15 +192,13 @@ rec { provided by `newScope' and the set provides a `newScope' attribute which can form the parent scope for later package sets. */ makeScope = newScope: f: - let self = f self // { - newScope = scope: newScope (self // scope); - callPackage = self.newScope {}; - overrideScope = g: lib.warn - "`overrideScope` (from `lib.makeScope`) is deprecated. Do `overrideScope' (self: super: { … })` instead of `overrideScope (super: self: { … })`. All other overrides have the parameters in that order, including other definitions of `overrideScope`. This was the only definition violating the pattern." - (makeScope newScope (lib.fixedPoints.extends (lib.flip g) f)); - overrideScope' = g: makeScope newScope (lib.fixedPoints.extends g f); - packages = f; - }; - in self; - + lib.overrides.makeExtensibleAttrset (self: super: f self // { + newScope = scope: newScope (self // scope); + callPackage = self.newScope {}; + overrideScope = g: lib.warn + "`overrideScope` (from `lib.makeScope`) is deprecated. Do `overrideScope' (self: super: { … })` instead of `overrideScope (super: self: { … })`. All other overrides have the parameters in that order, including other definitions of `overrideScope`. This was the only definition violating the pattern." + (makeScope newScope (lib.overrides.extends (lib.flip g) f)); + overrideScope' = g: makeScope newScope (lib.overrides.extends g f); + packages = f; + }); } diff --git a/lib/default.nix b/lib/default.nix index d7a05fec8338e..ce419c29b0f3d 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -4,10 +4,11 @@ * for new functions in `./tests.nix'. */ let + bootstrapLib = mkLib bootstrapLib; - inherit (import ./fixed-points.nix {}) makeExtensible; + lib = bootstrapLib.makeExtensible mkLib; - lib = makeExtensible (self: let + mkLib = self: let callLibs = file: import file { lib = self; }; in with self; { @@ -20,6 +21,8 @@ let lists = callLibs ./lists.nix; strings = callLibs ./strings.nix; stringsWithDeps = callLibs ./strings-with-deps.nix; + monoid = callLibs ./monoid.nix; + overrides = callLibs ./overrides.nix; # packaging customisation = callLibs ./customisation.nix; @@ -61,8 +64,7 @@ let boolToString mergeAttrs flip mapNullable inNixShell min max importJSON warn info nixpkgsVersion version mod compare splitByAndCompare functionArgs setFunctionArgs isFunction; - inherit (fixedPoints) fix fix' extends composeExtensions - makeExtensible makeExtensibleWithCustomName; + inherit (fixedPoints) fix fix'; inherit (attrsets) attrByPath hasAttrByPath setAttrByPath getAttrFromPath attrVals attrValues catAttrs filterAttrs filterAttrsRecursive foldAttrs collect nameValuePair mapAttrs @@ -90,6 +92,7 @@ let toInt readPathsFromFile fileContents; inherit (stringsWithDeps) textClosureList textClosureMap noDepEntry fullDepEntry packEntry stringAfter; + inherit (overrides) extends composeExtensions makeExtensible; inherit (customisation) overrideDerivation makeOverridable callPackageWith callPackagesWith extendDerivation hydraJob makeScope; @@ -134,5 +137,5 @@ let mergeAttrsNoOverride mergeAttrByFunc mergeAttrsByFuncDefaults mergeAttrsByFuncDefaultsClean mergeAttrBy prepareDerivationArgs nixType imap overridableDelayableArgs; - }); + }; in lib diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 7169c46fcbbca..5225618d812b9 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -23,69 +23,4 @@ rec { # implement deep overriding. See pkgs/development/haskell-modules/default.nix # for a concrete example. fix' = f: let x = f x // { __unfix__ = f; }; in x; - - # Modify the contents of an explicitly recursive attribute set in a way that - # honors `self`-references. This is accomplished with a function - # - # g = self: super: { foo = super.foo + " + "; } - # - # that has access to the unmodified input (`super`) as well as the final - # non-recursive representation of the attribute set (`self`). `extends` - # differs from the native `//` operator insofar as that it's applied *before* - # references to `self` are resolved: - # - # nix-repl> fix (extends g f) - # { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } - # - # The name of the function is inspired by object-oriented inheritance, i.e. - # think of it as an infix operator `g extends f` that mimics the syntax from - # Java. It may seem counter-intuitive to have the "base class" as the second - # argument, but it's nice this way if several uses of `extends` are cascaded. - # - # To get a better understanding how `extends` turns a function with a fix - # point (the package set we start with) into a new function with a different fix - # point (the desired packages set) lets just see, how `extends g f` - # unfolds with `g` and `f` defined above: - # - # extends g f = self: let super = f self; in super // g self super; - # = self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super - # = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } - # = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; } - # = self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; } - # - extends = f: rattrs: self: let super = rattrs self; in super // f self super; - - # Compose two extending functions of the type expected by 'extends' - # into one where changes made in the first are available in the - # 'super' of the second - composeExtensions = - f: g: self: super: - let fApplied = f self super; - super' = super // fApplied; - in fApplied // g self super'; - - # Create an overridable, recursive attribute set. For example: - # - # nix-repl> obj = makeExtensible (self: { }) - # - # nix-repl> obj - # { __unfix__ = «lambda»; extend = «lambda»; } - # - # nix-repl> obj = obj.extend (self: super: { foo = "foo"; }) - # - # nix-repl> obj - # { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; } - # - # nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; }) - # - # nix-repl> obj - # { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } - makeExtensible = makeExtensibleWithCustomName "extend"; - - # Same as `makeExtensible` but the name of the extending attribute is - # customized. - makeExtensibleWithCustomName = extenderName: rattrs: - fix' rattrs // { - ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); - }; } diff --git a/lib/monoid.nix b/lib/monoid.nix new file mode 100644 index 0000000000000..d6965a4afb7e9 --- /dev/null +++ b/lib/monoid.nix @@ -0,0 +1,23 @@ +{ lib }: + +# TODO say what monoid is I suppose + +{ + + list = { + identity = []; + append = lib.trivial.concat; + }; + + attrset = { + identity = {}; + append = lib.trivial.mergeAttrs; + }; + + inherit (lib.overrides) monoidalExtension attrsetDeep extensibleAttrset; + + # Monoidally left-fold a list. The monoid's `append` and `identity` become the + # other arguments besides the list to the `foldl`. + fold = { identity, append, ... }: lib.foldl append identity; + +} diff --git a/lib/overrides.nix b/lib/overrides.nix new file mode 100644 index 0000000000000..41893e044690f --- /dev/null +++ b/lib/overrides.nix @@ -0,0 +1,107 @@ +{ lib }: + +# Overlays, overrides, and other mechanisms for extensiblilty. + +let brand = "extensible-attrset"; in + +rec { + # + monoidalExtension = { append, identity }: { + identity = _: _: identity; + append = f: g: self: super: + let fApplied = f self super; + super' = append super fApplied; + in append fApplied (g self super'); + }; + + # + fixMondoidalExtension = { append, identity }: + override: lib.fix (self: override self identity); + + # + extendMonoidal = { append, identity }: + f: rattrs: self: let super = rattrs self; in append super (f self super); + + # TODO need builtin to speed this up + mergeExtensibleRecursive = lib.zipAttrsWith (n: vs: + if builtins.length vs > 1 && lib.all (a: (a.type or "") == brand) vs + then lib.monoid.fold extensibleAttrset vs + else lib.last vs); + + # + attrsetDeep = { + identity = {}; + append = old: new: mergeExtensibleRecursive [old new]; + }; + + # + extensibleAttrset = { + identity = { __override__ = self: super: {}; }; + append = old: new: makeExtensibleAttrset + (composeExtensions old.__override__ new.__override__); + }; + + makeExtensibleAttrset = __override__: + fixMondoidalExtension attrsetDeep __override__ // { + type = brand; + inherit __override__; + }; + + # Modify the contents of an explicitly recursive attribute set in a way that + # honors `self`-references. This is accomplished with a function + # + # g = self: super: { foo = super.foo + " + "; } + # + # that has access to the unmodified input (`super`) as well as the final + # non-recursive representation of the attribute set (`self`). `extends` + # differs from the native `//` operator insofar as that it's applied *before* + # references to `self` are resolved: + # + # nix-repl> fix (extends g f) + # { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } + # + # The name of the function is inspired by object-oriented inheritance, i.e. + # think of it as an infix operator `g extends f` that mimics the syntax from + # Java. It may seem counter-intuitive to have the "base class" as the second + # argument, but it's nice this way if several uses of `extends` are cascaded. + # + # To get a better understanding how `extends` turns a function with a fix + # point (the package set we start with) into a new function with a different fix + # point (the desired packages set) lets just see, how `extends g f` + # unfolds with `g` and `f` defined above: + # + # extends g f = self: let super = f self; in super // g self super; + # = self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super + # = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } + # = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; } + # = self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; } + # + extends = extendMonoidal lib.monoid.attrsetDeep; + + # Compose two extending functions of the type expected by 'extends' + # into one where changes made in the first are available in the + # 'super' of the second + composeExtensions = (monoidalExtension lib.monoid.attrsetDeep).append; + + # Create an overridable, recursive attribute set. For example: + # + # nix-repl> obj = makeExtensible (self: { }) + # + # nix-repl> obj + # { __unfix__ = «lambda»; extend = «lambda»; } + # + # nix-repl> obj = obj.extend (self: super: { foo = "foo"; }) + # + # nix-repl> obj + # { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; } + # + # nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; }) + # + # nix-repl> obj + # { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } + makeExtensible = rattrs: + makeExtensibleAttrset (self: super: rattrs self) // { + __unfix__ = rattrs; + extend = f: makeExtensible (extends f rattrs); + }; +} diff --git a/pkgs/development/compilers/llvm/3.7/default.nix b/pkgs/development/compilers/llvm/3.7/default.nix index 3c557711449ff..bcee49d6f4b51 100644 --- a/pkgs/development/compilers/llvm/3.7/default.nix +++ b/pkgs/development/compilers/llvm/3.7/default.nix @@ -56,4 +56,4 @@ let libcxxabi = callPackage ./libc++abi.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/development/compilers/llvm/3.8/default.nix b/pkgs/development/compilers/llvm/3.8/default.nix index a848c8b9252b0..b5f4eaa380d2f 100644 --- a/pkgs/development/compilers/llvm/3.8/default.nix +++ b/pkgs/development/compilers/llvm/3.8/default.nix @@ -56,4 +56,4 @@ let libcxxabi = callPackage ./libc++abi.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/development/compilers/llvm/3.9/default.nix b/pkgs/development/compilers/llvm/3.9/default.nix index 752790cdd853c..df2f6e21bf916 100644 --- a/pkgs/development/compilers/llvm/3.9/default.nix +++ b/pkgs/development/compilers/llvm/3.9/default.nix @@ -56,4 +56,4 @@ let libcxxabi = callPackage ./libc++abi.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/development/compilers/llvm/4/default.nix b/pkgs/development/compilers/llvm/4/default.nix index 9651dbb72f4d7..4228a4d42b259 100644 --- a/pkgs/development/compilers/llvm/4/default.nix +++ b/pkgs/development/compilers/llvm/4/default.nix @@ -71,4 +71,4 @@ let openmp = callPackage ./openmp.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/development/compilers/llvm/5/default.nix b/pkgs/development/compilers/llvm/5/default.nix index 68ee80fa7a629..79d7924f7156f 100644 --- a/pkgs/development/compilers/llvm/5/default.nix +++ b/pkgs/development/compilers/llvm/5/default.nix @@ -89,4 +89,4 @@ let openmp = callPackage ./openmp.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/development/compilers/llvm/6/default.nix b/pkgs/development/compilers/llvm/6/default.nix index 5ee551f6b6b12..23073da975f95 100644 --- a/pkgs/development/compilers/llvm/6/default.nix +++ b/pkgs/development/compilers/llvm/6/default.nix @@ -89,4 +89,4 @@ let openmp = callPackage ./openmp.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/development/compilers/llvm/7/default.nix b/pkgs/development/compilers/llvm/7/default.nix index 5446f1b362a97..753fff27dd6d6 100644 --- a/pkgs/development/compilers/llvm/7/default.nix +++ b/pkgs/development/compilers/llvm/7/default.nix @@ -89,4 +89,4 @@ let openmp = callPackage ./openmp.nix {}; }); -in { inherit tools libraries; } // libraries // tools +in stdenv.lib.makeExtensible (_: _: { inherit tools libraries; } // tools // libraries) diff --git a/pkgs/stdenv/darwin/default.nix b/pkgs/stdenv/darwin/default.nix index 5fb410b64ebdc..f481a59b27abf 100644 --- a/pkgs/stdenv/darwin/default.nix +++ b/pkgs/stdenv/darwin/default.nix @@ -146,7 +146,7 @@ in rec { stage0 = stageFun 0 null { overrides = self: super: with stage0; rec { - darwin = super.darwin // { + darwin = lib.makeExtensibleAttrset (_: _: { Libsystem = stdenv.mkDerivation { name = "bootstrap-stage0-Libsystem"; buildCommand = '' @@ -156,9 +156,9 @@ in rec { ''; }; dyld = bootstrapTools; - }; + }); - llvmPackages_5 = { + llvmPackages_5 = lib.makeExtensibleAttrset (_: _: { libcxx = stdenv.mkDerivation { name = "bootstrap-stage0-libcxx"; phases = [ "installPhase" "fixupPhase" ]; @@ -178,7 +178,7 @@ in rec { ln -s ${bootstrapTools}/lib/libc++abi.dylib $out/lib/libc++abi.dylib ''; }; - }; + }); }; extraNativeBuildInputs = []; @@ -200,7 +200,9 @@ in rec { python2 = self.python; ninja = super.ninja.override { buildDocs = false; }; - darwin = super.darwin // { cctools = super.darwin.cctools.override { llvm = null; }; }; + darwin = lib.makeExtensibleAttrset (_: superDarwin: { + cctools = superDarwin.cctools.override { llvm = null; }; + }); }; in with prevStage; stageFun 1 prevStage { extraPreHook = "export NIX_CFLAGS_COMPILE+=\" -F${bootstrapTools}/Library/Frameworks\""; @@ -223,10 +225,10 @@ in rec { findfreetype libssh curl cmake autoconf automake libtool ed cpio coreutils libssh2 nghttp2 libkrb5 python2 ninja; - darwin = super.darwin // { + darwin = lib.makeExtensibleAttrset (_: _: { inherit (darwin) dyld Libsystem xnu configd ICU libdispatch libclosure launchd CF; - }; + }); }; in with prevStage; stageFun 2 prevStage { extraPreHook = '' @@ -260,16 +262,16 @@ in rec { # Avoid pulling in a full python and its extra dependencies for the llvm/clang builds. libxml2 = super.libxml2.override { pythonSupport = false; }; - llvmPackages_5 = super.llvmPackages_5 // (let - libraries = super.llvmPackages_5.libraries.extend (_: _: { + llvmPackages_5 = lib.makeExtensibleAttrset (_: _: { + libraries = { inherit (llvmPackages_5) libcxx libcxxabi; - }); - in { inherit libraries; } // libraries); + } + }); - darwin = super.darwin // { + darwin = lib.makeExtensibleAttrset (_: _: { inherit (darwin) dyld Libsystem xnu configd libdispatch libclosure launchd libiconv locale; - }; + }); }; in with prevStage; stageFun 3 prevStage { shell = "${pkgs.bash}/bin/bash"; @@ -314,24 +316,24 @@ in rec { ]; }); - llvmPackages_5 = super.llvmPackages_5 // (let - tools = super.llvmPackages_5.tools.extend (llvmSelf: _: { + llvmPackages_5 = let + tools = { inherit (llvmPackages_5) llvm clang-unwrapped; - }); - libraries = super.llvmPackages_5.libraries.extend (llvmSelf: _: { + }; + libraries = { inherit (llvmPackages_5) libcxx libcxxabi compiler-rt; - }); - in { inherit tools libraries; } // tools // libraries); + }; + in lib.makeExtensibleAttrset (_: _: { inherit tools libraries; } // tools // libraries); - darwin = super.darwin // rec { + darwin = lib.makeExtensibleAttrset (_: superDarwin: { inherit (darwin) dyld Libsystem libiconv locale; libxml2-nopython = super.libxml2.override { pythonSupport = false; }; - CF = super.darwin.CF.override { + CF = superDarwin.CF.override { libxml2 = libxml2-nopython; python = prevStage.python; }; - }; + }); }; in with prevStage; stageFun 4 prevStage { shell = "${pkgs.bash}/bin/bash"; @@ -353,14 +355,14 @@ in rec { ncurses libffi zlib llvm gmp pcre gnugrep coreutils findutils diffutils patchutils; - llvmPackages_5 = super.llvmPackages_5 // (let + llvmPackages_5 = let tools = super.llvmPackages_5.tools.extend (_: super: { inherit (llvmPackages_5) llvm clang-unwrapped; }); libraries = super.llvmPackages_5.libraries.extend (_: _: { inherit (llvmPackages_5) compiler-rt libcxx libcxxabi; }); - in { inherit tools libraries; } // tools // libraries); + in lib.makeExtensibleAttrset (_: _: { inherit tools libraries; } // tools // libraries); # N.B: the important thing here is to ensure that python == python2 # == python27 or you get weird issues with inconsistent package sets. @@ -373,7 +375,7 @@ in rec { # and I'm just leaving this blurb here so people realize why it matters python27 = super.python27.override { CF = prevStage.darwin.CF; }; - darwin = super.darwin // { + darwin = lib.makeExtensibleAttrset (_: _: { inherit (darwin) dyld ICU Libsystem libiconv; } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) { inherit (darwin) binutils binutils-unwrapped cctools; @@ -381,7 +383,7 @@ in rec { } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) { # Need to get rid of these when cross-compiling. inherit binutils binutils-unwrapped; - }; + }); in import ../generic rec { name = "stdenv-darwin"; @@ -437,8 +439,8 @@ in rec { llvmPackages = super.llvmPackages // { clang = cc; }; inherit cc; - darwin = super.darwin // { - xnu = super.darwin.xnu.override { python = super.python.override { configd = null; }; }; + darwin = lib.makeExtensibleAttrset (_: superDarwin: { + xnu = superDarwin.xnu.override { python = super.python.override { configd = null; }; }; }; }); }; diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix index 1d412a6582cda..62e0bdac34862 100644 --- a/pkgs/top-level/stage.nix +++ b/pkgs/top-level/stage.nix @@ -179,7 +179,7 @@ let # The complete chain of package set builders, applied from top to bottom. # stdenvOverlays must be last as it brings package forward from the # previous bootstrapping phases which have already been overlayed. - toFix = lib.foldl' (lib.flip lib.extends) (self: {}) ([ + toFix = map lib.overrides.makeExtensibleAttrset ([ stdenvBootstappingAndPlatforms platformCompat stdenvAdapters @@ -194,4 +194,4 @@ let in # Return the complete set of packages. - lib.fix toFix + lib.monoid.fold lib.monoid.extensibleAttrset toFix