1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00

WIP: Allow for null packages and formatters

This is useful for frameworks (such as flake-parts) to avoid unnecessary
evaluation. See discussion here:
https://github.com/hercules-ci/flake-parts/issues/288#issuecomment-2912459614

While digging into this, I discovered that `nix fmt` already handles
`null` formatters identically to undefined formatters. I added a couple
of tests to demonstrate this behavior.

`nix flake show` needs some reworking to avoid crashing with a "error:
expected a derivation" when it encounters a `null` formatter or package.
My changes here avoid the crash, but has some cosmetic issues, which is why
I've labeled this PR as a draft.

Cosmetic issues
===============

With the following `flake.nix`:

```nix
{
  outputs = _: {
    packages.x86_64-linux.default = null;
  };
}
```

`nix flake show` shows a weird empty system:

```
$ nix flake show
path:/tmp/tmp.uL0iGuNwXB?lastModified=1748472558&narHash=sha256-tC%2BhdXAyoeFvWHNllJbois8X%2B7wpZ6CJzEzbcaGQxtM%3D
└───packages
    └───x86_64-linux
```

Similarly, `nix flake show --json` includes an empty object:

```
$ nix flake show --json
{
  "packages": {
    "x86_64-linux": {
      "default": null
    }
  }
}
```

`nix build` crashes:

```
$ nix build .#default
error: expected flake output attribute 'packages.x86_64-linux.default' to be a derivation or path but found null: null
```
This commit is contained in:
Jeremy Fleischman 2025-05-28 15:55:41 -07:00
parent ba96067535
commit 929423476e
No known key found for this signature in database
6 changed files with 59 additions and 6 deletions

View file

@ -1,3 +1,4 @@
#include "nix/expr/value.hh"
#include "nix/util/users.hh" #include "nix/util/users.hh"
#include "nix/expr/eval-cache.hh" #include "nix/expr/eval-cache.hh"
#include "nix/store/sqlite.hh" #include "nix/store/sqlite.hh"
@ -762,6 +763,14 @@ std::vector<Symbol> AttrCursor::getAttrs()
return attrs; return attrs;
} }
bool AttrCursor::isNull()
{
// <<< TODO: caching? >>>
auto & v = forceValue();
return v.type() == nNull;
}
bool AttrCursor::isDerivation() bool AttrCursor::isDerivation()
{ {
auto aType = maybeGetAttr("type"); auto aType = maybeGetAttr("type");

View file

@ -153,6 +153,8 @@ public:
bool isDerivation(); bool isDerivation();
bool isNull();
Value & forceValue(); Value & forceValue();
/** /**

View file

@ -1340,10 +1340,14 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
} }
} else { } else {
try { try {
if (visitor.isDerivation()) if (visitor.isNull()) {
showDerivation(); j = nullptr;
else } else{
throw Error("expected a derivation"); if (visitor.isDerivation())
showDerivation();
else
throw Error("expected a derivation");
}
} catch (IFDError & e) { } catch (IFDError & e) {
if (!json) { if (!json) {
logger->cout(fmt("%s " ANSI_WARNING "omitted due to use of import from derivation" ANSI_NORMAL, headerPrefix)); logger->cout(fmt("%s " ANSI_WARNING "omitted due to use of import from derivation" ANSI_NORMAL, headerPrefix));

View file

@ -16,6 +16,7 @@ writeSimpleFlake() {
foo = import ./simple.nix; foo = import ./simple.nix;
fooScript = (import ./shell.nix {}).foo; fooScript = (import ./shell.nix {}).foo;
default = foo; default = foo;
noPackage = null;
}; };
packages.someOtherSystem = rec { packages.someOtherSystem = rec {
foo = import ./simple.nix; foo = import ./simple.nix;

View file

@ -53,7 +53,7 @@ cat >flake.nix <<EOF
packages.$system = { }; packages.$system = { };
packages.someOtherSystem = { }; packages.someOtherSystem = { };
formatter = { }; formatter.x86_64-linux = null;
nixosConfigurations = { }; nixosConfigurations = { };
nixosModules = { }; nixosModules = { };
}; };
@ -63,7 +63,7 @@ nix flake show --json --all-systems > show-output.json
nix eval --impure --expr ' nix eval --impure --expr '
let show_output = builtins.fromJSON (builtins.readFile ./show-output.json); let show_output = builtins.fromJSON (builtins.readFile ./show-output.json);
in in
assert show_output == { }; assert show_output == { formatter = { x86_64-linux = null; }; };
true true
' '

View file

@ -85,3 +85,40 @@ rm ./my-result
# Flake outputs check. # Flake outputs check.
nix flake check nix flake check
nix flake show | grep -P "package 'formatter'" nix flake show | grep -P "package 'formatter'"
function expectFailWithOutputMatching() {
outputMustMatch=$1
if output=$(nix fmt 2>&1); then
echo >&2 "nix fmt unexpectedly succeeded"
exit 1
fi
if ! echo "$output" | grep "$outputMustMatch"; then
echo >&2 "Expected nix fmt output to match:"
echo >&2 "$outputMustMatch"
echo >&2 "However, the actual output was:"
echo >&2 "$output"
exit 1
fi
}
# Try a flake with no formatter.
cat << EOF > flake.nix
{
outputs = _: {};
}
EOF
expectFailWithOutputMatching "does not provide attribute 'formatter.$system'"
# Confirm that a null formatter is treated as if there is no formatter.
cat << EOF > flake.nix
{
outputs = _: {
formatter.$system = null;
};
}
EOF
if nix fmt | grep "does not provide attribute 'formatter.$system'"; then
echo >&2 "nix fmt unexpectedly succeeded"
exit 1
fi