aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/rl-next/consistent-nix-build.md6
-rw-r--r--src/libcmd/installables.cc38
-rw-r--r--tests/functional/build.sh32
-rw-r--r--tests/functional/fod-failing.nix39
4 files changed, 111 insertions, 4 deletions
diff --git a/doc/manual/rl-next/consistent-nix-build.md b/doc/manual/rl-next/consistent-nix-build.md
new file mode 100644
index 000000000..d5929dc8e
--- /dev/null
+++ b/doc/manual/rl-next/consistent-nix-build.md
@@ -0,0 +1,6 @@
+---
+synopsis: Show all FOD errors with `nix build --keep-going`
+---
+
+`nix build --keep-going` now behaves consistently with `nix-build --keep-going`. This means
+that if e.g. multiple FODs fail to build, all hash mismatches are displayed.
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index dca17555a..2c18653e4 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -547,6 +547,37 @@ std::vector<BuiltPathWithResult> Installable::build(
return res;
}
+static void throwBuildErrors(
+ std::vector<KeyedBuildResult> & buildResults,
+ const Store & store)
+{
+ std::vector<KeyedBuildResult> failed;
+ for (auto & buildResult : buildResults) {
+ if (!buildResult.success()) {
+ failed.push_back(buildResult);
+ }
+ }
+
+ auto failedResult = failed.begin();
+ if (failedResult != failed.end()) {
+ if (failed.size() == 1) {
+ failedResult->rethrow();
+ } else {
+ StringSet failedPaths;
+ for (; failedResult != failed.end(); failedResult++) {
+ if (!failedResult->errorMsg.empty()) {
+ logError(ErrorInfo{
+ .level = lvlError,
+ .msg = failedResult->errorMsg,
+ });
+ }
+ failedPaths.insert(failedResult->path.to_string(store));
+ }
+ throw Error("build of %s failed", concatStringsSep(", ", quoteStrings(failedPaths)));
+ }
+ }
+}
+
std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build2(
ref<Store> evalStore,
ref<Store> store,
@@ -608,10 +639,9 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
if (settings.printMissing)
printMissing(store, pathsToBuild, lvlInfo);
- for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) {
- if (!buildResult.success())
- buildResult.rethrow();
-
+ auto buildResults = store->buildPathsWithResults(pathsToBuild, bMode, evalStore);
+ throwBuildErrors(buildResults, *store);
+ for (auto & buildResult : buildResults) {
for (auto & aux : backmap[buildResult.path]) {
std::visit(overloaded {
[&](const DerivedPath::Built & bfd) {
diff --git a/tests/functional/build.sh b/tests/functional/build.sh
index 7fbdb0f07..95a20dc6a 100644
--- a/tests/functional/build.sh
+++ b/tests/functional/build.sh
@@ -133,3 +133,35 @@ nix build --impure -f multiple-outputs.nix --json e --no-link | jq --exit-status
# Make sure that `--stdin` works and does not apply any defaults
printf "" | nix build --no-link --stdin --json | jq --exit-status '. == []'
printf "%s\n" "$drv^*" | nix build --no-link --stdin --json | jq --exit-status '.[0]|has("drvPath")'
+
+# --keep-going and FOD
+out="$(nix build -f fod-failing.nix -L 2>&1)" && status=0 || status=$?
+test "$status" = 1
+# one "hash mismatch" error, one "build of ... failed"
+test "$(<<<"$out" grep -E '^error:' | wc -l)" = 2
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x1\\.drv'"
+<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x3\\.drv'"
+<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
+<<<"$out" grepQuiet -E "error: build of '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out' failed"
+
+out="$(nix build -f fod-failing.nix -L x1 x2 x3 --keep-going 2>&1)" && status=0 || status=$?
+test "$status" = 1
+# three "hash mismatch" errors - for each failing fod, one "build of ... failed"
+test "$(<<<"$out" grep -E '^error:' | wc -l)" = 4
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x1\\.drv'"
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x3\\.drv'"
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
+<<<"$out" grepQuiet -E "error: build of '.*-x[1-3]\\.drv\\^out', '.*-x[1-3]\\.drv\\^out', '.*-x[1-3]\\.drv\\^out' failed"
+
+out="$(nix build -f fod-failing.nix -L x4 2>&1)" && status=0 || status=$?
+test "$status" = 1
+test "$(<<<"$out" grep -E '^error:' | wc -l)" = 2
+<<<"$out" grepQuiet -E "error: 1 dependencies of derivation '.*-x4\\.drv' failed to build"
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
+
+out="$(nix build -f fod-failing.nix -L x4 --keep-going 2>&1)" && status=0 || status=$?
+test "$status" = 1
+test "$(<<<"$out" grep -E '^error:' | wc -l)" = 3
+<<<"$out" grepQuiet -E "error: 2 dependencies of derivation '.*-x4\\.drv' failed to build"
+<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x3\\.drv'"
+<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
diff --git a/tests/functional/fod-failing.nix b/tests/functional/fod-failing.nix
new file mode 100644
index 000000000..37c04fe12
--- /dev/null
+++ b/tests/functional/fod-failing.nix
@@ -0,0 +1,39 @@
+with import ./config.nix;
+rec {
+ x1 = mkDerivation {
+ name = "x1";
+ builder = builtins.toFile "builder.sh"
+ ''
+ echo $name > $out
+ '';
+ outputHashMode = "recursive";
+ outputHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+ };
+ x2 = mkDerivation {
+ name = "x2";
+ builder = builtins.toFile "builder.sh"
+ ''
+ echo $name > $out
+ '';
+ outputHashMode = "recursive";
+ outputHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+ };
+ x3 = mkDerivation {
+ name = "x3";
+ builder = builtins.toFile "builder.sh"
+ ''
+ echo $name > $out
+ '';
+ outputHashMode = "recursive";
+ outputHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+ };
+ x4 = mkDerivation {
+ name = "x4";
+ inherit x2 x3;
+ builder = builtins.toFile "builder.sh"
+ ''
+ echo $x2 $x3
+ exit 1
+ '';
+ };
+}