Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package nix for openSUSE:Factory checked in at 2025-09-26 22:24:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nix (Old) and /work/SRC/openSUSE:Factory/.nix.new.11973 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nix" Fri Sep 26 22:24:39 2025 rev:8 rq:1307210 version:2.31.2 Changes: -------- --- /work/SRC/openSUSE:Factory/nix/nix.changes 2025-09-05 21:44:16.579080774 +0200 +++ /work/SRC/openSUSE:Factory/.nix.new.11973/nix.changes 2025-09-26 22:25:59.177713278 +0200 @@ -1,0 +2,10 @@ +Thu Sep 18 13:04:51 UTC 2025 - Marcus Rueckert <[email protected]> + +- Update to 2.31.2: + - Temporary build directories created during derivation builds no + longer include the derivation name in their path to avoid build + failures when the derivation name is too long. This change + ensures pred ictable prefix lengths for build directories under + `/nix/var/nix/builds` + +------------------------------------------------------------------- Old: ---- nix-2.31.1.tar.gz New: ---- nix-2.31.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nix.spec ++++++ --- /var/tmp/diff_new_pack.8pRRUg/_old 2025-09-26 22:25:59.849741620 +0200 +++ /var/tmp/diff_new_pack.8pRRUg/_new 2025-09-26 22:25:59.853741788 +0200 @@ -35,7 +35,7 @@ %endif Name: nix -Version: 2.31.1 +Version: 2.31.2 Release: 0 Summary: The purely functional package manager License: LGPL-2.1-only ++++++ nix-2.31.1.tar.gz -> nix-2.31.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/.version new/nix-2.31.2/.version --- old/nix-2.31.1/.version 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/.version 2025-09-17 22:25:38.000000000 +0200 @@ -1 +1 @@ -2.31.1 +2.31.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/doc/manual/rl-next/shorter-build-dir-names.md new/nix-2.31.2/doc/manual/rl-next/shorter-build-dir-names.md --- old/nix-2.31.1/doc/manual/rl-next/shorter-build-dir-names.md 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.31.2/doc/manual/rl-next/shorter-build-dir-names.md 2025-09-17 22:25:38.000000000 +0200 @@ -0,0 +1,6 @@ +--- +synopsis: "Temporary build directories no longer include derivation names" +prs: [13839] +--- + +Temporary build directories created during derivation builds no longer include the derivation name in their path to avoid build failures when the derivation name is too long. This change ensures predictable prefix lengths for build directories under `/nix/var/nix/builds`. \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libcmd/installables.cc new/nix-2.31.2/src/libcmd/installables.cc --- old/nix-2.31.1/src/libcmd/installables.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libcmd/installables.cc 2025-09-17 22:25:38.000000000 +0200 @@ -178,10 +178,16 @@ for (auto & [inputName, input] : flake.lockFile.root->inputs) { auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes if (auto input3 = std::dynamic_pointer_cast<const flake::LockedNode>(input2)) { + fetchers::Attrs extraAttrs; + + if (!input3->lockedRef.subdir.empty()) { + extraAttrs["dir"] = input3->lockedRef.subdir; + } + overrideRegistry( fetchers::Input::fromAttrs(fetchSettings, {{"type", "indirect"}, {"id", inputName}}), input3->lockedRef.input, - {}); + extraAttrs); } } }}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libexpr/meson.build new/nix-2.31.2/src/libexpr/meson.build --- old/nix-2.31.1/src/libexpr/meson.build 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libexpr/meson.build 2025-09-17 22:25:38.000000000 +0200 @@ -40,7 +40,10 @@ boost = dependency( 'boost', - modules : [ 'container', 'context' ], + modules : [ + 'container', + 'context', + ], include_type : 'system', ) # boost is a public dependency, but not a pkg-config dependency unfortunately, so we diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libfetchers/include/nix/fetchers/input-cache.hh new/nix-2.31.2/src/libfetchers/include/nix/fetchers/input-cache.hh --- old/nix-2.31.1/src/libfetchers/include/nix/fetchers/input-cache.hh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libfetchers/include/nix/fetchers/input-cache.hh 2025-09-17 22:25:38.000000000 +0200 @@ -11,6 +11,7 @@ ref<SourceAccessor> accessor; Input resolvedInput; Input lockedInput; + Attrs extraAttrs; }; CachedResult getAccessor(ref<Store> store, const Input & originalInput, UseRegistries useRegistries); @@ -19,6 +20,7 @@ { Input lockedInput; ref<SourceAccessor> accessor; + Attrs extraAttrs; }; virtual std::optional<CachedInput> lookup(const Input & originalInput) const = 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libfetchers/input-cache.cc new/nix-2.31.2/src/libfetchers/input-cache.cc --- old/nix-2.31.1/src/libfetchers/input-cache.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libfetchers/input-cache.cc 2025-09-17 22:25:38.000000000 +0200 @@ -22,7 +22,8 @@ fetched = lookup(resolvedInput); if (!fetched) { auto [accessor, lockedInput] = resolvedInput.getAccessor(store); - fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor}); + fetched.emplace( + CachedInput{.lockedInput = lockedInput, .accessor = accessor, .extraAttrs = extraAttrs}); } upsert(resolvedInput, *fetched); } else { @@ -36,7 +37,7 @@ debug("got tree '%s' from '%s'", fetched->accessor, fetched->lockedInput.to_string()); - return {fetched->accessor, resolvedInput, fetched->lockedInput}; + return {fetched->accessor, resolvedInput, fetched->lockedInput, fetched->extraAttrs}; } struct InputCacheImpl : InputCache diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libflake/flake.cc new/nix-2.31.2/src/libflake/flake.cc --- old/nix-2.31.1/src/libflake/flake.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libflake/flake.cc 2025-09-17 22:25:38.000000000 +0200 @@ -340,8 +340,9 @@ // Fetch a lazy tree first. auto cachedInput = state.inputCache->getAccessor(state.store, originalRef.input, useRegistries); - auto resolvedRef = FlakeRef(std::move(cachedInput.resolvedInput), originalRef.subdir); - auto lockedRef = FlakeRef(std::move(cachedInput.lockedInput), originalRef.subdir); + auto subdir = fetchers::maybeGetStrAttr(cachedInput.extraAttrs, "dir").value_or(originalRef.subdir); + auto resolvedRef = FlakeRef(std::move(cachedInput.resolvedInput), subdir); + auto lockedRef = FlakeRef(std::move(cachedInput.lockedInput), subdir); // Parse/eval flake.nix to get at the input.self attributes. auto flake = readFlake(state, originalRef, resolvedRef, lockedRef, {cachedInput.accessor}, lockRootAttrPath); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/include/nix/store/filetransfer.hh new/nix-2.31.2/src/libstore/include/nix/store/filetransfer.hh --- old/nix-2.31.1/src/libstore/include/nix/store/filetransfer.hh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/include/nix/store/filetransfer.hh 2025-09-17 22:25:38.000000000 +0200 @@ -30,9 +30,17 @@ )", {"binary-caches-parallel-connections"}}; + /* Do not set this too low. On glibc, getaddrinfo() contains fallback code + paths that deal with ill-behaved DNS servers. Setting this too low + prevents some fallbacks from occurring. + + See description of options timeout, single-request, single-request-reopen + in resolv.conf(5). Also see https://github.com/NixOS/nix/pull/13985 for + details on the interaction between getaddrinfo(3) behavior and libcurl + CURLOPT_CONNECTTIMEOUT. */ Setting<unsigned long> connectTimeout{ this, - 5, + 15, "connect-timeout", R"( The timeout (in seconds) for establishing connections in the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/include/nix/store/store-reference.hh new/nix-2.31.2/src/libstore/include/nix/store/store-reference.hh --- old/nix-2.31.1/src/libstore/include/nix/store/store-reference.hh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/include/nix/store/store-reference.hh 2025-09-17 22:25:38.000000000 +0200 @@ -64,7 +64,29 @@ auto operator<=>(const Specified & rhs) const = default; }; - typedef std::variant<Auto, Specified> Variant; + /** + * Special case for `daemon` to avoid normalization. + */ + struct Daemon : Specified + { + Daemon() + : Specified({.scheme = "unix"}) + { + } + }; + + /** + * Special case for `local` to avoid normalization. + */ + struct Local : Specified + { + Local() + : Specified({.scheme = "local"}) + { + } + }; + + typedef std::variant<Auto, Specified, Daemon, Local> Variant; Variant variant; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/local-store.cc new/nix-2.31.2/src/libstore/local-store.cc --- old/nix-2.31.1/src/libstore/local-store.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/local-store.cc 2025-09-17 22:25:38.000000000 +0200 @@ -456,12 +456,17 @@ StoreReference LocalStoreConfig::getReference() const { + auto params = getQueryParams(); + /* Back-compatibility kludge. Tools like nix-output-monitor expect 'local' + and can't parse 'local://'. */ + if (params.empty()) + return {.variant = StoreReference::Local{}}; return { .variant = StoreReference::Specified{ .scheme = *uriSchemes().begin(), }, - .params = getQueryParams(), + .params = std::move(params), }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/meson.build new/nix-2.31.2/src/libstore/meson.build --- old/nix-2.31.1/src/libstore/meson.build 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/meson.build 2025-09-17 22:25:38.000000000 +0200 @@ -101,7 +101,12 @@ boost = dependency( 'boost', - modules : [ 'container', 'regex' ], + modules : [ + 'container', + # Shouldn't list, because can header-only, and Meson currently looks for libs + #'regex', + 'url', + ], include_type : 'system', ) # boost is a public dependency, but not a pkg-config dependency unfortunately, so we diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/store-api.cc new/nix-2.31.2/src/libstore/store-api.cc --- old/nix-2.31.1/src/libstore/store-api.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/store-api.cc 2025-09-17 22:25:38.000000000 +0200 @@ -817,7 +817,13 @@ auto isShorthand = [](const StoreReference & ref) { /* At this point StoreReference **must** be resolved. */ - const auto & specified = std::get<StoreReference::Specified>(ref.variant); + const auto & specified = std::visit( + overloaded{ + [](const StoreReference::Auto &) -> const StoreReference::Specified & { unreachable(); }, + [](const StoreReference::Specified & specified) -> const StoreReference::Specified & { + return specified; + }}, + ref.variant); const auto & scheme = specified.scheme; return (scheme == "local" || scheme == "unix") && specified.authority.empty(); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/store-reference.cc new/nix-2.31.2/src/libstore/store-reference.cc --- old/nix-2.31.1/src/libstore/store-reference.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/store-reference.cc 2025-09-17 22:25:38.000000000 +0200 @@ -1,11 +1,12 @@ -#include <regex> - #include "nix/util/error.hh" +#include "nix/util/split.hh" #include "nix/util/url.hh" #include "nix/store/store-reference.hh" #include "nix/util/file-system.hh" #include "nix/util/util.hh" +#include <boost/url/ipv6_address.hpp> + namespace nix { static bool isNonUriPath(const std::string & spec) @@ -25,6 +26,8 @@ std::visit( overloaded{ [&](const StoreReference::Auto &) { res = "auto"; }, + [&](const StoreReference::Daemon &) { res = "daemon"; }, + [&](const StoreReference::Local &) { res = "local"; }, [&](const StoreReference::Specified & g) { res = g.scheme; res += "://"; @@ -41,6 +44,29 @@ return res; } +namespace { + +struct SchemeAndAuthorityWithPath +{ + std::string_view scheme; + std::string_view authority; +}; + +} // namespace + +/** + * Return the 'scheme' and remove the '://' or ':' separator. + */ +static std::optional<SchemeAndAuthorityWithPath> splitSchemePrefixTo(std::string_view string) +{ + auto scheme = splitPrefixTo(string, ':'); + if (!scheme) + return std::nullopt; + + splitPrefix(string, "//"); + return SchemeAndAuthorityWithPath{.scheme = *scheme, .authority = string}; +} + StoreReference StoreReference::parse(const std::string & uri, const StoreReference::Params & extraParams) { auto params = extraParams; @@ -68,21 +94,17 @@ .params = std::move(params), }; } else if (baseURI == "daemon") { + if (params.empty()) + return {.variant = Daemon{}}; return { - .variant = - Specified{ - .scheme = "unix", - .authority = "", - }, + .variant = Specified{.scheme = "unix", .authority = ""}, .params = std::move(params), }; } else if (baseURI == "local") { + if (params.empty()) + return {.variant = Local{}}; return { - .variant = - Specified{ - .scheme = "local", - .authority = "", - }, + .variant = Specified{.scheme = "local", .authority = ""}, .params = std::move(params), }; } else if (isNonUriPath(baseURI)) { @@ -94,6 +116,32 @@ }, .params = std::move(params), }; + } else if (auto schemeAndAuthority = splitSchemePrefixTo(baseURI)) { + /* Back-compatibility shim to accept unbracketed IPv6 addresses after the scheme. + * Old versions of nix allowed that. Note that this is ambiguous and does not allow + * specifying the port number. For that the address must be bracketed, otherwise it's + * greedily assumed to be the part of the host address. */ + auto authorityString = schemeAndAuthority->authority; + auto userinfo = splitPrefixTo(authorityString, '@'); + auto maybeIpv6 = boost::urls::parse_ipv6_address(authorityString); + if (maybeIpv6) { + std::string fixedAuthority; + if (userinfo) { + fixedAuthority += *userinfo; + fixedAuthority += '@'; + } + fixedAuthority += '['; + fixedAuthority += authorityString; + fixedAuthority += ']'; + return { + .variant = + Specified{ + .scheme = std::string(schemeAndAuthority->scheme), + .authority = fixedAuthority, + }, + .params = std::move(params), + }; + } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/uds-remote-store.cc new/nix-2.31.2/src/libstore/uds-remote-store.cc --- old/nix-2.31.1/src/libstore/uds-remote-store.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/uds-remote-store.cc 2025-09-17 22:25:38.000000000 +0200 @@ -57,15 +57,16 @@ StoreReference UDSRemoteStoreConfig::getReference() const { + /* We specifically return "daemon" here instead of "unix://" or "unix://${path}" + * to be more compatible with older versions of nix. Some tooling out there + * tries hard to parse store references and it might not be able to handle "unix://". */ + if (path == settings.nixDaemonSocketFile) + return {.variant = StoreReference::Daemon{}}; return { .variant = StoreReference::Specified{ .scheme = *uriSchemes().begin(), - // We return the empty string when the path looks like the - // default path, but we could also just return the path - // verbatim always, to be robust to overall config changes - // at the cost of some verbosity. - .authority = path == settings.nixDaemonSocketFile ? "" : path, + .authority = path, }, }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore/unix/build/derivation-builder.cc new/nix-2.31.2/src/libstore/unix/build/derivation-builder.cc --- old/nix-2.31.1/src/libstore/unix/build/derivation-builder.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore/unix/build/derivation-builder.cc 2025-09-17 22:25:38.000000000 +0200 @@ -706,7 +706,7 @@ /* Create a temporary directory where the build will take place. */ - topTmpDir = createTempDir(buildDir, "nix-build-" + std::string(drvPath.name()), 0700); + topTmpDir = createTempDir(buildDir, "nix", 0700); setBuildTmpDir(); assert(!tmpDir.empty()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/data/store-reference/daemon_shorthand.txt new/nix-2.31.2/src/libstore-tests/data/store-reference/daemon_shorthand.txt --- old/nix-2.31.1/src/libstore-tests/data/store-reference/daemon_shorthand.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.31.2/src/libstore-tests/data/store-reference/daemon_shorthand.txt 2025-09-17 22:25:38.000000000 +0200 @@ -0,0 +1 @@ +daemon \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/data/store-reference/local_shorthand_3.txt new/nix-2.31.2/src/libstore-tests/data/store-reference/local_shorthand_3.txt --- old/nix-2.31.1/src/libstore-tests/data/store-reference/local_shorthand_3.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.31.2/src/libstore-tests/data/store-reference/local_shorthand_3.txt 2025-09-17 22:25:38.000000000 +0200 @@ -0,0 +1 @@ +local \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_1.txt new/nix-2.31.2/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_1.txt --- old/nix-2.31.1/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_1.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.31.2/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_1.txt 2025-09-17 22:25:38.000000000 +0200 @@ -0,0 +1 @@ +ssh://::1 \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_2.txt new/nix-2.31.2/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_2.txt --- old/nix-2.31.1/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_2.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.31.2/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_2.txt 2025-09-17 22:25:38.000000000 +0200 @@ -0,0 +1 @@ +ssh://userinfo@fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_3.txt new/nix-2.31.2/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_3.txt --- old/nix-2.31.1/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_3.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/nix-2.31.2/src/libstore-tests/data/store-reference/ssh_unbracketed_ipv6_3.txt 2025-09-17 22:25:38.000000000 +0200 @@ -0,0 +1 @@ +ssh://userinfo@fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e?a=b&c=d \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/local-store.cc new/nix-2.31.2/src/libstore-tests/local-store.cc --- old/nix-2.31.1/src/libstore-tests/local-store.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore-tests/local-store.cc 2025-09-17 22:25:38.000000000 +0200 @@ -33,4 +33,10 @@ EXPECT_EQ(config.rootDir.get(), std::optional{"/foo/bar"}); } +TEST(LocalStore, constructConfig_to_string) +{ + LocalStoreConfig config{"local", "", {}}; + EXPECT_EQ(config.getReference().render(), "local"); +} + } // namespace nix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/store-reference.cc new/nix-2.31.2/src/libstore-tests/store-reference.cc --- old/nix-2.31.1/src/libstore-tests/store-reference.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore-tests/store-reference.cc 2025-09-17 22:25:38.000000000 +0200 @@ -107,6 +107,13 @@ URI_TEST_READ(local_shorthand_2, localExample_2) +URI_TEST( + local_shorthand_3, + (StoreReference{ + .variant = StoreReference::Local{}, + .params = {}, + })) + static StoreReference unixExample{ .variant = StoreReference::Specified{ @@ -134,4 +141,46 @@ .params = {}, })) +URI_TEST( + daemon_shorthand, + (StoreReference{ + .variant = StoreReference::Daemon{}, + .params = {}, + })) + +static StoreReference sshLoopbackIPv6{ + .variant = + StoreReference::Specified{ + .scheme = "ssh", + .authority = "[::1]", + }, +}; + +URI_TEST_READ(ssh_unbracketed_ipv6_1, sshLoopbackIPv6) + +static StoreReference sshIPv6AuthorityWithUserinfo{ + .variant = + StoreReference::Specified{ + .scheme = "ssh", + .authority = "userinfo@[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e]", + }, +}; + +URI_TEST_READ(ssh_unbracketed_ipv6_2, sshIPv6AuthorityWithUserinfo) + +static StoreReference sshIPv6AuthorityWithUserinfoAndParams{ + .variant = + StoreReference::Specified{ + .scheme = "ssh", + .authority = "userinfo@[fea5:23e1:3916:fc24:cb52:2837:2ecb:ea8e]", + }, + .params = + { + {"a", "b"}, + {"c", "d"}, + }, +}; + +URI_TEST_READ(ssh_unbracketed_ipv6_3, sshIPv6AuthorityWithUserinfoAndParams) + } // namespace nix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libstore-tests/uds-remote-store.cc new/nix-2.31.2/src/libstore-tests/uds-remote-store.cc --- old/nix-2.31.1/src/libstore-tests/uds-remote-store.cc 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libstore-tests/uds-remote-store.cc 2025-09-17 22:25:38.000000000 +0200 @@ -16,4 +16,10 @@ EXPECT_THROW(UDSRemoteStoreConfig("http", "/tmp/socket", {}), UsageError); } +TEST(UDSRemoteStore, constructConfig_to_string) +{ + UDSRemoteStoreConfig config{"unix", "", {}}; + EXPECT_EQ(config.getReference().render(), "daemon"); +} + } // namespace nix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libutil/meson.build new/nix-2.31.2/src/libutil/meson.build --- old/nix-2.31.1/src/libutil/meson.build 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libutil/meson.build 2025-09-17 22:25:38.000000000 +0200 @@ -57,7 +57,12 @@ boost = dependency( 'boost', - modules : [ 'context', 'coroutine', 'iostreams', 'url' ], + modules : [ + 'context', + 'coroutine', + 'iostreams', + 'url', + ], include_type : 'system', version : '>=1.82.0', ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/src/libutil/unix/include/nix/util/monitor-fd.hh new/nix-2.31.2/src/libutil/unix/include/nix/util/monitor-fd.hh --- old/nix-2.31.1/src/libutil/unix/include/nix/util/monitor-fd.hh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/src/libutil/unix/include/nix/util/monitor-fd.hh 2025-09-17 22:25:38.000000000 +0200 @@ -2,15 +2,18 @@ ///@file #include <thread> -#include <atomic> +#include <cassert> -#include <cstdlib> #include <poll.h> -#include <sys/types.h> -#include <unistd.h> -#include <signal.h> +#include <errno.h> + +#ifdef __APPLE__ +# include <sys/types.h> +# include <sys/event.h> +#endif #include "nix/util/signals.hh" +#include "nix/util/file-descriptor.hh" namespace nix { @@ -20,111 +23,113 @@ std::thread thread; Pipe notifyPipe; -public: - MonitorFdHup(int fd) - { - notifyPipe.create(); - thread = std::thread([this, fd]() { - while (true) { - // There is a POSIX violation on macOS: you have to listen for - // at least POLLHUP to receive HUP events for a FD. POSIX says - // this is not so, and you should just receive them regardless. - // However, as of our testing on macOS 14.5, the events do not - // get delivered if in the all-bits-unset case, but do get - // delivered if `POLLHUP` is set. - // - // This bug filed as rdar://37537852 - // (https://openradar.appspot.com/37537852). - // - // macOS's own man page - // (https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/poll.2.html) - // additionally says that `POLLHUP` is ignored as an input. It - // seems the likely order of events here was - // - // 1. macOS did not follow the POSIX spec - // - // 2. Somebody ninja-fixed this other spec violation to make - // sure `POLLHUP` was not forgotten about, even though they - // "fixed" this issue in a spec-non-compliant way. Whatever, - // we'll use the fix. - // - // Relevant code, current version, which shows the : - // https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/sys_generic.c#L1751-L1758 - // - // The `POLLHUP` detection was added in - // https://github.com/apple-oss-distributions/xnu/commit/e13b1fa57645afc8a7b2e7d868fe9845c6b08c40#diff-a5aa0b0e7f4d866ca417f60702689fc797e9cdfe33b601b05ccf43086c35d395R1468 - // That means added in 2007 or earlier. Should be good enough - // for us. - short hangup_events = -#ifdef __APPLE__ - POLLHUP -#else - 0 -#endif - ; + void runThread(int watchFd, int notifyFd); - /* Wait indefinitely until a POLLHUP occurs. */ - constexpr size_t num_fds = 2; - struct pollfd fds[num_fds] = { - { - .fd = fd, - .events = hangup_events, - }, - { - .fd = notifyPipe.readSide.get(), - .events = hangup_events, - }, - }; - - auto count = poll(fds, num_fds, -1); - if (count == -1) { - if (errno == EINTR || errno == EAGAIN) - continue; - throw SysError("failed to poll() in MonitorFdHup"); - } - /* This shouldn't happen, but can on macOS due to a bug. - See rdar://37550628. - - This may eventually need a delay or further - coordination with the main thread if spinning proves - too harmful. - */ - if (count == 0) - continue; - if (fds[0].revents & POLLHUP) { - unix::triggerInterrupt(); - break; - } - if (fds[1].revents & POLLHUP) { - break; - } - // On macOS, (jade thinks that) it is possible (although not - // observed on macOS 14.5) that in some limited cases on buggy - // kernel versions, all the non-POLLHUP events for the socket - // get delivered. - // - // We could sleep to avoid pointlessly spinning a thread on - // those, but this opens up a different problem, which is that - // if do sleep, it will be longer before the daemon fork for a - // client exits. Imagine a sequential shell script, running Nix - // commands, each of which talk to the daemon. If the previous - // command registered a temp root, exits, and then the next - // command issues a delete request before the temp root is - // cleaned up, that delete request might fail. - // - // Not sleeping doesn't actually fix the race condition --- we - // would need to block on the old connections' tempt roots being - // cleaned up in in the new connection --- but it does make it - // much less likely. - } - }); - }; +public: + MonitorFdHup(int fd); ~MonitorFdHup() { + // Close the write side to signal termination via POLLHUP notifyPipe.writeSide.close(); thread.join(); } }; +#ifdef __APPLE__ +/* This custom kqueue usage exists because Apple's poll implementation is + * broken and loses event subscriptions if EVFILT_READ fires without matching + * the requested `events` in the pollfd. + * + * We use EVFILT_READ, which causes some spurious wakeups (at most one per write + * from the client, in addition to the socket lifecycle events), because the + * alternate API, EVFILT_SOCK, doesn't work on pipes, which this is also used + * to monitor in certain situations. + * + * See (EVFILT_SOCK): + * https://github.com/netty/netty/blob/64bd2f4eb62c2fb906bc443a2aabf894c8b7dce9/transport-classes-kqueue/src/main/java/io/netty/channel/kqueue/AbstractKQueueChannel.java#L434 + * + * See: https://git.lix.systems/lix-project/lix/issues/729 + * Apple bug in poll(2): FB17447257, available at https://openradar.appspot.com/FB17447257 + */ +inline void MonitorFdHup::runThread(int watchFd, int notifyFd) +{ + int kqResult = kqueue(); + if (kqResult < 0) { + throw SysError("MonitorFdHup kqueue"); + } + AutoCloseFD kq{kqResult}; + + std::array<struct kevent, 2> kevs; + + // kj uses EVFILT_WRITE for this, but it seems that it causes more spurious + // wakeups in our case of doing blocking IO from another thread compared to + // EVFILT_READ. + // + // EVFILT_WRITE and EVFILT_READ (for sockets at least, where I am familiar + // with the internals) both go through a common filter which catches EOFs + // and generates spurious wakeups for either readable/writable events. + EV_SET(&kevs[0], watchFd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, nullptr); + EV_SET(&kevs[1], notifyFd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, nullptr); + + int result = kevent(kq.get(), kevs.data(), kevs.size(), nullptr, 0, nullptr); + if (result < 0) { + throw SysError("MonitorFdHup kevent add"); + } + + while (true) { + struct kevent event; + int numEvents = kevent(kq.get(), nullptr, 0, &event, 1, nullptr); + if (numEvents < 0) { + throw SysError("MonitorFdHup kevent watch"); + } + + if (numEvents > 0 && (event.flags & EV_EOF)) { + if (event.ident == uintptr_t(watchFd)) { + unix::triggerInterrupt(); + } + // Either watched fd or notify fd closed, exit + return; + } + } +} +#else +inline void MonitorFdHup::runThread(int watchFd, int notifyFd) +{ + while (true) { + struct pollfd fds[2]; + fds[0].fd = watchFd; + fds[0].events = 0; // POSIX: POLLHUP is always reported + fds[1].fd = notifyFd; + fds[1].events = 0; + + auto count = poll(fds, 2, -1); + if (count == -1) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } else { + throw SysError("in MonitorFdHup poll()"); + } + } + + if (fds[0].revents & POLLHUP) { + unix::triggerInterrupt(); + break; + } + + if (fds[1].revents & POLLHUP) { + // Notify pipe closed, exit thread + break; + } + } +} +#endif + +inline MonitorFdHup::MonitorFdHup(int fd) +{ + notifyPipe.create(); + int notifyFd = notifyPipe.readSide.get(); + thread = std::thread([this, fd, notifyFd]() { this->runThread(fd, notifyFd); }); +}; + } // namespace nix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/tests/functional/check.sh new/nix-2.31.2/tests/functional/check.sh --- old/nix-2.31.1/tests/functional/check.sh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/tests/functional/check.sh 2025-09-17 22:25:38.000000000 +0200 @@ -52,10 +52,10 @@ nix-build check.nix -A failed --argstr checkBuildId "$checkBuildId" \ --no-out-link --keep-failed --option build-dir "$TEST_ROOT/custom-build-dir" 2> "$TEST_ROOT/log" || status=$? [ "$status" = "100" ] - [[ 1 == "$(count "$customBuildDir/nix-build-"*)" ]] - local buildDir=("$customBuildDir/nix-build-"*) + [[ 1 == "$(count "$customBuildDir/nix-"*)" ]] + local buildDir=("$customBuildDir/nix-"*) if [[ "${#buildDir[@]}" -ne 1 ]]; then - echo "expected one nix-build-* directory, got: ${buildDir[*]}" >&2 + echo "expected one nix-* directory, got: ${buildDir[*]}" >&2 exit 1 fi if [[ -e ${buildDir[*]}/build ]]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/tests/functional/flakes/flakes.sh new/nix-2.31.2/tests/functional/flakes/flakes.sh --- old/nix-2.31.1/tests/functional/flakes/flakes.sh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/tests/functional/flakes/flakes.sh 2025-09-17 22:25:38.000000000 +0200 @@ -470,3 +470,33 @@ EOF [[ "$(nix flake metadata --json "$flake3Dir" | jq -r .locks.nodes.flake1.locked.rev)" = $prevFlake1Rev ]] + +baseDir=$TEST_ROOT/$RANDOM +subdirFlakeDir1=$baseDir/foo1 +mkdir -p "$subdirFlakeDir1" + +writeSimpleFlake "$baseDir" + +cat > "$subdirFlakeDir1"/flake.nix <<EOF +{ + outputs = inputs: { + shouldBeOne = 1; + }; +} +EOF + +nix registry add --registry "$registry" flake2 "path:$baseDir?dir=foo1" +[[ "$(nix eval --flake-registry "$registry" flake2#shouldBeOne)" = 1 ]] + +subdirFlakeDir2=$baseDir/foo2 +mkdir -p "$subdirFlakeDir2" +cat > "$subdirFlakeDir2"/flake.nix <<EOF +{ + inputs.foo1.url = "path:$baseDir?dir=foo1"; + + outputs = inputs: { }; +} +EOF + +# Regression test for https://github.com/NixOS/nix/issues/13918 +[[ "$(nix eval --inputs-from "$subdirFlakeDir2" foo1#shouldBeOne)" = 1 ]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/tests/functional/store-info.sh new/nix-2.31.2/tests/functional/store-info.sh --- old/nix-2.31.1/tests/functional/store-info.sh 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/tests/functional/store-info.sh 2025-09-17 22:25:38.000000000 +0200 @@ -13,14 +13,20 @@ # Need to actually ask Nix in this case echo "$defaultStore" ;; + local | 'local://' ) + echo 'local' + ;; + daemon | 'unix://' ) + echo 'daemon' + ;; 'local://'* ) # To not be captured by next pattern echo "$url" ;; - local | 'local?'* ) + 'local?'* ) echo "local://${url#local}" ;; - daemon | 'daemon?'* ) + 'daemon?'* ) echo "unix://${url#daemon}" ;; * ) @@ -38,13 +44,13 @@ # Test cases for `normalize_nix_store_url` itself # Normalize local store -[[ "$(normalize_nix_store_url "local://")" = "local://" ]] -[[ "$(normalize_nix_store_url "local")" = "local://" ]] +[[ "$(normalize_nix_store_url "local://")" = "local" ]] +[[ "$(normalize_nix_store_url "local")" = "local" ]] [[ "$(normalize_nix_store_url "local?foo=bar")" = "local://?foo=bar" ]] # Normalize unix domain socket remote store -[[ "$(normalize_nix_store_url "unix://")" = "unix://" ]] -[[ "$(normalize_nix_store_url "daemon")" = "unix://" ]] +[[ "$(normalize_nix_store_url "unix://")" = "daemon" ]] +[[ "$(normalize_nix_store_url "daemon")" = "daemon" ]] [[ "$(normalize_nix_store_url "daemon?x=y")" = "unix://?x=y" ]] # otherwise unchanged diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/tests/nixos/authorization.nix new/nix-2.31.2/tests/nixos/authorization.nix --- old/nix-2.31.1/tests/nixos/authorization.nix 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/tests/nixos/authorization.nix 2025-09-17 22:25:38.000000000 +0200 @@ -84,7 +84,7 @@ su --login mallory -c ' nix-store --generate-binary-cache-key cache1.example.org sk1 pk1 (! nix store sign --key-file sk1 ${pathFour} 2>&1)' | tee diag 1>&2 - grep -F "cannot open connection to remote store 'unix://'" diag + grep -F "cannot open connection to remote store 'daemon'" diag """) machine.succeed(""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.31.1/tests/nixos/user-sandboxing/default.nix new/nix-2.31.2/tests/nixos/user-sandboxing/default.nix --- old/nix-2.31.1/tests/nixos/user-sandboxing/default.nix 2025-09-01 09:52:24.000000000 +0200 +++ new/nix-2.31.2/tests/nixos/user-sandboxing/default.nix 2025-09-17 22:25:38.000000000 +0200 @@ -104,8 +104,8 @@ # Wait for the build to be ready # This is OK because it runs as root, so we can access everything - machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-build-open-build-dir.drv-*/build/syncPoint") - dir = machine.succeed("ls -d /nix/var/nix/builds/nix-build-open-build-dir.drv-*").strip() + machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-*/build/syncPoint") + dir = machine.succeed("ls -d /nix/var/nix/builds/nix-*").strip() # But Alice shouldn't be able to access the build directory machine.fail(f"su alice -c 'ls {dir}/build'") @@ -125,8 +125,8 @@ args = [ (builtins.storePath "${create-hello-world}") ]; }' >&2 & """.strip()) - machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-build-innocent.drv-*/build/syncPoint") - dir = machine.succeed("ls -d /nix/var/nix/builds/nix-build-innocent.drv-*").strip() + machine.wait_until_succeeds("stat /nix/var/nix/builds/nix-*/build/syncPoint") + dir = machine.succeed("ls -d /nix/var/nix/builds/nix-*").strip() # The build ran as `nixbld1` (which is the only build user on the # machine), but a process running as `nixbld1` outside the sandbox
