Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package nix for openSUSE:Factory checked in at 2026-07-15 16:55:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nix (Old) and /work/SRC/openSUSE:Factory/.nix.new.1991 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nix" Wed Jul 15 16:55:11 2026 rev:20 rq:1365947 version:2.34.8 Changes: -------- --- /work/SRC/openSUSE:Factory/nix/nix.changes 2026-05-28 23:12:16.072210170 +0200 +++ /work/SRC/openSUSE:Factory/.nix.new.1991/nix.changes 2026-07-15 17:11:54.656162643 +0200 @@ -1,0 +2,6 @@ +Wed Jul 8 11:17:31 UTC 2026 - Eyad Issa <[email protected]> + +- Update to version 2.37.8: + see /usr/share/doc/packages/rl-2.34.md + +------------------------------------------------------------------- Old: ---- nix-2.34.7.tar.gz New: ---- nix-2.34.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nix.spec ++++++ --- /var/tmp/diff_new_pack.ZGpOno/_old 2026-07-15 17:11:55.388187593 +0200 +++ /var/tmp/diff_new_pack.ZGpOno/_new 2026-07-15 17:11:55.388187593 +0200 @@ -26,7 +26,7 @@ %bcond_with docs Name: nix -Version: 2.34.7 +Version: 2.34.8 Release: 0 Summary: The purely functional package manager License: LGPL-2.1-only ++++++ nix-2.34.7.tar.gz -> nix-2.34.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/.version new/nix-2.34.8/.version --- old/nix-2.34.7/.version 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/.version 2026-07-01 22:22:08.000000000 +0200 @@ -1 +1 @@ -2.34.7 +2.34.8 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/scripts/install-nix-from-tarball.sh new/nix-2.34.8/scripts/install-nix-from-tarball.sh --- old/nix-2.34.7/scripts/install-nix-from-tarball.sh 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/scripts/install-nix-from-tarball.sh 2026-07-01 22:22:08.000000000 +0200 @@ -28,14 +28,15 @@ OS="$(uname -s)" -# macOS support for 10.12.6 or higher +# Since nixpkgs 25.11 the minimum deployment target is macOS 14.0 if [ "$OS" = "Darwin" ]; then + # shellcheck disable=SC2034 IFS='.' read -r macos_major macos_minor macos_patch << EOF $(sw_vers -productVersion) EOF - if [ "$macos_major" -lt 10 ] || { [ "$macos_major" -eq 10 ] && [ "$macos_minor" -lt 12 ]; } || { [ "$macos_minor" -eq 12 ] && [ "$macos_patch" -lt 6 ]; }; then + if [ "$macos_major" -lt 14 ]; then # patch may not be present; command substitution for simplicity - echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 10.12.6 or higher" + echo "$0: macOS $(sw_vers -productVersion) is not supported, upgrade to 14.0 or higher" exit 1 fi fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libcmd/include/nix/cmd/markdown.hh new/nix-2.34.8/src/libcmd/include/nix/cmd/markdown.hh --- old/nix-2.34.7/src/libcmd/include/nix/cmd/markdown.hh 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libcmd/include/nix/cmd/markdown.hh 2026-07-01 22:22:08.000000000 +0200 @@ -1,6 +1,7 @@ #pragma once ///@file +#include <string> #include <string_view> namespace nix { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libcmd/repl.cc new/nix-2.34.8/src/libcmd/repl.cc --- old/nix-2.34.7/src/libcmd/repl.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libcmd/repl.cc 2026-07-01 22:22:08.000000000 +0200 @@ -659,6 +659,8 @@ ExprAttrs * bindings = nullptr; try { bindings = parseReplBindings(line); + } catch (IncompleteReplExpr &) { + throw; } catch (ParseError &) { } @@ -875,7 +877,13 @@ // Use original source (s) for error messages, not s + ";" try { return state->parseReplBindings(s + ";", s, basePath, staticEnv); - } catch (ParseError &) { + } catch (ParseError & e) { + // All binding parse attempts failed. If the last error indicates + // incomplete input (e.g. unclosed multi-line string), signal the + // mainLoop to read continuation lines instead of falling through + // to expression parsing which would produce a misleading error. + if (e.msg().find("unexpected end of file") != std::string::npos) + throw IncompleteReplExpr(e.msg()); // Semicolon retry failed; rethrow the original bindings error std::rethrow_exception(bindingsError); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libfetchers/git-lfs-fetch.cc new/nix-2.34.8/src/libfetchers/git-lfs-fetch.cc --- old/nix-2.34.7/src/libfetchers/git-lfs-fetch.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libfetchers/git-lfs-fetch.cc 2026-07-01 22:22:08.000000000 +0200 @@ -7,6 +7,7 @@ #include "nix/util/users.hh" #include "nix/util/util.hh" #include "nix/util/hash.hh" +#include "nix/util/json-utils.hh" #include "nix/store/ssh.hh" #include <git2/attr.h> @@ -290,7 +291,8 @@ const auto obj = objUrls[0]; try { - std::string sha256 = obj.at("oid"); // oid is also the sha256 + // Use the committed pointer's oid/size for integrity, not server's claim + std::string sha256 = pointer->oid; std::string ourl = obj.at("actions").at("download").at("href"); auto authHeader = [&]() -> std::optional<std::string> { const auto & download = obj.at("actions").at("download"); @@ -302,7 +304,20 @@ return std::nullopt; return std::string(*authIt); }(); - const uint64_t size = obj.at("size"); + const uint64_t size = pointer->size; + + auto objOid = getString(valueAt(getObject(obj), "oid")); + auto objSize = getUnsigned(valueAt(getObject(obj), "size")); + if (objOid != pointer->oid || objSize != pointer->size) { + throw Error( + "LFS server returned mismatched oid/size for '%s' (got oid=%s size=%d, expected oid=%s size=%d)", + pointerFilePath, + objOid, + objSize, + pointer->oid, + pointer->size); + } + sizeCallback(size); downloadToSink(ourl, authHeader, sink, sha256, size); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore/build/derivation-goal.cc new/nix-2.34.8/src/libstore/build/derivation-goal.cc --- old/nix-2.34.7/src/libstore/build/derivation-goal.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore/build/derivation-goal.cc 2026-07-01 22:22:08.000000000 +0200 @@ -161,12 +161,16 @@ } auto resolutionGoal = worker.makeDerivationResolutionGoal(drvPath, *drv, buildMode); + /* We'll handle the error below. */ + resolutionGoal->preserveFailure = true; { Goals waitees{resolutionGoal}; co_await await(std::move(waitees)); } if (nrFailed != 0) { - co_return doneFailure({BuildResult::Failure::DependencyFailed, "Build failed due to failed dependency"}); + auto * failure = resolutionGoal->buildResult.tryGetFailure(); + assert(failure); + co_return doneFailure(*failure); } if (resolutionGoal->resolvedDrv) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore/build/derivation-trampoline-goal.cc new/nix-2.34.8/src/libstore/build/derivation-trampoline-goal.cc --- old/nix-2.34.7/src/libstore/build/derivation-trampoline-goal.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore/build/derivation-trampoline-goal.cc 2026-07-01 22:22:08.000000000 +0200 @@ -2,6 +2,9 @@ #include "nix/store/build/worker.hh" #include "nix/store/derivations.hh" +#include <ranges> +#include <algorithm> + namespace nix { DerivationTrampolineGoal::DerivationTrampolineGoal( @@ -145,6 +148,9 @@ }, wantedOutputs.raw); + /* Must have at least one wanted output. This is assumed below. */ + assert(!resolvedWantedOutputs.empty()); + Goals concreteDrvGoals; /* Build this step! */ @@ -156,20 +162,71 @@ concreteDrvGoals.insert(std::move(g)); } - // Copy on purpose - co_await await(Goals(concreteDrvGoals)); + co_await await(concreteDrvGoals); trace("outer build done"); - auto & g = *concreteDrvGoals.begin(); - buildResult = g->buildResult; - if (auto * successP = buildResult.tryGetSuccess()) - for (auto & g2 : concreteDrvGoals) - if (auto * successP2 = g2->buildResult.tryGetSuccess()) - for (auto && [x, y] : successP2->builtOutputs) - successP->builtOutputs.insert_or_assign(x, y); + if (nrFailed != 0) { + auto gi = std::ranges::find_if(concreteDrvGoals, [](const GoalPtr & goal) -> bool { + auto exitCode = goal->exitCode; + /* Note that without --keep-going waitees might be cancelled before + we are woken up. */ + return exitCode != ecBusy && exitCode != ecSuccess; + }); + + const Goal * g = gi->get(); + assert(gi != concreteDrvGoals.end() && "expected a failing goal"); + auto exitCode = g->exitCode; + const auto * failure = g->buildResult.tryGetFailure(); + assert(failure && "failing goal does not report a failed build result"); + + /* Report the exit status of *some* failing goal. This might not be strictly + correct, since multiple subgoals can fail independently, but this should be + a good enough heuristic without --keep-going. */ + co_return doneFailure(exitCode, *failure); + } + + SingleDrvOutputs outputs; - co_return amDone(g->exitCode); + auto successes = std::views::transform(concreteDrvGoals, [](const GoalPtr & a) -> const BuildResult::Success & { + auto * success = a->buildResult.tryGetSuccess(); + assert(success && "goal succeeded, but some waitees do not report a successful status"); + return *success; + }); + + for (const auto & success : successes) + std::ranges::copy(success.builtOutputs, std::inserter(outputs, outputs.end())); + + auto statuses = successes | std::views::transform(&BuildResult::Success::status); + + /* Aggregate the status code. If some outputs we already valid, but we had + to build/substitute the other ones, report it as the smallest common + denominator. */ + auto compareSuccesses = [](auto a, auto b) { + /* This is technically an identity mapping of the underlying values, but + it would be worse to rely on the enum ordering here. */ + auto toPriority = [](auto st) { + using enum BuildResult::Success::Status; + switch (st) { + case Built: + return 0; + case Substituted: + return 1; + case AlreadyValid: + return 2; + case ResolvesToAlreadyValid: + return 3; + default: + unreachable(); + } + }; + return toPriority(a) < toPriority(b); + }; + + co_return doneSuccess({ + .status = std::ranges::min(statuses, compareSuccesses), + .builtOutputs = std::move(outputs), + }); } } // namespace nix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore/derivations.cc new/nix-2.34.8/src/libstore/derivations.cc --- old/nix-2.34.7/src/libstore/derivations.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore/derivations.cc 2026-07-01 22:22:08.000000000 +0200 @@ -225,6 +225,7 @@ size_t start = 0; size_t end = str.remaining.size(); const auto data = str.remaining.data(); + bool foundClose = false; while (start < end) { auto idx = str.remaining.find('"', start); if (idx == std::string_view::npos) { @@ -235,10 +236,13 @@ ; if ((idx - pos) % 2 == 0) { // even number of backslashes end = idx; + foundClose = true; break; } start = idx + 1; } + if (!foundClose) + throw FormatError("unterminated string in derivation"); start = 0; const auto content = str.remaining.substr(start, end); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore/filetransfer.cc new/nix-2.34.8/src/libstore/filetransfer.cc --- old/nix-2.34.7/src/libstore/filetransfer.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore/filetransfer.cc 2026-07-01 22:22:08.000000000 +0200 @@ -798,6 +798,8 @@ private: bool quitting = false; public: + bool work = false; + void quit() { quitting = true; @@ -853,12 +855,14 @@ void stopWorkerThread() { /* Signal the worker thread to exit. */ - state_.lock()->quit(); - wakeupMulti(); + auto state(state_.lock()); + state->quit(); + wakeupMulti(*state); } - void wakeupMulti() + void wakeupMulti(State & state) { + state.work = true; if (auto ec = ::curl_multi_wakeup(curlm.get())) throw curlMultiError(ec); } @@ -908,25 +912,12 @@ } } - /* Wait for activity, including wakeup events. */ - long maxSleepTimeMs = items.empty() ? 10000 : 100; - auto sleepTimeMs = nextWakeup != std::chrono::steady_clock::time_point() - ? std::max( - 0, - (int) std::chrono::duration_cast<std::chrono::milliseconds>( - nextWakeup - std::chrono::steady_clock::now()) - .count()) - : maxSleepTimeMs; - - int numfds = 0; - mc = curl_multi_poll(curlm.get(), nullptr, 0, sleepTimeMs, &numfds); - if (mc != CURLM_OK) - throw curlMultiError(mc); - nextWakeup = std::chrono::steady_clock::time_point(); std::vector<std::shared_ptr<TransferItem>> incoming; + std::vector<std::weak_ptr<Item>> unpause; auto now = std::chrono::steady_clock::now(); + bool haveWork; { auto state(state_.lock()); @@ -948,7 +939,9 @@ break; } } + unpause = std::exchange(state->unpause, {}); quit = state->isQuitting(); + haveWork = std::exchange(state->work, false); } for (auto & item : incoming) { @@ -959,14 +952,10 @@ items[item->req] = item; } - /* NOTE: Unpausing may invoke callbacks to flush all buffers. */ - auto unpause = [&]() { - auto state(state_.lock()); - auto res = state->unpause; - state->unpause.clear(); - return res; - }(); + if (quit) + break; + /* NOTE: Unpausing may invoke callbacks to flush all buffers. */ for (auto & item : unpause) { /* The transfer might have completed (failed) between it getting enqueued for unpause and by the time the worker thread picked @@ -976,6 +965,26 @@ continue; static_cast<TransferItem &>(*ptr).unpause(); } + + /* Wait for activity, including wakeup events. */ + long maxSleepTimeMs = items.empty() ? 10000 : 100; + auto sleepTimeMs = nextWakeup != std::chrono::steady_clock::time_point() + ? std::max( + 0, + (int) std::chrono::duration_cast<std::chrono::milliseconds>( + nextWakeup - std::chrono::steady_clock::now()) + .count()) + : maxSleepTimeMs; + + /* Since https://github.com/curl/curl/commit/2a2104f3cff44bb28bb570a093be52bbeeed8f23 (8.21), + curl_multi_perform seems to swallow queued up events ¯\_(ツ)_/¯. */ + if (haveWork) + sleepTimeMs = 0; + + int numfds = 0; + mc = curl_multi_poll(curlm.get(), nullptr, 0, sleepTimeMs, &numfds); + if (mc != CURLM_OK) + throw curlMultiError(mc); } debug("download thread shutting down"); @@ -1012,9 +1021,9 @@ throw nix::Error("cannot enqueue download request because the download thread is shutting down"); state->incoming.push(item); item->enqueued = true; /* Now any exceptions should be reported via the callback. */ + wakeupMulti(*state); } - wakeupMulti(); return ItemHandle(item.get_ptr()); } @@ -1034,7 +1043,7 @@ { auto state(state_.lock()); state->unpause.push_back(std::move(item)); - wakeupMulti(); + wakeupMulti(*state); } void unpauseTransfer(ItemHandle handle) override diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore/local-store.cc new/nix-2.34.8/src/libstore/local-store.cc --- old/nix-2.34.7/src/libstore/local-store.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore/local-store.cc 2026-07-01 22:22:08.000000000 +0200 @@ -212,7 +212,7 @@ #if HAVE_POSIX_FALLOCATE res = posix_fallocate(fd.get(), 0, gcSettings.reservedSize); #endif - if (res == -1) { + if (res != 0) { writeFull(fd.get(), std::string(gcSettings.reservedSize, 'X')); [[gnu::unused]] auto res2 = @@ -393,17 +393,7 @@ AutoCloseFD LocalStore::openGCLock() { auto fnGCLock = config->stateDir.get() / "gc.lock"; - auto fdGCLock = open( - fnGCLock.string().c_str(), - O_RDWR | O_CREAT -#ifndef _WIN32 - | O_CLOEXEC -#endif - , - 0600); - if (!fdGCLock) - throw SysError("opening global GC lock %1%", PathFmt(fnGCLock)); - return toDescriptor(fdGCLock); + return openLockFile(fnGCLock, /*create=*/true); } void LocalStore::deleteStorePath(const std::filesystem::path & path, uint64_t & bytesFreed, bool isKnownPath) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore/unix/build/derivation-builder.cc new/nix-2.34.8/src/libstore/unix/build/derivation-builder.cc --- old/nix-2.34.7/src/libstore/unix/build/derivation-builder.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore/unix/build/derivation-builder.cc 2026-07-01 22:22:08.000000000 +0200 @@ -499,8 +499,7 @@ .gid = gid, .chdir = "/"}); if (!statusOk(diffRes.first)) - throw ExecError( - diffRes.first, "diff-hook program %s %2%", PathFmt(diffHook), statusToString(diffRes.first)); + throw ExecError(diffRes.first, "diff-hook program %s %s", PathFmt(diffHook), statusToString(diffRes.first)); if (diffRes.second != "") printError(chomp(diffRes.second)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libstore-tests/derivation/external-formats.cc new/nix-2.34.8/src/libstore-tests/derivation/external-formats.cc --- old/nix-2.34.7/src/libstore-tests/derivation/external-formats.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libstore-tests/derivation/external-formats.cc 2026-07-01 22:22:08.000000000 +0200 @@ -15,6 +15,14 @@ parseDerivation(*store, readFile(goldenMaster("bad-version.drv")), "whatever", mockXpSettings), FormatError); } +TEST_F(DerivationTest, UnterminatedString) +{ + ASSERT_THROW( + parseDerivation( + *store, "Derive([(\"out\",\"/nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo", "bar", mockXpSettings), + FormatError); +} + TEST_F(DynDerivationTest, BadATerm_oldVersionDynDeps) { ASSERT_THROW( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libutil/archive.cc new/nix-2.34.8/src/libutil/archive.cc --- old/nix-2.34.7/src/libutil/archive.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libutil/archive.cc 2026-07-01 22:22:08.000000000 +0200 @@ -34,8 +34,7 @@ /* Maximum directory nesting depth for dumpPath()/parseDump(). Bounds stack usage so deep trees cannot overflow the (possibly coroutine) - stack these run on. Chosen to fit comfortably in the default 128 KiB - boost coroutine stack. */ + stack these run on. */ static constexpr size_t narMaxDepth = 64; PathFilter defaultPathFilter = [](const std::string &) { return true; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libutil/serialise.cc new/nix-2.34.8/src/libutil/serialise.cc --- old/nix-2.34.7/src/libutil/serialise.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libutil/serialise.cc 2026-07-01 22:22:08.000000000 +0200 @@ -305,6 +305,13 @@ { } +/* 512KiB is a conservative estimate for deeply nested NARs, which are limited + to 64 levels. We also tend to allocate rather large buffers on the stack, so + we should leave plenty of headroom. Note that no evaluation is supposed to + happen on sourceToSink/sinkToSource coroutine stacks (for Boehm GC reasons), + which requires much more stack space. */ +static constexpr size_t defaultCoroutineStackSize = 512 * 1024; + std::unique_ptr<FinishSink> sourceToSink(fun<void(Source &)> reader) { struct SourceToSink : FinishSink @@ -328,8 +335,9 @@ cur = in; if (!coro) { - coro = - coro_t::push_type(boost::coroutines2::protected_fixedsize_stack(), [&](coro_t::pull_type & yield) { + coro = coro_t::push_type( + boost::coroutines2::protected_fixedsize_stack(defaultCoroutineStackSize), + [&](coro_t::pull_type & yield) { LambdaSource source([&](char * out, size_t out_len) { if (cur.empty()) { yield(); @@ -386,8 +394,9 @@ { bool hasCoro = coro.has_value(); if (!hasCoro) { - coro = - coro_t::pull_type(boost::coroutines2::protected_fixedsize_stack(), [&](coro_t::push_type & yield) { + coro = coro_t::pull_type( + boost::coroutines2::protected_fixedsize_stack(defaultCoroutineStackSize), + [&](coro_t::push_type & yield) { LambdaSink sink([&](std::string_view data) { if (!data.empty()) { yield(data); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/libutil/unix/processes.cc new/nix-2.34.8/src/libutil/unix/processes.cc --- old/nix-2.34.7/src/libutil/unix/processes.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/libutil/unix/processes.cc 2026-07-01 22:22:08.000000000 +0200 @@ -51,11 +51,13 @@ } Pid::~Pid() -try { - if (pid != -1) - kill(/*allowInterrupts=*/false); -} catch (...) { - ignoreExceptionInDestructor(); +{ + try { + if (pid != -1) + kill(/*allowInterrupts=*/false); + } catch (...) { + ignoreExceptionInDestructor(); + } } void Pid::operator=(pid_t pid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/src/nix/nix-store/nix-store.cc new/nix-2.34.8/src/nix/nix-store/nix-store.cc --- old/nix-2.34.7/src/nix/nix-store/nix-store.cc 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/src/nix/nix-store/nix-store.cc 2026-07-01 22:22:08.000000000 +0200 @@ -575,6 +575,7 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) { + auto localStore = ensureLocalStore(); ValidPathInfos infos; while (1) { @@ -592,7 +593,7 @@ /* !!! races */ if (canonicalise) canonicalisePathMetaData( - store->printStorePath(info->path), + localStore->toRealPath(info->path), {NIX_WHEN_SUPPORT_ACLS(settings.getLocalSettings().ignoredAcls)}); if (!hashGiven) { HashResult hash = hashPath( @@ -606,7 +607,7 @@ } } - ensureLocalStore()->registerValidPaths(infos); + localStore->registerValidPaths(infos); } static void opLoadDB(Strings opFlags, Strings opArgs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/build.sh new/nix-2.34.8/tests/functional/build.sh --- old/nix-2.34.7/tests/functional/build.sh 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/tests/functional/build.sh 2026-07-01 22:22:08.000000000 +0200 @@ -191,13 +191,9 @@ # Precise number of errors depends on daemon version / goal refactorings (( "$(<<<"$out" grep -cE '^error:')" >= 2 )) -if isDaemonNewer "2.31"; then +if isDaemonNewer "2.29pre"; then <<<"$out" grepQuiet -E "error: Cannot build '.*-x4\\.drv'" <<<"$out" grepQuiet -E "Reason: 1 dependency failed." -elif isDaemonNewer "2.29pre"; then - <<<"$out" grepQuiet -E "error: Cannot build '.*-x4\\.drv'" - <<<"$out" grepQuiet -E "Reason: 1 dependency failed." - <<<"$out" grepQuiet -E "Build failed due to failed dependency" else <<<"$out" grepQuiet -E "error: 1 dependencies of derivation '.*-x4\\.drv' failed to build" fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/chroot-store.sh new/nix-2.34.8/tests/functional/chroot-store.sh --- old/nix-2.34.7/tests/functional/chroot-store.sh 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/tests/functional/chroot-store.sh 2026-07-01 22:22:08.000000000 +0200 @@ -60,6 +60,15 @@ # Path gets decoded. [[ ! -d "$TEST_ROOT/x%2Bchroot" ]] +# Regression test: `nix-store --register-validity` against a chroot store must +# canonicalise the real (chroot-prefixed) path, not the logical store path +# (which does not exist on the host filesystem). +regPath=$NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-reg +touch "$TEST_ROOT/x/nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-reg" +[[ ! -e "$regPath" ]] +(echo "$regPath" && echo && echo 0) | nix-store --store "local?root=$TEST_ROOT/x" --register-validity +nix-store --store "$TEST_ROOT/x" --check-validity "$regPath" + # Ensure store info trusted works with local store nix --store "$TEST_ROOT/x" store info --json | jq -e '.trusted' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/meson.build new/nix-2.34.8/tests/functional/meson.build --- old/nix-2.34.7/tests/functional/meson.build 2026-05-04 19:22:33.000000000 +0200 +++ new/nix-2.34.8/tests/functional/meson.build 2026-07-01 22:22:08.000000000 +0200 @@ -66,6 +66,7 @@ 'user-envs-migration.sh', 'cli-characterisation.sh', 'binary-cache.sh', + 'multiple-outputs-substitute-failure.sh', 'multiple-outputs.sh', 'nix-build.sh', 'gc-concurrent.sh', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/multiple-outputs-substitute-failure.sh new/nix-2.34.8/tests/functional/multiple-outputs-substitute-failure.sh --- old/nix-2.34.7/tests/functional/multiple-outputs-substitute-failure.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.34.8/tests/functional/multiple-outputs-substitute-failure.sh 2026-07-01 22:22:08.000000000 +0200 @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# See https://github.com/NixOS/nix/issues/15916 + +source common.sh + +TODO_NixOS # Requires substituting from a local binary cache, enable when we sign paths in NixOS tests +needLocalStore "'--no-require-sigs' can’t be used with the daemon" + +BINARY_CACHE=file://$cacheDir + +readarray -t outPaths < <(nix build -f multiple-outputs.nix 'independent^*' --no-link --print-out-paths) +[[ ${#outPaths[@]} -eq 2 ]] +nix copy --to "$BINARY_CACHE" "${outPaths[@]}" +for p in "${outPaths[@]}"; do + [[ $p == *-second ]] && secondOut=$p +done + +# Corrupt the second output, so that the substitution partially succeeds. +secondNarInfoFile="$cacheDir/$(basename "$secondOut" | cut -c1-32).narinfo" +sed -i 's|^NarHash:.*|NarHash: sha256:0000000000000000000000000000000000000000000000000000|' "$secondNarInfoFile" + +clearStore +clearCacheCache + +# Note that using "^*" matters here. We want all wanted outputs for the same goal. +expect 1 nix build -j 0 -f multiple-outputs.nix "independent^*" --no-link \ + --substituters "$BINARY_CACHE" --no-require-sigs --substitute 2>&1 | grepQuiet "hash mismatch" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/repl/multiline-string-binding.expected new/nix-2.34.8/tests/functional/repl/multiline-string-binding.expected --- old/nix-2.34.7/tests/functional/repl/multiline-string-binding.expected 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.34.8/tests/functional/repl/multiline-string-binding.expected 2026-07-01 22:22:08.000000000 +0200 @@ -0,0 +1,9 @@ +Nix <nix version> +Type :? for help. + +nix-repl> x = '' + > hello + > '' + +nix-repl> x +"hello\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/repl/multiline-string-binding.in new/nix-2.34.8/tests/functional/repl/multiline-string-binding.in --- old/nix-2.34.7/tests/functional/repl/multiline-string-binding.in 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.34.8/tests/functional/repl/multiline-string-binding.in 2026-07-01 22:22:08.000000000 +0200 @@ -0,0 +1,4 @@ +x = '' + hello +'' +x diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/repl/multiline-string-function-binding.expected new/nix-2.34.8/tests/functional/repl/multiline-string-function-binding.expected --- old/nix-2.34.7/tests/functional/repl/multiline-string-function-binding.expected 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.34.8/tests/functional/repl/multiline-string-function-binding.expected 2026-07-01 22:22:08.000000000 +0200 @@ -0,0 +1,11 @@ +Nix <nix version> +Type :? for help. + +nix-repl> f = x: x + +nix-repl> y = f '' + > world + > '' + +nix-repl> y +"world\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.34.7/tests/functional/repl/multiline-string-function-binding.in new/nix-2.34.8/tests/functional/repl/multiline-string-function-binding.in --- old/nix-2.34.7/tests/functional/repl/multiline-string-function-binding.in 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.34.8/tests/functional/repl/multiline-string-function-binding.in 2026-07-01 22:22:08.000000000 +0200 @@ -0,0 +1,5 @@ +f = x: x +y = f '' + world +'' +y
