From 5c9592194c3824b8d1f9da1ddc4d6b1c099bbc89 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Jul 2025 17:07:18 +0200 Subject: [PATCH] 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. --- src/nix/flake.cc | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 35e96e493..444d5707b 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -833,8 +833,31 @@ struct CmdFlakeCheck : FlakeCommand if (build && !drvPaths.empty()) { Activity act(*logger, lvlInfo, actUnknown, fmt("running %d flake checks", drvPaths.size())); - store->buildPaths(drvPaths); + + auto missing = store->queryMissing(drvPaths); + + /* This command doesn't need to actually substitute + derivation outputs if they're missing but + substitutable. So filter out derivations that are + substitutable or already built. */ + std::vector toBuild; + for (auto & path : drvPaths) { + std::visit(overloaded { + [&](const DerivedPath::Built & bfd) { + auto drvPathP = std::get_if(&*bfd.drvPath); + if (!drvPathP || missing.willBuild.contains(drvPathP->path)) + toBuild.push_back(path); + }, + [&](const DerivedPath::Opaque & bo) { + if (!missing.willSubstitute.contains(bo.path)) + toBuild.push_back(path); + }, + }, path.raw()); + } + + store->buildPaths(toBuild); } + if (hasErrors) throw Error("some errors were encountered during the evaluation");