Skip to content

Commit 77c97e7

Browse files
getchooedolstra
andcommitted
nix flake check: Skip substitutable derivations
Since `nix flake check` doesn't produce a `result` symlink, it doesn't actually need to build/substitute derivations that are already known to have succeeded, i.e. that are substitutable. This can speed up CI jobs in cases where the derivations have already been built by other jobs. For instance, a command like nix flake check github:NixOS/hydra/aa62c7f7db31753f0cde690f8654dd1907fc0ce2 should no longer build anything because the outputs are already in cache.nixos.org. Based-on: DeterminateSystems#134 Based-on: https://gerrit.lix.systems/c/lix/+/3841 Co-authored-by: Eelco Dolstra <[email protected]>
1 parent b062730 commit 77c97e7

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-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: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,8 +783,23 @@ struct CmdFlakeCheck : FlakeCommand
783783
}
784784

785785
if (build && !drvPaths.empty()) {
786-
Activity act(*logger, lvlInfo, actUnknown, fmt("running %d flake checks", drvPaths.size()));
787-
store->buildPaths(drvPaths);
786+
// This command doesn't need to actually substitute derivation outputs
787+
// if they're missing but substitutable.
788+
auto missing = store->queryMissing(drvPaths);
789+
// Only occurs if `drvPaths` contains a `DerivedPath::Opaque`, which should never happen
790+
assert(missing.unknown.empty());
791+
792+
std::vector<DerivedPath> toBuild;
793+
for (auto & path : missing.willBuild) {
794+
toBuild.emplace_back(
795+
DerivedPath::Built{
796+
.drvPath = makeConstantStorePathRef(path),
797+
.outputs = OutputsSpec::All{},
798+
});
799+
}
800+
801+
Activity act(*logger, lvlInfo, actUnknown, fmt("running %d flake checks", toBuild.size()));
802+
store->buildPaths(toBuild);
788803
}
789804
if (hasErrors)
790805
throw Error("some errors were encountered during the evaluation");

tests/functional/flakes/check.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,21 @@ EOF
135135

136136
checkRes=$(nix flake check --all-systems $flakeDir 2>&1 && fail "nix flake check --all-systems should have failed" || true)
137137
echo "$checkRes" | grepQuiet "formatter.system-1"
138+
139+
# Ensure non-substitutable (read: usually failed) checks are actually run
140+
# https://github.com/NixOS/nix/pull/13574
141+
cp "$config_nix" $flakeDir/
142+
cat > $flakeDir/flake.nix <<EOF
143+
{
144+
outputs = { self }: with import ./config.nix; {
145+
checks.${system}.expectedToFail = derivation {
146+
name = "expected-to-fail";
147+
inherit system;
148+
builder = "not-a-real-file";
149+
};
150+
};
151+
}
152+
EOF
153+
154+
checkRes=$(nix flake check $flakeDir 2>&1 && fail "nix flake check should have failed" || true)
155+
echo "$checkRes" | grepQuiet "builder failed with exit code 1"

0 commit comments

Comments
 (0)