Skip to content

Commit

Permalink
WIP: add mkPackageWithDeps
Browse files Browse the repository at this point in the history
This shows the `deps` pattern, merging the following into a
single fixpoint, from NixOS#273815

 - package function args (`this.deps`)
 - mkDerivation args (`this.setup`)
 - derivation args (`this.drvAttrs`)
 - package attributes (`this.public`)
  • Loading branch information
roberth committed Mar 17, 2024
1 parent d8ac889 commit 548835c
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 42 deletions.
13 changes: 12 additions & 1 deletion lib/customisation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,18 @@ rec {
overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
in
if isAttrs result then
result // {
result
# Overriding `overrideDerivation` and `overrideAttrs` is a hack:
# `callPackage` shouldn't have to be aware of those functions and then
# fix them up, but it has to because the package arguments aren't part of
# the package fixpoint in `mkDerivation`.
#
# If the original package defines its own `override` method, but not
# `overrideDerivation`, we can assume it's a callPackage-aware `mkPackage`
# call.
# Otherwise, it is a legacy package, for which we still need to perform
# the hacky fixup.
// optionalAttrs (! (result ? override) || (result ? overrideDerivation)) {
override = overrideArgs;
overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
Expand Down
147 changes: 147 additions & 0 deletions pkgs/build-support/package/make-package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
{ lib, callPackage, stdenv, config, ... }:
let
checkMeta = import ../../stdenv/generic/check-meta.nix {
inherit lib config;
# Nix itself uses the `system` field of a derivation to decide where
# to build it. This is a bit confusing for cross compilation.
inherit (stdenv) hostPlatform;
};

baseLayer = this: {
pos = builtins.unsafeGetAttrPos "name" this;
# TODO: drvAttrs won't be available in RFC 92 dynamic derivations or multi-derivation packages.
validity = checkMeta.assertValidity { inherit (this.public) meta; attrs = this.drvAttrs // { inherit (this) meta; }; };

# In the repl, use :p pkg.help
# Since https://github.com/NixOS/nix/pull/10208
help = if this.deps == {} then ''
# Overriding dependencies
This package does not have overridable dependencies using the .override attribute.
'' else ''
# Overriding dependencies
This package allows its dependencies to be overridden, using the .override
attribute. For example:
pkg.override (old: { dep = f old.dep; })
Instead of dep, you may set the following attributes:
${lib.concatMapStringsSep ", " lib.strings.escapeNixIdentifier (lib.attrNames this.deps)}
'';

deps = {};

public = builtins.intersectAttrs {
tests = null;
version = null;
} this // {
/*
The marker for a [package attribute set](https://nixos.org/manual/nix/stable/glossary.html#package-attribute-set).
The value is "derivation" for historical reasons.
*/
type = "derivation";

# FIXME: this assumes this.drvAttrs, which is a bad dependency on the
# derivation layer
meta = checkMeta.commonMeta {
inherit (this) validity pos;
attrs = this.drvAttrs // { inherit (this) meta; };
references = this.drvAttrs.nativeBuildInputs or []
++ this.drvAttrs.buildInputs or []
++ this.drvAttrs.propagatedNativeBuildInputs or []
++ this.drvAttrs.propagatedBuildInputs or [];
};

inherit (this) help name;

override = f: this.extend (this: old: {
deps = old.deps // f old.deps;
});

overrideAttrs = f:
this.extend (this: old:
let
r = f (old.setup or {});
r' =
if lib.isFunction r
then
# f = finalAttrs: prevAttrs: ...
f
(this.setup or {} // {
finalPackage = this.public;
})
old.setup or {}
else r;
in
{
setup = old.setup // r';
}
);
};
};

layers.derivation = { stdenv, ... }: this: old:
let
outputs = lib.genAttrs (this.drvAttrs.outputs) (outputName:
this.public // {
outPath = assert this.validity.handled; this.drvOutAttrs.${outputName};
inherit outputName;
outputSpecified = true;
}
);
in
{
drvAttrs = stdenv.makeDerivationArgument (
(if this ? version then {
pname = this.name;
inherit (this) version;
}
else {
inherit (this) name;
}) // this.setup
);
drvOutAttrs = builtins.derivationStrict this.drvAttrs;
public =
old.public
// rec {
outPath = assert this.validity.handled; this.drvOutAttrs.${outputName};
outputName = lib.head this.drvAttrs.outputs;
# legacy attribute for single-drv packages
drvPath = assert this.validity.handled; this.drvOutAttrs.drvPath;
}
// outputs;
};

layers.withDeps = f: this: old:
let
spy = lib.setFunctionArgs (args: { inherit args; }) (lib.functionArgs f);
# TODO: make callPackage a parameter?
values = (callPackage spy { }).args;
old2 = old // {
deps = old.deps or {} // values;
};
r = f (lib.mapAttrs (name: value: this.deps.${name}) values);
r' = if lib.isList r then lib.composeManyExtensions r else r;
in
old2 //
r' this old2;
# lib.composeExtensions f ({ })

