srcOnly: differentiate between computed and passed `drvAttrs` via `overrideAttrs` (#425937)

Changed files
+122 -42
pkgs
build-support
+37 -20
pkgs/build-support/src-only/default.nix
···
attrs:
let
-
args = attrs.drvAttrs or attrs;
-
name = args.name or "${args.pname}-${args.version}";
-
stdenv = args.stdenv or (lib.warn "srcOnly: stdenv not provided, using stdenvNoCC" stdenvNoCC);
-
drv = stdenv.mkDerivation (
-
args
-
// {
-
name = "${name}-source";
+
argsToOverride = args: {
+
name = "${args.name or "${args.pname}-${args.version}"}-source";
-
outputs = [ "out" ];
+
outputs = [ "out" ];
-
phases = [
-
"unpackPhase"
-
"patchPhase"
-
"installPhase"
-
];
-
separateDebugInfo = false;
+
phases = [
+
"unpackPhase"
+
"patchPhase"
+
"installPhase"
+
];
+
separateDebugInfo = false;
-
dontUnpack = false;
+
dontUnpack = lib.warnIf (args.dontUnpack or false
+
) "srcOnly: derivation has dontUnpack set, overriding" false;
-
dontInstall = false;
-
installPhase = "cp -pr --reflink=auto -- . $out";
-
}
-
);
+
dontInstall = false;
+
installPhase = "cp -pr --reflink=auto -- . $out";
+
};
in
-
lib.warnIf (args.dontUnpack or false) "srcOnly: derivation has dontUnpack set, overriding" drv
+
+
# If we are passed a derivation (based on stdenv*), we can use overrideAttrs to
+
# update the arguments to mkDerivation. This gives us the proper awareness of
+
# what arguments were effectively passed *to* mkDerivation as opposed to
+
# builtins.derivation (by mkDerivation). For example, stdenv.mkDerivation
+
# accepts an `env` attribute set which is postprocessed before being passed to
+
# builtins.derivation. This can lead to evaluation failures, if we assume
+
# that drvAttrs is equivalent to the arguments passed to mkDerivation.
+
# See https://github.com/NixOS/nixpkgs/issues/269539.
+
if lib.isDerivation attrs && attrs ? overrideAttrs then
+
attrs.overrideAttrs (_finalAttrs: prevAttrs: argsToOverride prevAttrs)
+
else
+
let
+
# TODO(@sternenseemann): remove drvAttrs special casing
+
# If we don't have overrideAttrs, it is extremely unlikely that we are seeing
+
# a derivation constructed by stdenv.mkDerivation. Since srcOnly assumes
+
# that we are using stdenv's setup.sh, it therefore doesn't make sense to
+
# have derivation specific logic in this branch.
+
args = attrs.drvAttrs or attrs;
+
stdenv = args.stdenv or (lib.warn "srcOnly: stdenv not provided, using stdenvNoCC" stdenvNoCC);
+
drv = stdenv.mkDerivation (args // argsToOverride args);
+
in
+
drv
+85 -22
pkgs/build-support/src-only/tests.nix
···
hello,
emptyDirectory,
zlib,
+
git,
+
withCFlags,
stdenv,
testers,
}:
let
+
# Extract (effective) arguments passed to stdenv.mkDerivation and compute the
+
# arguments we would need to pass to srcOnly manually in order to get the same
+
# as `srcOnly drv`, i.e. the arguments passed to stdenv.mkDerivation plus the
+
# used stdenv itself.
+
getEquivAttrs =
+
drv:
+
let
+
drv' = drv.overrideAttrs (
+
_finalAttrs: prevAttrs: {
+
passthru = prevAttrs.passthru or { } // {
+
passedAttrs = prevAttrs;
+
};
+
}
+
);
+
in
+
drv'.passedAttrs // { inherit (drv') stdenv; };
+
+
canEvalDrv = drv: (builtins.tryEval drv.drvPath).success;
+
emptySrc = srcOnly emptyDirectory;
zlibSrc = srcOnly zlib;
# It can be invoked in a number of ways. Let's make sure they're equivalent.
-
zlibSrcDrvAttrs = srcOnly zlib.drvAttrs;
+
zlibSrcEquiv = srcOnly (getEquivAttrs zlib);
# zlibSrcFreeform = # ???;
helloSrc = srcOnly hello;
-
helloSrcDrvAttrs = srcOnly hello.drvAttrs;
+
helloSrcEquiv = srcOnly (getEquivAttrs hello);
+
+
gitSrc = srcOnly git;
+
gitSrcEquiv = srcOnly (getEquivAttrs git);
# The srcOnly <drv> invocation leaks a lot of attrs into the srcOnly derivation,
# so for comparing with the freeform invocation, we need to make a selection.
···
;
};
helloDrvSimpleSrc = srcOnly helloDrvSimple;
-
helloDrvSimpleSrcFreeform = srcOnly (
-
{
-
inherit (helloDrvSimple)
-
name
-
pname
-
version
-
src
-
patches
-
stdenv
-
;
-
}
-
# __impureHostDeps get duplicated in helloDrvSimpleSrc (on darwin)
-
# This is harmless, but fails the test for what is arguably an
-
# unrelated non-problem, so we just work around it here.
-
# The inclusion of __impureHostDeps really shouldn't be required,
-
# and should be removed from this test.
-
// lib.optionalAttrs (helloDrvSimple ? __impureHostDeps) {
-
inherit (helloDrvSimple) __impureHostDeps;
+
helloDrvSimpleSrcFreeform = srcOnly ({
+
inherit (helloDrvSimple)
+
name
+
pname
+
version
+
src
+
patches
+
stdenv
+
;
+
});
+
+
# Test the issue reported in https://github.com/NixOS/nixpkgs/issues/269539
+
stdenvAdapterDrv =
+
let
+
drv = (withCFlags [ "-Werror" "-Wall" ] stdenv).mkDerivation {
+
name = "drv-using-stdenv-adapter";
+
};
+
in
+
# Confirm the issue we are trying to avoid exists
+
assert !(canEvalDrv (srcOnly drv.drvAttrs));
+
drv;
+
stdenvAdapterDrvSrc = srcOnly stdenvAdapterDrv;
+
stdenvAdapterDrvSrcEquiv = srcOnly (
+
getEquivAttrs stdenvAdapterDrv
+
// {
+
# The upside of using overrideAttrs is that any stdenv adapter related
+
# modifications are only applied once. Using the adapter here again would
+
# mean applying it twice in total (since withCFlags functions more or less
+
# like an automatic overrideAttrs).
+
inherit stdenv;
}
);
+
# Issue similar to https://github.com/NixOS/nixpkgs/issues/269539
+
structuredAttrsDrv =
+
let
+
drv = stdenv.mkDerivation {
+
name = "drv-using-structured-attrs";
+
src = emptyDirectory;
+
+
env.NIX_DEBUG = true;
+
__structuredAttrs = true;
+
};
+
in
+
# Confirm the issue we are trying to avoid exists
+
assert !(canEvalDrv (srcOnly drv.drvAttrs));
+
drv;
+
structuredAttrsDrvSrc = srcOnly structuredAttrsDrv;
+
structuredAttrsDrvSrcEquiv = srcOnly (getEquivAttrs structuredAttrsDrv);
+
in
runCommand "srcOnly-tests"
{
moreTests = [
-
(testers.testEqualDerivation "zlibSrcDrvAttrs == zlibSrc" zlibSrcDrvAttrs zlibSrc)
+
(testers.testEqualDerivation "zlibSrcEquiv == zlibSrc" zlibSrcEquiv zlibSrc)
# (testers.testEqualDerivation
# "zlibSrcFreeform == zlibSrc"
# zlibSrcFreeform
# zlibSrc)
-
(testers.testEqualDerivation "helloSrcDrvAttrs == helloSrc" helloSrcDrvAttrs helloSrc)
+
(testers.testEqualDerivation "helloSrcEquiv == helloSrc" helloSrcEquiv helloSrc)
+
(testers.testEqualDerivation "helloSrcEquiv == helloSrc" helloSrcEquiv helloSrc)
+
(testers.testEqualDerivation "gitSrcEquiv == gitSrc" gitSrcEquiv gitSrc)
(testers.testEqualDerivation "helloDrvSimpleSrcFreeform == helloDrvSimpleSrc"
helloDrvSimpleSrcFreeform
helloDrvSimpleSrc
+
)
+
(testers.testEqualDerivation "stdenvAdapterDrvSrcEquiv == stdenvAdapterDrvSrc"
+
stdenvAdapterDrvSrcEquiv
+
stdenvAdapterDrvSrc
+
)
+
(testers.testEqualDerivation "structuredAttrsDrvSrcEquiv == structuredAttrsDrvSrc"
+
structuredAttrsDrvSrcEquiv
+
structuredAttrsDrvSrc
)
];
}