From 05f9db601abd582be51f096affbb97eff49f2ccb Mon Sep 17 00:00:00 2001 From: Will Fancher Date: Thu, 13 Jul 2017 18:54:04 -0400 Subject: [PATCH] Added `self` views of the interface in `makeExtensibleWithInterface` Fixing the `overrideScope` in `haskellpackages`. --- lib/customisation.nix | 51 +++++++++----------- lib/fixed-points.nix | 43 +++++++++++------ pkgs/development/haskell-modules/default.nix | 2 +- pkgs/top-level/haskell-packages.nix | 40 +++++++-------- pkgs/top-level/splice.nix | 4 +- 5 files changed, 76 insertions(+), 64 deletions(-) diff --git a/lib/customisation.nix b/lib/customisation.nix index 425c45233543..91aed8b9ca8b 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -50,28 +50,22 @@ rec { } else { })); - # Like `makeOverridable`, except a `self` argument is passed to `f`, - # which represents the fixed point result, even after using `extend` - # or `override`. - # - # Also, an `interface` function is taken as an argument, paralleling - # the `interface` argument to `makeExtensibleWithInterface`. This Is - # mostly useful for adding new `override` style functions, - # e.g. `overrideScope`. + # A more powerful version of `makeOverridable` with features similar + # to `makeExtensibleWithInterface`. makeOverridableWithInterface = interface: f: origArgs: let addOverrideFuncs = {val, args, ...}: overridePackage: (lib.optionalAttrs (builtins.isAttrs val) (val // { - extend = f: overridePackage (self: super: { + extend = f: overridePackage (_: self: super: { val = super.val // f self.val super.val; }); - overrideDerivation = newArgs: overridePackage (self: super: { + overrideDerivation = newArgs: overridePackage (_: self: super: { val = lib.overrideDerivation super.val newArgs; }); ${if val ? overrideAttrs then "overrideAttrs" else null} = fdrv: - overridePackage (self: super: { + overridePackage (_: self: super: { val = super.val.overrideAttrs fdrv; }); })) // (lib.optionalAttrs (builtins.isFunction val) { @@ -81,15 +75,15 @@ rec { }) // { inherit overridePackage; - override = newArgs: overridePackage (self: super: { + override = newArgs: overridePackage (_: self: super: { args = super.args // (if builtins.isFunction newArgs then newArgs super.args else newArgs); }); }; - in lib.makeExtensibleWithInterface (x: o: interface (addOverrideFuncs x o) o) (self: { + in lib.makeExtensibleWithInterface (x: o: interface (addOverrideFuncs x o) o) (output: self: { args = origArgs; - val = f self.args self.val; + val = f output self.args self.val; }); @@ -145,35 +139,37 @@ rec { it exposes a deeper structure. It provides `self` and `super` views of both the arguments and return value of the function, allowing you to change both in one override; you can even have - overrides for one based on overrides for the other. The type of - `self`, `super`, and the return value are all: - `{ args :: argumentsToF, val :: returnValueOfF }` + overrides for one based on overrides for the other. It also + provides the `output` view, which is the view of `self` after + passing it through the `makeOverridable` interface and adding all + the `overrideX` functions. `output` is necessary when your + overrides depend on the overridable structure of `output`. nix-repl> obj = makeOverridable ({a, b}: {inherit a b;}) {a = 1; b = 3;} - nix-repl> obj = obj.overridePackage (self: super: { args = super.args // {b = self.val.a;}; }) + nix-repl> obj = obj.overridePackage (output: self: super: { args = super.args // {b = self.val.a;}; }) nix-repl> obj.b 1 - nix-repl> obj = obj.overridePackage (self: super: { val = super.val // {a = self.args.a + 10;}; }) + nix-repl> obj = obj.overridePackage (output: self: super: { val = super.val // {a = self.args.a + 10;}; }) nix-repl> obj.b 11 */ - makeOverridable = fn: makeOverridableWithInterface (x: _: x) (args: _: fn args); + makeOverridable = fn: makeOverridableWithInterface (x: _: x) (_: args: _: fn args); callPackageCommon = functionArgs: scope: f: args: let intersect = builtins.intersectAttrs functionArgs; interface = val: overridePackage: val // { - overrideScope = newScope: overridePackage (self: super: { + overrideScope = newScope: overridePackage (_: self: super: { scope = super.scope.extend newScope; }); }; in (makeOverridableWithInterface interface f (intersect scope // args)) - .overridePackage (self: super: { + .overridePackage (output: self: super: { inherit scope; # Don't use super.args because that contains the original scope. args = intersect self.scope // args; @@ -219,15 +215,16 @@ rec { */ callPackageWith = autoArgs: fn: args: let f = if builtins.isFunction fn then fn else import fn; - in callPackageCommon (builtins.functionArgs f) autoArgs (x: _: f x) args; + in callPackageCommon (builtins.functionArgs f) autoArgs (output: x: _: f x) args; - # Like `callPackageWith`, but provides the function with the `self` - # argument. `fn` is called with the new `self` whenever an override + # Like `callPackageWith`, but provides the function with a `self` + # view of the output, which has the override functions + # injected. `fn` is called with the new output whenever an override # or extension is added. - callPackageWithSelfWith = autoArgs: fn: args: + callPackageWithOutputWith = autoArgs: fn: args: let f = if builtins.isFunction fn then fn else import fn; - in callPackageCommon (builtins.functionArgs f) autoArgs f args; + in callPackageCommon (builtins.functionArgs f) autoArgs (output: args: _: f args output ) args; /* Like callPackage, but for a function that returns an attribute diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 5039a45cc3f1..910dd24b202e 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -71,19 +71,34 @@ rec { # Same as `makeExtensible` but the name of the extending attribute is # customized. - makeExtensibleWithCustomName = extenderName: makeExtensibleWithInterface - (fixedPoint: extend: fixedPoint // { ${extenderName} = extend; }); + makeExtensibleWithCustomName = extenderName: f: makeExtensibleWithInterface + (fixedPoint: extend: fixedPoint // { ${extenderName} = ext: extend (_: ext); }) + (_: f); - # Similar to `makeExtensible`, but expects you to implement the - # final interface for the result. Specifically, it takes an extra - # argument: a function that takes the final result and the `extend` - # function as arguments, and returns a transformed result - # (preferably one that contains the `extend` function). This is - # mainly useful for getting to choose what to name the `extend` - # function in the resulting attribute set. But it's also useful for - # having an internal structure that extensions can see, but the user - # facing code cannot. - makeExtensibleWithInterface = interface: fext: interface - (fix' fext) - (f: makeExtensibleWithInterface interface (extends f fext)); + # A version of `makeExtensible` that allows the function being fixed + # to return a different interface than the interface returned to the + # user. Along with `self` and `super` views of the internal + # interface, a `self` view of the output interface is also + # provided. `extend` is not added to the output by default. This is + # the job of the interface. + # + # nix-repl> foo = {a, b}: {c = a + b;} + # + # nix-repl> interface = {args, val, ...}: extend: val // {inherit extend;} + # + # nix-repl> obj = makeExtensibleWithInterface interface (output: self: { args = {a = 1; b = 2;}; val = foo self.args; }) + # + # nix-repl> obj.c + # 3 + # + # nix-repl> obj = obj.extend (output: self: super: { args = super.args // { b = output.d; }; }) + # + # nix-repl> obj = obj.extend (output: self: super: { val = super.val // { d = 10; }; }) + # + # nix-repl> { inherit (obj) c d; } + # { c = 11; d = 10; } + makeExtensibleWithInterface = interface: f: let i = interface + (fix' (f i)) + (fext: makeExtensibleWithInterface interface (i': (extends (fext i') (f i')))); + in i; } diff --git a/pkgs/development/haskell-modules/default.nix b/pkgs/development/haskell-modules/default.nix index d68b10b386ee..9a67adf57aca 100644 --- a/pkgs/development/haskell-modules/default.nix +++ b/pkgs/development/haskell-modules/default.nix @@ -7,7 +7,7 @@ , configurationNix ? import ./configuration-nix.nix }: -self: # Provided by `callPackageWithSelf` +self: # Provided by `callPackageWithOutput` let diff --git a/pkgs/top-level/haskell-packages.nix b/pkgs/top-level/haskell-packages.nix index 36ae1979ba0b..dde5aa522786 100644 --- a/pkgs/top-level/haskell-packages.nix +++ b/pkgs/top-level/haskell-packages.nix @@ -1,4 +1,4 @@ -{ pkgs, callPackage, callPackageWithSelf, stdenv, buildPlatform, targetPlatform }: +{ pkgs, callPackage, callPackageWithOutput, stdenv, buildPlatform, targetPlatform }: let # These are attributes in compiler and packages that don't support integer-simple. integerSimpleExcludes = [ @@ -118,79 +118,79 @@ in rec { packages = { # Support for this compiler is broken, because it can't deal with directory-based package databases. - # ghc6104 = callPackageWithSelf ../development/haskell-modules { ghc = compiler.ghc6104; }; - ghc6123 = callPackageWithSelf ../development/haskell-modules { + # ghc6104 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc6104; }; + ghc6123 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc6123; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-6.12.x.nix { }; }; - ghc704 = callPackageWithSelf ../development/haskell-modules { + ghc704 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc704; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.0.x.nix { }; }; - ghc722 = callPackageWithSelf ../development/haskell-modules { + ghc722 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc722; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.2.x.nix { }; }; - ghc742 = callPackageWithSelf ../development/haskell-modules { + ghc742 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc742; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.4.x.nix { }; }; - ghc763 = callPackageWithSelf ../development/haskell-modules { + ghc763 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc763; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.6.x.nix { }; }; - ghc783 = callPackageWithSelf ../development/haskell-modules { + ghc783 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc783; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.8.x.nix { }; }; - ghc784 = callPackageWithSelf ../development/haskell-modules { + ghc784 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc784; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.8.x.nix { }; }; - ghc7102 = callPackageWithSelf ../development/haskell-modules { + ghc7102 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc7102; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.10.x.nix { }; }; - ghc7103 = callPackageWithSelf ../development/haskell-modules { + ghc7103 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc7103; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.10.x.nix { }; }; - ghc801 = callPackageWithSelf ../development/haskell-modules { + ghc801 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc801; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-8.0.x.nix { }; }; - ghc802 = callPackageWithSelf ../development/haskell-modules { + ghc802 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc802; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-8.0.x.nix { }; }; - ghc821 = callPackageWithSelf ../development/haskell-modules { + ghc821 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc821; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-8.2.x.nix { }; }; - ghcHEAD = callPackageWithSelf ../development/haskell-modules { + ghcHEAD = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghcHEAD; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-head.nix { }; }; # TODO Support for multiple variants here - ghcCross = callPackageWithSelf ../development/haskell-modules { + ghcCross = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghcHEAD.crossCompiler; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-head.nix { }; }; - ghcCross821 = callPackageWithSelf ../development/haskell-modules { + ghcCross821 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghc821.crossCompiler; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-8.2.x.nix { }; }; - ghcjs = callPackageWithSelf ../development/haskell-modules { + ghcjs = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghcjs; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-7.10.x.nix { }; packageSetConfig = callPackage ../development/haskell-modules/configuration-ghcjs.nix { }; }; - ghcjsHEAD = callPackageWithSelf ../development/haskell-modules { + ghcjsHEAD = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghcjsHEAD; compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-8.0.x.nix { }; packageSetConfig = callPackage ../development/haskell-modules/configuration-ghcjs.nix { }; }; - ghcHaLVM240 = callPackageWithSelf ../development/haskell-modules { + ghcHaLVM240 = callPackageWithOutput ../development/haskell-modules { ghc = compiler.ghcHaLVM240; compilerConfig = callPackage ../development/haskell-modules/configuration-halvm-2.4.0.nix { }; }; diff --git a/pkgs/top-level/splice.nix b/pkgs/top-level/splice.nix index 329a83e5a319..36596ec5961b 100644 --- a/pkgs/top-level/splice.nix +++ b/pkgs/top-level/splice.nix @@ -79,11 +79,11 @@ in # `newScope' for sets of packages in `pkgs' (see e.g. `gnome' below). callPackage = pkgs.newScope {}; - callPackageWithSelf = pkgs.newScopeWithSelf {}; + callPackageWithOutput = pkgs.newScopeWithOutput {}; callPackages = lib.callPackagesWith splicedPackages; newScope = extra: lib.callPackageWith (splicedPackages // extra); - newScopeWithSelf = extra: lib.callPackageWithSelfWith (splicedPackages // extra); + newScopeWithOutput = extra: lib.callPackageWithOutputWith (splicedPackages // extra); }