diff --git a/pkgs/build-support/package/make-package.nix b/pkgs/build-support/package/make-package.nix index 80d6e42f7a5f73..15758a7002b04b 100644 --- a/pkgs/build-support/package/make-package.nix +++ b/pkgs/build-support/package/make-package.nix @@ -61,6 +61,8 @@ let deps = old.deps // f old.deps; }); + # FIXME: Use `toExtension f`? + # TODO: Support legacy attrs like passthru? overrideAttrs = f: this.extend (this: old: let @@ -115,7 +117,7 @@ let // outputs; }; - layers.withDeps = f: this: old: + layers.withDeps = f: externalArgs: this: old: let fargs = lib.functionArgs f; spy = lib.setFunctionArgs @@ -127,11 +129,25 @@ let true) fargs); # TODO: make callPackage a parameter? - values = (callPackage spy { }).args; + values = (callPackage spy externalArgs).args; old2 = old // { deps = old.deps or {} // values; + inherit values; }; - r = f (lib.mapAttrs (name: value: this.deps.${name}) fargs); + r = + f + (lib.mapAttrs + (name: hasDefault: + builtins.addErrorContext + "while evaluating the package function argument `${name}`" + (externalArgs.${name} or ( + this.deps.${name} or ( + throw "Dependency ${name} went missing from the package internal `deps` attribute. Did you forget to preserve previous deps? Write e.g. `deps = prev.deps // { ... }`" + ) + )) + ) + fargs + ); r' = if lib.isList r then lib.composeManyExtensions r else r; in old2 // @@ -143,13 +159,54 @@ let # TODO: layers.pkg-config # TODO: layers. - mkPackage = f: lib.encapsulate (lib.extends f baseLayer); - mkPackageWithDeps = f: mkPackage (layers.withDeps f); + layers.noop = _this: _old: { }; + + mkPackageWith = { + /* these are not overridable by the layer implementations - not suited for `deps` */ + externalDeps ? { inherit layers; } + }: f: lib.encapsulate ( + this: + let baseLayer' = x: baseLayer x // { + /** + Extend the package layers with the given function. + */ + extend = f: this.extend (this: old: { + userLayer = lib.composeExtensions old.userLayer f; + }); + }; + in + # The root of the mkPackage fixpoint is responsible for managing the deps, + # and combining the layers (without adding an extra fixpoint). + # Virtually all package logic happens in userLayer. + { + userLayer = final: prev: + this.externalDeps.layers.withDeps + f + (this.externalDeps // { + # Package attributes + inherit final prev; + # Dependencies + /** + Override the package dependencies that are not overridable by the individual layer implementations, + Notably, the `layers` attribute. + */ + overrideExternalDeps = newDeps: + this.extend (this: old: { + externalDeps = old.externalDeps // newDeps; + }); + }) + final + prev; + inherit externalDeps; + package = lib.extends this.userLayer baseLayer' this.package; + inherit (this.package) public; + } + ); + mkPackage = mkPackageWith {}; in { inherit layers mkPackage - mkPackageWithDeps ; } diff --git a/pkgs/by-name/he/hello/package.nix b/pkgs/by-name/he/hello/package.nix index 0cf0ae493b72ff..ed46895f03cea5 100644 --- a/pkgs/by-name/he/hello/package.nix +++ b/pkgs/by-name/he/hello/package.nix @@ -1,4 +1,4 @@ -{ mkPackageWithDeps, layers }: mkPackageWithDeps ({ stdenv, fetchurl, testers, lib, callPackage, nixos }: [ +{ mkPackage }: mkPackage ({ final, layers, stdenv, fetchurl, testers, nixos, callPackage, lib }: [ (layers.derivation { inherit stdenv; }) (this: old: { name = "hello";