Skip to content

Commit 5e17a3f

Browse files
authored
Merge pull request #13998 from Mic92/fast-flake-check
nix flake check: Skip substitutable derivations
2 parents 0b401e2 + ecdda57 commit 5e17a3f

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
synopsis: "`nix flake check` now skips derivations that can be substituted"
3+
prs: [13574]
4+
---
5+
6+
Previously, `nix flake check` would evaluate and build/substitute all
7+
derivations. Now, it will skip downloading derivations that can be substituted.
8+
This can drastically decrease the time invocations take in environments where
9+
checks may already be cached (like in CI).

src/nix/flake.cc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,8 +786,32 @@ struct CmdFlakeCheck : FlakeCommand
786786
}
787787

788788
if (build && !drvPaths.empty()) {
789-
Activity act(*logger, lvlInfo, actUnknown, fmt("running %d flake checks", drvPaths.size()));
790-
store->buildPaths(drvPaths);
789+
// TODO: This filtering of substitutable paths is a temporary workaround until
790+
// https://github.com/NixOS/nix/issues/5025 (union stores) is implemented.
791+
//
792+
// Once union stores are available, this code should be replaced with a proper
793+
// union store configuration. Ideally, we'd use a union of multiple destination
794+
// stores to preserve the current behavior where different substituters can
795+
// cache different check results.
796+
//
797+
// For now, we skip building derivations whose outputs are already available
798+
// via substitution, as `nix flake check` only needs to verify buildability,
799+
// not actually produce the outputs.
800+
auto missing = store->queryMissing(drvPaths);
801+
// Only occurs if `drvPaths` contains a `DerivedPath::Opaque`, which should never happen
802+
assert(missing.unknown.empty());
803+
804+
std::vector<DerivedPath> toBuild;
805+
for (auto & path : missing.willBuild) {
806+
toBuild.emplace_back(
807+
DerivedPath::Built{
808+
.drvPath = makeConstantStorePathRef(path),
809+
.outputs = OutputsSpec::All{},
810+
});
811+
}
812+
813+
Activity act(*logger, lvlInfo, actUnknown, fmt("running %d flake checks", toBuild.size()));
814+
store->buildPaths(toBuild);
791815
}
792816
if (hasErrors)
793817
throw Error("some errors were encountered during the evaluation");

tests/functional/flakes/check.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,23 @@ EOF
167167
if !isTestOnNixOS && $NIX_REMOTE != daemon; then
168168
expectStderr 100 nix flake check "$flakeDir" | grepQuiet 'builder failed with exit code 1'
169169
fi
170+
171+
# Ensure non-substitutable (read: usually failed) checks are actually run
172+
# https://github.com/NixOS/nix/pull/13574
173+
cp "$config_nix" $flakeDir/
174+
cat > $flakeDir/flake.nix <<EOF
175+
{
176+
outputs = { self }: with import ./config.nix; {
177+
checks.${system}.expectedToFail = derivation {
178+
name = "expected-to-fail";
179+
inherit system;
180+
builder = "not-a-real-file";
181+
};
182+
};
183+
}
184+
EOF
185+
186+
# NOTE: Regex pattern is used for compatibility with older daemon versions
187+
# We also can't expect a specific status code. Earlier daemons return 1, but as of 2.31, we return 100
188+
checkRes=$(nix flake check $flakeDir 2>&1 && fail "nix flake check should have failed" || true)
189+
echo "$checkRes" | grepQuiet -E "builder( for .*)? failed with exit code 1"

0 commit comments

Comments
 (0)