# TODO: layers.meson
# TODO: layers.cmake
# TODO: layers.pkg-config
# TODO: layers.<some language>

mkPackage = f: lib.encapsulate (lib.extends f baseLayer);
mkPackageWithDeps = f: mkPackage (layers.withDeps f);
in
{
inherit
layers
mkPackage
mkPackageWithDeps
;
}
77 changes: 36 additions & 41 deletions pkgs/by-name/he/hello/package.nix
Original file line number Diff line number Diff line change
@@ -1,46 +1,41 @@
{ callPackage
, lib
, stdenv
, fetchurl
, nixos
, testers
, hello
}:
{ mkPackageWithDeps, layers }: mkPackageWithDeps ({ stdenv, fetchurl, testers, lib, callPackage, nixos }: [
(layers.derivation { inherit stdenv; })
(this: old: {
name = "hello";
version = "2.12.1";

stdenv.mkDerivation (finalAttrs: {
pname = "hello";
version = "2.12.1";
setup = old.setup or {} // {
src = fetchurl {
url = "mirror://gnu/hello/hello-${this.version}.tar.gz";
sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
};
doCheck = true;
};

src = fetchurl {
url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
};
tests = {
version = testers.testVersion { package = this.public; };

doCheck = true;
invariant-under-noXlibs =
testers.testEqualDerivation
"hello must not be rebuilt when environment.noXlibs is set."
this.public
(nixos { environment.noXlibs = true; }).pkgs.hello;

passthru.tests = {
version = testers.testVersion { package = hello; };
run = callPackage ./test.nix { hello = this.public; };
};

invariant-under-noXlibs =
testers.testEqualDerivation
"hello must not be rebuilt when environment.noXlibs is set."
hello
(nixos { environment.noXlibs = true; }).pkgs.hello;
};

passthru.tests.run = callPackage ./test.nix { hello = finalAttrs.finalPackage; };

meta = with lib; {
description = "A program that produces a familiar, friendly greeting";
longDescription = ''
GNU Hello is a program that prints "Hello, world!" when you run it.
It is fully customizable.
'';
homepage = "https://www.gnu.org/software/hello/manual/";
changelog = "https://git.savannah.gnu.org/cgit/hello.git/plain/NEWS?h=v${finalAttrs.version}";
license = licenses.gpl3Plus;
maintainers = [ maintainers.eelco ];
mainProgram = "hello";
platforms = platforms.all;
};
})
meta = with lib; {
description = "A program that produces a familiar, friendly greeting";
longDescription = ''
GNU Hello is a program that prints "Hello, world!" when you run it.
It is fully customizable.
'';
homepage = "https://www.gnu.org/software/hello/manual/";
changelog = "https://git.savannah.gnu.org/cgit/hello.git/plain/NEWS?h=v${this.version}";
license = licenses.gpl3Plus;
maintainers = [ maintainers.eelco ];
mainProgram = "hello";
platforms = platforms.all;
};
})
])
5 changes: 5 additions & 0 deletions pkgs/stdenv/generic/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ argsStdenv@{ name ? "stdenv", preHook ? "", initialPath
, # The implementation of `mkDerivation`, parameterized with the final stdenv so we can tie the knot.
# This is convient to have as a parameter so the stdenv "adapters" work better
mkDerivationFromStdenv ? stdenv: (import ./make-derivation.nix { inherit lib config; } stdenv).mkDerivation

, # TODO: unify with the above
makeDerivationArgumentFromStdenv ? stdenv: (import ./make-derivation.nix { inherit lib config; } stdenv).makeDerivationArgument
}:

let
Expand Down Expand Up @@ -158,6 +161,8 @@ let

mkDerivation = mkDerivationFromStdenv stdenv;

makeDerivationArgument = makeDerivationArgumentFromStdenv stdenv;

inherit fetchurlBoot;

inherit overrides;
Expand Down
1 change: 1 addition & 0 deletions pkgs/stdenv/generic/make-derivation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -630,4 +630,5 @@ extendDerivation
in
{
inherit mkDerivation;
inherit makeDerivationArgument;
}
6 changes: 6 additions & 0 deletions pkgs/top-level/all-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ with pkgs;
import ./pkg-config/defaultPkgConfigPackages.nix pkgs
) // { __attrsFailEvaluation = true; };

inherit (import ../build-support/package/make-package.nix { inherit callPackage config lib stdenv; })
layers
mkPackage
mkPackageWithDeps
;

### Nixpkgs maintainer tools

nix-generate-from-cpan = callPackage ../../maintainers/scripts/nix-generate-from-cpan.nix { };
Expand Down

0 comments on commit 548835c

Please sign in to comment.