From b644e5750e9a590e7ea64cc0c4dbda9afaf5643f Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Fri, 15 Nov 2024 10:45:29 +1100 Subject: [PATCH 01/22] Remove broken stack size logic from Windows The API only changes the stack size once there's already a stack overflow exception. Pretty useless. --- src/libutil/current-process.cc | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/libutil/current-process.cc b/src/libutil/current-process.cc index ac01f441e..46e72b63a 100644 --- a/src/libutil/current-process.cc +++ b/src/libutil/current-process.cc @@ -19,10 +19,6 @@ # include "namespaces.hh" #endif -#ifndef _WIN32 -# include -#endif - namespace nix { unsigned int getMaxCPU() @@ -77,29 +73,6 @@ void setStackSize(size_t stackSize) ); } } - #else - ULONG_PTR stackLow, stackHigh; - GetCurrentThreadStackLimits(&stackLow, &stackHigh); - ULONG maxStackSize = stackHigh - stackLow; - ULONG currStackSize = 0; - // This retrieves the current promised stack size - SetThreadStackGuarantee(&currStackSize); - if (currStackSize < stackSize) { - savedStackSize = currStackSize; - ULONG newStackSize = std::min(static_cast(stackSize), maxStackSize); - if (SetThreadStackGuarantee(&newStackSize) == 0) { - logger->log( - lvlError, - HintFmt( - "Failed to increase stack size from %1% to %2% (maximum allowed stack size: %3%): %4%", - savedStackSize, - stackSize, - maxStackSize, - std::to_string(GetLastError()) - ).str() - ); - } - } #endif } From 3bd7fa3bb4e950dcb256fff3c923dbea7d1fb349 Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Tue, 12 Nov 2024 20:47:31 +1100 Subject: [PATCH 02/22] local-store: fix infinite loop on Windows Also switch to std::filesystem. --- src/libstore/local-store.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index eafdac0cd..f95291786 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -212,16 +212,15 @@ LocalStore::LocalStore( /* Ensure that the store and its parents are not symlinks. */ if (!settings.allowSymlinkedStore) { - Path path = realStoreDir; - struct stat st; - while (path != "/") { - st = lstat(path); - if (S_ISLNK(st.st_mode)) + std::filesystem::path path = realStoreDir.get(); + std::filesystem::path root = path.root_path(); + while (path != root) { + if (std::filesystem::is_symlink(path)) throw Error( "the path '%1%' is a symlink; " "this is not allowed for the Nix store and its parent directories", path); - path = dirOf(path); + path = path.parent_path(); } } From 666d656593e135dbe2f84a7db0309e479ecadaa5 Mon Sep 17 00:00:00 2001 From: Illia Bobyr Date: Thu, 16 Jan 2025 00:58:29 -0800 Subject: [PATCH 03/22] nix-profile-daemon.fish: fmt `nix-profile.fish` and part of `nix-profile-daemon.fish` use 4 space indentation. Which is also the indentation that the fish shell documentation is using. Reformatting a chunk of `nix-profile-daemon.fish` from 2 space indentation to 4 space indentation for consistency. --- scripts/nix-profile-daemon.fish.in | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/nix-profile-daemon.fish.in b/scripts/nix-profile-daemon.fish.in index 346dce5dd..ac2ecdeee 100644 --- a/scripts/nix-profile-daemon.fish.in +++ b/scripts/nix-profile-daemon.fish.in @@ -12,7 +12,7 @@ end # Only execute this file once per shell. if test -n "$__ETC_PROFILE_NIX_SOURCED" - exit + exit end set __ETC_PROFILE_NIX_SOURCED 1 @@ -29,26 +29,26 @@ end # Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work. if test -n "$NIX_SSL_CERT_FILE" - : # Allow users to override the NIX_SSL_CERT_FILE + : # Allow users to override the NIX_SSL_CERT_FILE else if test -e /etc/ssl/certs/ca-certificates.crt # NixOS, Ubuntu, Debian, Gentoo, Arch - set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt + set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt else if test -e /etc/ssl/ca-bundle.pem # openSUSE Tumbleweed - set --export NIX_SSL_CERT_FILE /etc/ssl/ca-bundle.pem + set --export NIX_SSL_CERT_FILE /etc/ssl/ca-bundle.pem else if test -e /etc/ssl/certs/ca-bundle.crt # Old NixOS - set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-bundle.crt + set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-bundle.crt else if test -e /etc/pki/tls/certs/ca-bundle.crt # Fedora, CentOS - set --export NIX_SSL_CERT_FILE /etc/pki/tls/certs/ca-bundle.crt + set --export NIX_SSL_CERT_FILE /etc/pki/tls/certs/ca-bundle.crt else if test -e "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" # fall back to cacert in Nix profile - set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" + set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" else if test -e "$NIX_LINK/etc/ca-bundle.crt" # old cacert in Nix profile - set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ca-bundle.crt" + set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ca-bundle.crt" else - # Fall back to what is in the nix profiles, favouring whatever is defined last. - for i in (string split ' ' $NIX_PROFILES) - if test -e "$i/etc/ssl/certs/ca-bundle.crt" - set --export NIX_SSL_CERT_FILE "$i/etc/ssl/certs/ca-bundle.crt" + # Fall back to what is in the nix profiles, favouring whatever is defined last. + for i in (string split ' ' $NIX_PROFILES) + if test -e "$i/etc/ssl/certs/ca-bundle.crt" + set --export NIX_SSL_CERT_FILE "$i/etc/ssl/certs/ca-bundle.crt" + end end - end end add_path "@localstatedir@/nix/profiles/default/bin" From b36637c8f7ab7a2b93c6eae1139ea1c672700186 Mon Sep 17 00:00:00 2001 From: Illia Bobyr Date: Mon, 13 Jan 2025 18:08:41 -0800 Subject: [PATCH 04/22] nix-profile{,-daemon}.fish: Do not source twice In order for the script not be sourced multiple times by the same shell instance, `__ETC_PROFILE_NIX_SOURCED` needs to be set with a `--global` flag. Both files are almost identical. And style differences make it harder to see what is actually different and keep them in sync, when it is required. --- scripts/nix-profile-daemon.fish.in | 20 ++++--- scripts/nix-profile.fish.in | 91 +++++++++++++++++------------- 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/scripts/nix-profile-daemon.fish.in b/scripts/nix-profile-daemon.fish.in index ac2ecdeee..3d193412a 100644 --- a/scripts/nix-profile-daemon.fish.in +++ b/scripts/nix-profile-daemon.fish.in @@ -1,3 +1,13 @@ +# Only execute this file once per shell. +if test -z "$HOME" || \ + test -n "$__ETC_PROFILE_NIX_SOURCED" + exit +end + +set --global __ETC_PROFILE_NIX_SOURCED 1 + +# Local helpers + function add_path --argument-names new_path if type -q fish_add_path # fish 3.2.0 or newer @@ -10,13 +20,7 @@ function add_path --argument-names new_path end end -# Only execute this file once per shell. -if test -n "$__ETC_PROFILE_NIX_SOURCED" - exit -end - -set __ETC_PROFILE_NIX_SOURCED 1 - +# Main configuration set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile" # Populate bash completions, .desktop files, etc @@ -54,4 +58,6 @@ end add_path "@localstatedir@/nix/profiles/default/bin" add_path "$HOME/.nix-profile/bin" +# Cleanup + functions -e add_path diff --git a/scripts/nix-profile.fish.in b/scripts/nix-profile.fish.in index 619df52b8..dd2fbe209 100644 --- a/scripts/nix-profile.fish.in +++ b/scripts/nix-profile.fish.in @@ -1,3 +1,13 @@ +# Only execute this file once per shell. +if test -z "$HOME" || test -z "$USER" || \ + test -n "$__ETC_PROFILE_NIX_SOURCED" + exit +end + +set --global __ETC_PROFILE_NIX_SOURCED 1 + +# Local helpers + function add_path --argument-names new_path if type -q fish_add_path # fish 3.2.0 or newer @@ -10,50 +20,51 @@ function add_path --argument-names new_path end end -if test -n "$HOME" && test -n "$USER" +# Main configuration - # Set up the per-user profile. +# Set up the per-user profile. - set NIX_LINK $HOME/.nix-profile +set NIX_LINK $HOME/.nix-profile - # Set up environment. - # This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix - set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile" +# Set up environment. +# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix +set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile" - # Populate bash completions, .desktop files, etc - if test -z "$XDG_DATA_DIRS" - # According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default - set --export XDG_DATA_DIRS "/usr/local/share:/usr/share:$NIX_LINK/share:/nix/var/nix/profiles/default/share" - else - set --export XDG_DATA_DIRS "$XDG_DATA_DIRS:$NIX_LINK/share:/nix/var/nix/profiles/default/share" - end - - # Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work. - if test -n "$NIX_SSH_CERT_FILE" - : # Allow users to override the NIX_SSL_CERT_FILE - else if test -e /etc/ssl/certs/ca-certificates.crt # NixOS, Ubuntu, Debian, Gentoo, Arch - set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt - else if test -e /etc/ssl/ca-bundle.pem # openSUSE Tumbleweed - set --export NIX_SSL_CERT_FILE /etc/ssl/ca-bundle.pem - else if test -e /etc/ssl/certs/ca-bundle.crt # Old NixOS - set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-bundle.crt - else if test -e /etc/pki/tls/certs/ca-bundle.crt # Fedora, CentOS - set --export NIX_SSL_CERT_FILE /etc/pki/tls/certs/ca-bundle.crt - else if test -e "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" # fall back to cacert in Nix profile - set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" - else if test -e "$NIX_LINK/etc/ca-bundle.crt" # old cacert in Nix profile - set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ca-bundle.crt" - end - - # Only use MANPATH if it is already set. In general `man` will just simply - # pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin` - # which is in the $PATH. For more info, run `manpath -d`. - if set --query MANPATH - set --export --prepend --path MANPATH "$NIX_LINK/share/man" - end - - add_path "$NIX_LINK/bin" - set --erase NIX_LINK +# Populate bash completions, .desktop files, etc +if test -z "$XDG_DATA_DIRS" + # According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default + set --export XDG_DATA_DIRS "/usr/local/share:/usr/share:$NIX_LINK/share:/nix/var/nix/profiles/default/share" +else + set --export XDG_DATA_DIRS "$XDG_DATA_DIRS:$NIX_LINK/share:/nix/var/nix/profiles/default/share" end +# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work. +if test -n "$NIX_SSH_CERT_FILE" + : # Allow users to override the NIX_SSL_CERT_FILE +else if test -e /etc/ssl/certs/ca-certificates.crt # NixOS, Ubuntu, Debian, Gentoo, Arch + set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt +else if test -e /etc/ssl/ca-bundle.pem # openSUSE Tumbleweed + set --export NIX_SSL_CERT_FILE /etc/ssl/ca-bundle.pem +else if test -e /etc/ssl/certs/ca-bundle.crt # Old NixOS + set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-bundle.crt +else if test -e /etc/pki/tls/certs/ca-bundle.crt # Fedora, CentOS + set --export NIX_SSL_CERT_FILE /etc/pki/tls/certs/ca-bundle.crt +else if test -e "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" # fall back to cacert in Nix profile + set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ssl/certs/ca-bundle.crt" +else if test -e "$NIX_LINK/etc/ca-bundle.crt" # old cacert in Nix profile + set --export NIX_SSL_CERT_FILE "$NIX_LINK/etc/ca-bundle.crt" +end + +# Only use MANPATH if it is already set. In general `man` will just simply +# pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin` +# which is in the $PATH. For more info, run `manpath -d`. +if set --query MANPATH + set --export --prepend --path MANPATH "$NIX_LINK/share/man" +end + +add_path "$NIX_LINK/bin" +set --erase NIX_LINK + +# Cleanup + functions -e add_path From 7465fbe9264e46c556b456226e8fb980fcfd7e66 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 27 Jan 2025 12:32:46 +0100 Subject: [PATCH 05/22] refactor: Extract EvalState::realiseString --- src/libexpr-c/nix_api_value.cc | 6 +----- src/libexpr/eval.hh | 9 +++++++++ src/libexpr/primops.cc | 9 +++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/libexpr-c/nix_api_value.cc b/src/libexpr-c/nix_api_value.cc index bae078d31..448f4a58a 100644 --- a/src/libexpr-c/nix_api_value.cc +++ b/src/libexpr-c/nix_api_value.cc @@ -613,12 +613,8 @@ nix_realised_string * nix_string_realise(nix_c_context * context, EvalState * st context->last_err_code = NIX_OK; try { auto & v = check_value_in(value); - nix::NixStringContext stringContext; - auto rawStr = state->state.coerceToString(nix::noPos, v, stringContext, "while realising a string").toOwned(); nix::StorePathSet storePaths; - auto rewrites = state->state.realiseContext(stringContext, &storePaths); - - auto s = nix::rewriteStrings(rawStr, rewrites); + auto s = state->state.realiseString(v, &storePaths, isIFD); // Convert to the C API StorePath type and convert to vector for index-based access std::vector vec; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 84b7d823c..767578343 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -820,6 +820,15 @@ public: */ [[nodiscard]] StringMap realiseContext(const NixStringContext & context, StorePathSet * maybePaths = nullptr, bool isIFD = true); + /** + * Realise the given string with context, and return the string with outputs instead of downstream output placeholders. + * @param[in] str the string to realise + * @param[out] paths all referenced store paths will be added to this set + * @return the realised string + * @throw EvalError if the value is not a string, path or derivation (see `coerceToString`) + */ + std::string realiseString(Value & str, StorePathSet * storePathsOutMaybe, bool isIFD = true, const PosIdx pos = noPos); + /* Call the binary path filter predicate used builtins.path etc. */ bool callPathFilter( Value * filterFun, diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index a0e2753b5..e6f6f1dda 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -47,6 +47,15 @@ static inline Value * mkString(EvalState & state, const std::csub_match & match) return v; } +std::string EvalState::realiseString(Value & s, StorePathSet * storePathsOutMaybe, bool isIFD, const PosIdx pos) +{ + nix::NixStringContext stringContext; + auto rawStr = coerceToString(pos, s, stringContext, "while realising a string").toOwned(); + auto rewrites = realiseContext(stringContext, storePathsOutMaybe, isIFD); + + return nix::rewriteStrings(rawStr, rewrites); +} + StringMap EvalState::realiseContext(const NixStringContext & context, StorePathSet * maybePathsOut, bool isIFD) { std::vector drvs; From 0d7418b4feebcfb3e0e66798398d3ecf618c1e58 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 27 Jan 2025 14:25:35 +0100 Subject: [PATCH 06/22] packages.default: Add meta.mainProgram --- packaging/everything.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/everything.nix b/packaging/everything.nix index 2b47c31bb..0974a34df 100644 --- a/packaging/everything.nix +++ b/packaging/everything.nix @@ -93,6 +93,7 @@ let libs = throw "`nix.dev.libs` is not meant to be used; use `nix.libs` instead."; }; meta = { + mainProgram = "nix"; pkgConfigModules = [ "nix-cmd" "nix-expr" From 850329dea59358db6e8ea572d769eb706715c508 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 27 Jan 2025 14:26:05 +0100 Subject: [PATCH 07/22] packages.nix-cli: Add meta.mainProgram --- src/nix/package.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nix/package.nix b/src/nix/package.nix index 89c52c3bb..6e59adc38 100644 --- a/src/nix/package.nix +++ b/src/nix/package.nix @@ -103,6 +103,7 @@ mkMesonExecutable (finalAttrs: { ]; meta = { + mainProgram = "nix"; platforms = lib.platforms.unix ++ lib.platforms.windows; }; From a5de2dd27457a9dd3d121b402b9445ef86aad262 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 24 Jan 2025 16:39:56 +0100 Subject: [PATCH 08/22] tests/functional/characterisation/framework: Log to stderr It seems that `meson test --print-errorlogs` only captures stderr, so this makes it forward the logs as intended. We might want to redirect stdout in our common setup script instead. --- .../functional/characterisation/framework.sh | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/tests/functional/characterisation/framework.sh b/tests/functional/characterisation/framework.sh index 5ca125ab5..d2c2155db 100644 --- a/tests/functional/characterisation/framework.sh +++ b/tests/functional/characterisation/framework.sh @@ -1,5 +1,7 @@ # shellcheck shell=bash +badTestNames=() + # Golden test support # # Test that the output of the given test matches what is expected. If @@ -18,10 +20,11 @@ function diffAndAcceptInner() { fi # Diff so we get a nice message - if ! diff --color=always --unified "$expectedOrEmpty" "$got"; then - echo "FAIL: evaluation result of $testName not as expected" + if ! diff >&2 --color=always --unified "$expectedOrEmpty" "$got"; then + echo >&2 "FAIL: evaluation result of $testName not as expected" # shellcheck disable=SC2034 badDiff=1 + badTestNames+=("$testName") fi # Update expected if `_NIX_TEST_ACCEPT` is non-empty. @@ -42,14 +45,14 @@ function characterisationTestExit() { if test -n "${_NIX_TEST_ACCEPT-}"; then if (( "$badDiff" )); then set +x - echo 'Output did mot match, but accepted output as the persisted expected output.' - echo 'That means the next time the tests are run, they should pass.' + echo >&2 'Output did mot match, but accepted output as the persisted expected output.' + echo >&2 'That means the next time the tests are run, they should pass.' set -x else set +x - echo 'NOTE: Environment variable _NIX_TEST_ACCEPT is defined,' - echo 'indicating the unexpected output should be accepted as the expected output going forward,' - echo 'but no tests had unexpected output so there was no expected output to update.' + echo >&2 'NOTE: Environment variable _NIX_TEST_ACCEPT is defined,' + echo >&2 'indicating the unexpected output should be accepted as the expected output going forward,' + echo >&2 'but no tests had unexpected output so there was no expected output to update.' set -x fi if (( "$badExitCode" )); then @@ -60,16 +63,21 @@ function characterisationTestExit() { else if (( "$badDiff" )); then set +x - echo '' - echo 'You can rerun this test with:' - echo '' - echo " _NIX_TEST_ACCEPT=1 make tests/functional/${TEST_NAME}.sh.test" - echo '' - echo 'to regenerate the files containing the expected output,' - echo 'and then view the git diff to decide whether a change is' - echo 'good/intentional or bad/unintentional.' - echo 'If the diff contains arbitrary or impure information,' - echo 'please improve the normalization that the test applies to the output.' + echo >&2 '' + echo >&2 'The following tests had unexpected output:' + for testName in "${badTestNames[@]}"; do + echo >&2 " $testName" + done + echo >&2 '' + echo >&2 'You can rerun this test with:' + echo >&2 '' + echo >&2 " _NIX_TEST_ACCEPT=1 meson test ${TEST_NAME}" + echo >&2 '' + echo >&2 'to regenerate the files containing the expected output,' + echo >&2 'and then view the git diff to decide whether a change is' + echo >&2 'good/intentional or bad/unintentional.' + echo >&2 'If the diff contains arbitrary or impure information,' + echo >&2 'please improve the normalization that the test applies to the output.' set -x fi exit $(( "$badExitCode" + "$badDiff" )) From fa87ad6a7ca97c4bd45ddec284be4209495bb1eb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 29 Jan 2025 15:34:49 +0100 Subject: [PATCH 09/22] Fix shellcheck warnings --- tests/functional/git-hashing/fixed.sh | 2 ++ tests/functional/help.sh | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/functional/git-hashing/fixed.sh b/tests/functional/git-hashing/fixed.sh index 1962472a8..f33d95cfa 100644 --- a/tests/functional/git-hashing/fixed.sh +++ b/tests/functional/git-hashing/fixed.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + source common.sh # Store layer needs bugfix diff --git a/tests/functional/help.sh b/tests/functional/help.sh index 2d64c465d..efacaba59 100755 --- a/tests/functional/help.sh +++ b/tests/functional/help.sh @@ -25,7 +25,7 @@ done # FIXME: we don't know whether we built the manpages, so we can't # reliably test them here. -exit 0 +if false; then # test help output @@ -74,3 +74,5 @@ nix-daemon --help nix-hash --help nix-instantiate --help nix-prefetch-url --help + +fi From 102d90ebf07b1f268a3551daf5457131ae063d4a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 30 Jan 2025 11:27:24 +0100 Subject: [PATCH 10/22] Fix duplicate setPathDisplay() Fixes messages like 'copying /tmp/repo/tmp/repo to the store'. The PosixSourceAccessor already sets the prefix. Setting the prefix twice shouldn't be a problem, but GitRepoImpl::getAccessor() returns a wrapped accessor so it's not actually idempotent. --- src/libfetchers/git.cc | 2 -- tests/functional/fetchGit.sh | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index b411e112f..e8698709a 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -737,8 +737,6 @@ struct GitInputScheme : InputScheme exportIgnore, makeNotAllowedError(repoInfo.locationToArg())); - accessor->setPathDisplay(repoInfo.locationToArg()); - /* If the repo has submodules, return a mounted input accessor consisting of the accessor for the top-level repo and the accessors for the submodule workdirs. */ diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 78925b5cd..f3eda54dc 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -37,6 +37,7 @@ nix-instantiate --eval -E "builtins.readFile ((builtins.fetchGit file://$TEST_RO # Fetch a worktree. unset _NIX_FORCE_HTTP +expectStderr 0 nix eval -vvvv --impure --raw --expr "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath" | grepQuiet "copying '$TEST_ROOT/worktree/' to the store" path0=$(nix eval --impure --raw --expr "(builtins.fetchGit file://$TEST_ROOT/worktree).outPath") path0_=$(nix eval --impure --raw --expr "(builtins.fetchTree { type = \"git\"; url = file://$TEST_ROOT/worktree; }).outPath") [[ $path0 = $path0_ ]] From 3032512425a09fc58f2d658442043894e0aab256 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 30 Jan 2025 12:41:02 +0100 Subject: [PATCH 11/22] =?UTF-8?q?GitExportIgnoreSourceAccessor:=20Don't=20?= =?UTF-8?q?show=20=C2=ABunknown=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In general we should set the path display prefix on the inner accessor, so we now pass the display prefix to getAccessor(). --- src/libfetchers/git-utils.cc | 21 +++++++++++++-------- src/libfetchers/git-utils.hh | 5 ++++- src/libfetchers/git.cc | 4 +--- src/libfetchers/github.cc | 7 ++++--- src/libfetchers/tarball.cc | 12 +++++++----- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/libfetchers/git-utils.cc b/src/libfetchers/git-utils.cc index 6a75daf61..a6b13fb31 100644 --- a/src/libfetchers/git-utils.cc +++ b/src/libfetchers/git-utils.cc @@ -508,7 +508,10 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this */ ref getRawAccessor(const Hash & rev); - ref getAccessor(const Hash & rev, bool exportIgnore) override; + ref getAccessor( + const Hash & rev, + bool exportIgnore, + std::string displayPrefix) override; ref getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError e) override; @@ -627,7 +630,7 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this Hash treeHashToNarHash(const Hash & treeHash) override { - auto accessor = getAccessor(treeHash, false); + auto accessor = getAccessor(treeHash, false, ""); fetchers::Cache::Key cacheKey{"treeHashToNarHash", {{"treeHash", treeHash.gitRev()}}}; @@ -1194,16 +1197,18 @@ ref GitRepoImpl::getRawAccessor(const Hash & rev) return make_ref(self, rev); } -ref GitRepoImpl::getAccessor(const Hash & rev, bool exportIgnore) +ref GitRepoImpl::getAccessor( + const Hash & rev, + bool exportIgnore, + std::string displayPrefix) { auto self = ref(shared_from_this()); ref rawGitAccessor = getRawAccessor(rev); - if (exportIgnore) { + rawGitAccessor->setPathDisplay(std::move(displayPrefix)); + if (exportIgnore) return make_ref(self, rawGitAccessor, rev); - } - else { + else return rawGitAccessor; - } } ref GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError) @@ -1236,7 +1241,7 @@ std::vector> GitRepoImpl::getSubmodules /* Read the .gitmodules files from this revision. */ CanonPath modulesFile(".gitmodules"); - auto accessor = getAccessor(rev, exportIgnore); + auto accessor = getAccessor(rev, exportIgnore, ""); if (!accessor->pathExists(modulesFile)) return {}; /* Parse it and get the revision of each submodule. */ diff --git a/src/libfetchers/git-utils.hh b/src/libfetchers/git-utils.hh index ff115143f..9677f5079 100644 --- a/src/libfetchers/git-utils.hh +++ b/src/libfetchers/git-utils.hh @@ -86,7 +86,10 @@ struct GitRepo virtual bool hasObject(const Hash & oid) = 0; - virtual ref getAccessor(const Hash & rev, bool exportIgnore) = 0; + virtual ref getAccessor( + const Hash & rev, + bool exportIgnore, + std::string displayPrefix) = 0; virtual ref getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError) = 0; diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index e8698709a..e40afb865 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -672,9 +672,7 @@ struct GitInputScheme : InputScheme verifyCommit(input, repo); bool exportIgnore = getExportIgnoreAttr(input); - auto accessor = repo->getAccessor(rev, exportIgnore); - - accessor->setPathDisplay("«" + input.to_string() + "»"); + auto accessor = repo->getAccessor(rev, exportIgnore, "«" + input.to_string() + "»"); /* If the repo has submodules, fetch them and return a mounted input accessor consisting of the accessor for the top-level diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc index 185941988..ec469df7c 100644 --- a/src/libfetchers/github.cc +++ b/src/libfetchers/github.cc @@ -294,9 +294,10 @@ struct GitArchiveInputScheme : InputScheme #endif input.attrs.insert_or_assign("lastModified", uint64_t(tarballInfo.lastModified)); - auto accessor = getTarballCache()->getAccessor(tarballInfo.treeHash, false); - - accessor->setPathDisplay("«" + input.to_string() + "»"); + auto accessor = getTarballCache()->getAccessor( + tarballInfo.treeHash, + false, + "«" + input.to_string() + "»"); return {accessor, input}; } diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc index 28574e7b1..699612e25 100644 --- a/src/libfetchers/tarball.cc +++ b/src/libfetchers/tarball.cc @@ -105,7 +105,8 @@ DownloadFileResult downloadFile( static DownloadTarballResult downloadTarball_( const std::string & url, - const Headers & headers) + const Headers & headers, + const std::string & displayPrefix) { Cache::Key cacheKey{"tarball", {{"url", url}}}; @@ -118,7 +119,7 @@ static DownloadTarballResult downloadTarball_( .treeHash = treeHash, .lastModified = (time_t) getIntAttr(infoAttrs, "lastModified"), .immutableUrl = maybeGetStrAttr(infoAttrs, "immutableUrl"), - .accessor = getTarballCache()->getAccessor(treeHash, false), + .accessor = getTarballCache()->getAccessor(treeHash, false, displayPrefix), }; }; @@ -371,9 +372,10 @@ struct TarballInputScheme : CurlInputScheme { auto input(_input); - auto result = downloadTarball_(getStrAttr(input.attrs, "url"), {}); - - result.accessor->setPathDisplay("«" + input.to_string() + "»"); + auto result = downloadTarball_( + getStrAttr(input.attrs, "url"), + {}, + "«" + input.to_string() + "»"); if (result.immutableUrl) { auto immutableInput = Input::fromURL(*input.settings, *result.immutableUrl); From 7c8c71f8e9319b17e85c0f510bfd0d0558361ac2 Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Fri, 31 Jan 2025 21:11:45 +1100 Subject: [PATCH 12/22] Totally exclude nix::setStackSize on Windows --- src/libutil/current-process.cc | 4 ++-- src/libutil/current-process.hh | 3 +++ src/nix/main.cc | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libutil/current-process.cc b/src/libutil/current-process.cc index 46e72b63a..255ae2cf5 100644 --- a/src/libutil/current-process.cc +++ b/src/libutil/current-process.cc @@ -51,11 +51,11 @@ unsigned int getMaxCPU() ////////////////////////////////////////////////////////////////////// +#ifndef _WIN32 size_t savedStackSize = 0; void setStackSize(size_t stackSize) { - #ifndef _WIN32 struct rlimit limit; if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur < stackSize) { savedStackSize = limit.rlim_cur; @@ -73,8 +73,8 @@ void setStackSize(size_t stackSize) ); } } - #endif } +#endif void restoreProcessContext(bool restoreMounts) { diff --git a/src/libutil/current-process.hh b/src/libutil/current-process.hh index 8286bf89d..660dcfe0b 100644 --- a/src/libutil/current-process.hh +++ b/src/libutil/current-process.hh @@ -17,10 +17,13 @@ namespace nix { */ unsigned int getMaxCPU(); +// It does not seem possible to dynamically change stack size on Windows. +#ifndef _WIN32 /** * Change the stack size. */ void setStackSize(size_t stackSize); +#endif /** * Restore the original inherited Unix process context (such as signal diff --git a/src/nix/main.cc b/src/nix/main.cc index b0e26e093..80ef53084 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -557,9 +557,11 @@ void mainWrapped(int argc, char * * argv) int main(int argc, char * * argv) { +#ifndef _WIN32 // Increase the default stack size for the evaluator and for // libstdc++'s std::regex. nix::setStackSize(64 * 1024 * 1024); +#endif return nix::handleExceptions(argv[0], [&]() { nix::mainWrapped(argc, argv); From 26539a087f7e0ff95c82e6fcd16f0017f4243e7e Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Fri, 31 Jan 2025 22:52:57 +1100 Subject: [PATCH 13/22] Add mbig-obj flag to allow cross-compiling libexpr to mingw32 --- nix-meson-build-support/big-objs/meson.build | 4 ++++ src/libexpr/meson.build | 1 + 2 files changed, 5 insertions(+) create mode 100644 nix-meson-build-support/big-objs/meson.build diff --git a/nix-meson-build-support/big-objs/meson.build b/nix-meson-build-support/big-objs/meson.build new file mode 100644 index 000000000..f5abd8bd8 --- /dev/null +++ b/nix-meson-build-support/big-objs/meson.build @@ -0,0 +1,4 @@ +# libexpr's primops creates a large object +# Without the following flag, we'll get errors when cross-compiling to mingw32: +# Fatal error: can't write 66 bytes to section .text of src/libexpr/libnixexpr.dll.p/primops.cc.obj: 'file too big' +add_project_arguments([ '-Wa,-mbig-obj' ], language: 'cpp') diff --git a/src/libexpr/meson.build b/src/libexpr/meson.build index b33aebc86..987300d58 100644 --- a/src/libexpr/meson.build +++ b/src/libexpr/meson.build @@ -24,6 +24,7 @@ deps_public_maybe_subproject = [ dependency('nix-fetchers'), ] subdir('nix-meson-build-support/subprojects') +subdir('nix-meson-build-support/big-objs') boost = dependency( 'boost', From 5f6658b9c909894a89da74c3f34b1ebe1434b8e7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2025 15:32:06 +0100 Subject: [PATCH 14/22] fetchTree: Distinguish between fetchGit and fetchTree consistently --- src/libexpr/primops/fetchTree.cc | 31 +++++++++---------- tests/functional/fetchGit.sh | 2 +- .../lang/eval-fail-fetchTree-negative.err.exp | 2 +- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index fe42b88f1..8c2d9ed06 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -90,24 +90,26 @@ static void fetchTree( fetchers::Input input { state.fetchSettings }; NixStringContext context; std::optional type; + auto fetcher = params.isFetchGit ? "fetchGit" : "fetchTree"; if (params.isFetchGit) type = "git"; state.forceValue(*args[0], pos); if (args[0]->type() == nAttrs) { - state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.fetchTree"); + state.forceAttrs(*args[0], pos, fmt("while evaluating the argument passed to '%s'", fetcher)); fetchers::Attrs attrs; if (auto aType = args[0]->attrs()->get(state.sType)) { if (type) state.error( - "unexpected attribute 'type'" + "unexpected argument 'type'" ).atPos(pos).debugThrow(); - type = state.forceStringNoCtx(*aType->value, aType->pos, "while evaluating the `type` attribute passed to builtins.fetchTree"); + type = state.forceStringNoCtx(*aType->value, aType->pos, + fmt("while evaluating the `type` argument passed to '%s'", fetcher)); } else if (!type) state.error( - "attribute 'type' is missing in call to 'fetchTree'" + "argument 'type' is missing in call to '%s'", fetcher ).atPos(pos).debugThrow(); attrs.emplace("type", type.value()); @@ -127,9 +129,8 @@ static void fetchTree( else if (attr.value->type() == nInt) { auto intValue = attr.value->integer().value; - if (intValue < 0) { - state.error("negative value given for fetchTree attr %1%: %2%", state.symbols[attr.name], intValue).atPos(pos).debugThrow(); - } + if (intValue < 0) + state.error("negative value given for '%s' argument '%s': %d", fetcher, state.symbols[attr.name], intValue).atPos(pos).debugThrow(); attrs.emplace(state.symbols[attr.name], uint64_t(intValue)); } else if (state.symbols[attr.name] == "publicKeys") { @@ -137,8 +138,8 @@ static void fetchTree( attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, context).dump()); } else - state.error("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", - state.symbols[attr.name], showType(*attr.value)).debugThrow(); + state.error("argument '%s' to '%s' is %s while a string, Boolean or integer is expected", + state.symbols[attr.name], fetcher, showType(*attr.value)).debugThrow(); } if (params.isFetchGit && !attrs.contains("exportIgnore") && (!attrs.contains("submodules") || !*fetchers::maybeGetBoolAttr(attrs, "submodules"))) { @@ -153,14 +154,14 @@ static void fetchTree( if (!params.allowNameArgument) if (auto nameIter = attrs.find("name"); nameIter != attrs.end()) state.error( - "attribute 'name' isn’t supported in call to 'fetchTree'" + "argument 'name' isn’t supported in call to '%s'", fetcher ).atPos(pos).debugThrow(); input = fetchers::Input::fromAttrs(state.fetchSettings, std::move(attrs)); } else { auto url = state.coerceToString(pos, *args[0], context, - "while evaluating the first argument passed to the fetcher", - false, false).toOwned(); + fmt("while evaluating the first argument passed to '%s'", fetcher), + false, false).toOwned(); if (params.isFetchGit) { fetchers::Attrs attrs; @@ -173,7 +174,7 @@ static void fetchTree( } else { if (!experimentalFeatureSettings.isEnabled(Xp::Flakes)) state.error( - "passing a string argument to 'fetchTree' requires the 'flakes' experimental feature" + "passing a string argument to '%s' requires the 'flakes' experimental feature", fetcher ).atPos(pos).debugThrow(); input = fetchers::Input::fromURL(state.fetchSettings, url); } @@ -183,10 +184,6 @@ static void fetchTree( input = lookupInRegistries(state.store, input).first; if (state.settings.pureEval && !input.isConsideredLocked(state.fetchSettings)) { - auto fetcher = "fetchTree"; - if (params.isFetchGit) - fetcher = "fetchGit"; - state.error( "in pure evaluation mode, '%s' will not fetch unlocked input '%s'", fetcher, input.to_string() diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 78925b5cd..2056117ce 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -79,7 +79,7 @@ path2=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \" # In pure eval mode, fetchGit with a revision should succeed. [[ $(nix eval --raw --expr "builtins.readFile (fetchGit { url = file://$repo; rev = \"$rev2\"; } + \"/hello\")") = world ]] -# But without a hash, it fails +# But without a hash, it fails. expectStderr 1 nix eval --expr 'builtins.fetchGit "file:///foo"' | grepQuiet "'fetchGit' will not fetch unlocked input" # Fetch again. This should be cached. diff --git a/tests/functional/lang/eval-fail-fetchTree-negative.err.exp b/tests/functional/lang/eval-fail-fetchTree-negative.err.exp index d9ba1f0b2..423123ca0 100644 --- a/tests/functional/lang/eval-fail-fetchTree-negative.err.exp +++ b/tests/functional/lang/eval-fail-fetchTree-negative.err.exp @@ -5,4 +5,4 @@ error: | ^ 2| type = "file"; - error: negative value given for fetchTree attr owner: -1 + error: negative value given for 'fetchTree' argument 'owner': -1 From a142803c282a68c1ba21390bcaf0cef0310271a0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2025 21:39:32 +0100 Subject: [PATCH 15/22] tests/functional/fetchGit.sh: Drop unnecessary --impure flags --- tests/functional/fetchGit.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 2056117ce..6c86b20aa 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -64,7 +64,7 @@ git -C $repo add differentbranch git -C $repo commit -m 'Test2' git -C $repo checkout master devrev=$(git -C $repo rev-parse devtest) -nix eval --impure --raw --expr "builtins.fetchGit { url = file://$repo; rev = \"$devrev\"; }" +nix eval --raw --expr "builtins.fetchGit { url = file://$repo; rev = \"$devrev\"; }" [[ $(nix eval --raw --expr "builtins.readFile (builtins.fetchGit { url = file://$repo; rev = \"$devrev\"; allRefs = true; } + \"/differentbranch\")") = 'different file' ]] @@ -142,10 +142,10 @@ path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$rep [[ $(nix eval --impure --expr "builtins.hasAttr \"dirtyShortRev\" (builtins.fetchGit $repo)") == "false" ]] status=0 -nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$? +nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$? [[ "$status" = "102" ]] -path5=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath") +path5=$(nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath") [[ $path = $path5 ]] # tarball-ttl should be ignored if we specify a rev @@ -255,7 +255,7 @@ echo "/exported-wonky export-ignore=wonk" >> $repo/.gitattributes git -C $repo add not-exported-file exported-wonky .gitattributes git -C $repo commit -m 'Bla6' rev5=$(git -C $repo rev-parse HEAD) -path12=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev5\"; }).outPath") +path12=$(nix eval --raw --expr "(builtins.fetchGit { url = file://$repo; rev = \"$rev5\"; }).outPath") [[ ! -e $path12/not-exported-file ]] [[ -e $path12/exported-wonky ]] From 5dec1dc086aa173c74644c4e3b46e97620f61dce Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2025 21:53:57 +0100 Subject: [PATCH 16/22] fetchGit/fetchTree: Allow fetching using only a NAR hash Fixes #12027. --- src/libexpr/primops/fetchTree.cc | 13 +++++++++---- tests/functional/fetchGit.sh | 7 ++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 8c2d9ed06..ddbd899e7 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -184,10 +184,15 @@ static void fetchTree( input = lookupInRegistries(state.store, input).first; if (state.settings.pureEval && !input.isConsideredLocked(state.fetchSettings)) { - state.error( - "in pure evaluation mode, '%s' will not fetch unlocked input '%s'", - fetcher, input.to_string() - ).atPos(pos).debugThrow(); + if (input.getNarHash()) + warn( + "Input '%s' is unlocked (e.g. lacks a Git revision) but does have a NAR hash. " + "This is deprecated since such inputs are verifiable but may not be reproducible.", + input.to_string()); + else + state.error( + "in pure evaluation mode, '%s' will not fetch unlocked input '%s'", + fetcher, input.to_string()).atPos(pos).debugThrow(); } state.checkURI(input.toURLString()); diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 6c86b20aa..3bd4dcaa6 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -141,13 +141,14 @@ path4=$(nix eval --impure --refresh --raw --expr "(builtins.fetchGit file://$rep [[ $(nix eval --impure --expr "builtins.hasAttr \"dirtyRev\" (builtins.fetchGit $repo)") == "false" ]] [[ $(nix eval --impure --expr "builtins.hasAttr \"dirtyShortRev\" (builtins.fetchGit $repo)") == "false" ]] -status=0 -nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" || status=$? -[[ "$status" = "102" ]] +expect 102 nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-B5yIPHhEm0eysJKEsO7nqxprh9vcblFxpJG11gXJus1=\"; }).outPath" path5=$(nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath") [[ $path = $path5 ]] +# It's allowed to use only a narHash, but you should get a warning. +expectStderr 0 nix eval --raw --expr "(builtins.fetchGit { url = $repo; ref = \"tag2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath" | grepQuiet "warning: Input .* is unlocked" + # tarball-ttl should be ignored if we specify a rev echo delft > $repo/hello git -C $repo add hello From 4113fdf2f05b5145d5f649f4393758606e2e2c97 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2025 22:07:50 +0100 Subject: [PATCH 17/22] Allow use of lock files with unlocked entries as long as they have a NAR hash Fixes #12364. --- src/libflake/flake/lockfile.cc | 13 ++++++++++--- tests/functional/flakes/unlocked-override.sh | 8 ++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libflake/flake/lockfile.cc b/src/libflake/flake/lockfile.cc index 25e7299f0..e3bf22c21 100644 --- a/src/libflake/flake/lockfile.cc +++ b/src/libflake/flake/lockfile.cc @@ -45,9 +45,16 @@ LockedNode::LockedNode( , isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true) , parentInputAttrPath(json.find("parent") != json.end() ? (std::optional) json["parent"] : std::nullopt) { - if (!lockedRef.input.isConsideredLocked(fetchSettings) && !lockedRef.input.isRelative()) - throw Error("Lock file contains unlocked input '%s'. Use '--allow-dirty-locks' to accept this lock file.", - fetchers::attrsToJSON(lockedRef.input.toAttrs())); + if (!lockedRef.input.isLocked() && !lockedRef.input.isRelative()) { + if (lockedRef.input.getNarHash()) + warn( + "Lock file entry '%s' is unlocked (e.g. lacks a Git revision) but does have a NAR hash. " + "This is deprecated since such inputs are verifiable but may not be reproducible.", + lockedRef.to_string()); + else + throw Error("Lock file contains unlocked input '%s'. Use '--allow-dirty-locks' to accept this lock file.", + fetchers::attrsToJSON(lockedRef.input.toAttrs())); + } // For backward compatibility, lock file entries are implicitly final. assert(!lockedRef.input.attrs.contains("__final")); diff --git a/tests/functional/flakes/unlocked-override.sh b/tests/functional/flakes/unlocked-override.sh index dcb427a8f..512aca401 100755 --- a/tests/functional/flakes/unlocked-override.sh +++ b/tests/functional/flakes/unlocked-override.sh @@ -37,8 +37,8 @@ expectStderr 1 nix flake lock "$flake2Dir" --override-input flake1 "$TEST_ROOT/f nix flake lock "$flake2Dir" --override-input flake1 "$TEST_ROOT/flake1" --allow-dirty-locks -# Using a lock file with a dirty lock requires --allow-dirty-locks as well. -expectStderr 1 nix eval "$flake2Dir#x" | - grepQuiet "Lock file contains unlocked input" +# Using a lock file with a dirty lock does not require --allow-dirty-locks, but should print a warning. +expectStderr 0 nix eval "$flake2Dir#x" | + grepQuiet "warning: Lock file entry .* is unlocked" -[[ $(nix eval "$flake2Dir#x" --allow-dirty-locks) = 456 ]] +[[ $(nix eval "$flake2Dir#x") = 456 ]] From 9e240eccede1b9444cb63ca00814af4235956024 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2025 22:14:49 +0100 Subject: [PATCH 18/22] Remove isConsideredLocked() --- src/libexpr/primops/fetchTree.cc | 2 +- src/libfetchers/fetchers.cc | 6 ------ src/libfetchers/fetchers.hh | 9 --------- src/libflake/flake/lockfile.cc | 16 +++++++++++++--- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index ddbd899e7..c4b8b2999 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -183,7 +183,7 @@ static void fetchTree( if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes)) input = lookupInRegistries(state.store, input).first; - if (state.settings.pureEval && !input.isConsideredLocked(state.fetchSettings)) { + if (state.settings.pureEval && !input.isLocked()) { if (input.getNarHash()) warn( "Input '%s' is unlocked (e.g. lacks a Git revision) but does have a NAR hash. " diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 9459db087..aadeecba2 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -155,12 +155,6 @@ bool Input::isLocked() const return scheme && scheme->isLocked(*this); } -bool Input::isConsideredLocked( - const Settings & settings) const -{ - return isLocked() || (settings.allowDirtyLocks && getNarHash()); -} - bool Input::isFinal() const { return maybeGetBoolAttr(attrs, "__final").value_or(false); diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index 644c267c1..37de1f507 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -90,15 +90,6 @@ public: */ bool isLocked() const; - /** - * Return whether the input is either locked, or, if - * `allow-dirty-locks` is enabled, it has a NAR hash. In the - * latter case, we can verify the input but we may not be able to - * fetch it from anywhere. - */ - bool isConsideredLocked( - const Settings & settings) const; - /** * Only for relative path flakes, i.e. 'path:./foo', returns the * relative path, i.e. './foo'. diff --git a/src/libflake/flake/lockfile.cc b/src/libflake/flake/lockfile.cc index e3bf22c21..b0971a696 100644 --- a/src/libflake/flake/lockfile.cc +++ b/src/libflake/flake/lockfile.cc @@ -1,7 +1,10 @@ #include +#include "fetch-settings.hh" +#include "flake/settings.hh" #include "lockfile.hh" #include "store-api.hh" +#include "strings.hh" #include #include @@ -9,8 +12,6 @@ #include #include -#include "strings.hh" -#include "flake/settings.hh" namespace nix::flake { @@ -255,11 +256,20 @@ std::optional LockFile::isUnlocked(const fetchers::Settings & fetchSet visit(root); + /* Return whether the input is either locked, or, if + `allow-dirty-locks` is enabled, it has a NAR hash. In the + latter case, we can verify the input but we may not be able to + fetch it from anywhere. */ + auto isConsideredLocked = [&](const fetchers::Input & input) + { + return input.isLocked() || (fetchSettings.allowDirtyLocks && input.getNarHash()); + }; + for (auto & i : nodes) { if (i == ref(root)) continue; auto node = i.dynamic_pointer_cast(); if (node - && (!node->lockedRef.input.isConsideredLocked(fetchSettings) + && (!isConsideredLocked(node->lockedRef.input) || !node->lockedRef.input.isFinal()) && !node->lockedRef.input.isRelative()) return node->lockedRef; From 8006196c55362685e576cda6b61513424daaaf33 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 29 Jan 2025 12:47:11 +0100 Subject: [PATCH 19/22] tests/functional/fetchGit.sh: Add a test for NAR hash mismatches --- tests/functional/fetchGit.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index 3bd4dcaa6..54be96da9 100755 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -146,6 +146,9 @@ expect 102 nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev path5=$(nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath") [[ $path = $path5 ]] +# Ensure that NAR hashes are checked. +expectStderr 102 nix eval --raw --expr "(builtins.fetchGit { url = $repo; rev = \"$rev2\"; narHash = \"sha256-Hr8g6AqANb4xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath" | grepQuiet "error: NAR hash mismatch" + # It's allowed to use only a narHash, but you should get a warning. expectStderr 0 nix eval --raw --expr "(builtins.fetchGit { url = $repo; ref = \"tag2\"; narHash = \"sha256-Hr8g6AqANb3xqX28eu1XnjK/3ab8Gv6TJSnkb1LezG9=\"; }).outPath" | grepQuiet "warning: Input .* is unlocked" From f62a28716301a1176aa5d6b6c6a13f11d0f4f99f Mon Sep 17 00:00:00 2001 From: Brian McKenna Date: Sat, 1 Feb 2025 21:36:50 +1100 Subject: [PATCH 20/22] Only enable big-obj on Windows --- nix-meson-build-support/big-objs/meson.build | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nix-meson-build-support/big-objs/meson.build b/nix-meson-build-support/big-objs/meson.build index f5abd8bd8..7e422abd8 100644 --- a/nix-meson-build-support/big-objs/meson.build +++ b/nix-meson-build-support/big-objs/meson.build @@ -1,4 +1,6 @@ -# libexpr's primops creates a large object -# Without the following flag, we'll get errors when cross-compiling to mingw32: -# Fatal error: can't write 66 bytes to section .text of src/libexpr/libnixexpr.dll.p/primops.cc.obj: 'file too big' -add_project_arguments([ '-Wa,-mbig-obj' ], language: 'cpp') +if host_machine.system() == 'windows' + # libexpr's primops creates a large object + # Without the following flag, we'll get errors when cross-compiling to mingw32: + # Fatal error: can't write 66 bytes to section .text of src/libexpr/libnixexpr.dll.p/primops.cc.obj: 'file too big' + add_project_arguments([ '-Wa,-mbig-obj' ], language: 'cpp') +endif From 453e8dc067e77d5d81cad5a533f99fdc33bcf2a1 Mon Sep 17 00:00:00 2001 From: Steve Walker <65963536+etherswangel@users.noreply.github.com> Date: Fri, 17 Jan 2025 22:17:39 +0800 Subject: [PATCH 21/22] Fix flakes follow symlinks Co-authored-by: Jan Christoph Bischko --- src/libflake/flake/flakeref.cc | 2 +- tests/functional/flakes/meson.build | 1 + tests/functional/flakes/symlink-paths.sh | 75 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/functional/flakes/symlink-paths.sh diff --git a/src/libflake/flake/flakeref.cc b/src/libflake/flake/flakeref.cc index 720f771ab..fbe61c294 100644 --- a/src/libflake/flake/flakeref.cc +++ b/src/libflake/flake/flakeref.cc @@ -107,7 +107,7 @@ std::pair parsePathFlakeRefWithFragment( to 'baseDir'). If so, search upward to the root of the repo (i.e. the directory containing .git). */ - path = absPath(path, baseDir); + path = absPath(path, baseDir, true); if (isFlake) { diff --git a/tests/functional/flakes/meson.build b/tests/functional/flakes/meson.build index cc65dc306..af7fb304b 100644 --- a/tests/functional/flakes/meson.build +++ b/tests/functional/flakes/meson.build @@ -28,6 +28,7 @@ suites += { 'commit-lock-file-summary.sh', 'non-flake-inputs.sh', 'relative-paths.sh', + 'symlink-paths.sh' ], 'workdir': meson.current_source_dir(), } diff --git a/tests/functional/flakes/symlink-paths.sh b/tests/functional/flakes/symlink-paths.sh new file mode 100644 index 000000000..2559e8107 --- /dev/null +++ b/tests/functional/flakes/symlink-paths.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +source ./common.sh + +requireGit + +create_flake() { + local flakeDir="$1" + createGitRepo $flakeDir + cat > $flakeDir/flake.nix < $repoDir/subdir/flake.nix < $repoDir/file + mkdir $repoDir/subdir + cat > $repoDir/subdir/flake.nix < $repo2Dir/file + git -C "$repo2Dir" add flake1_sym file + git -C "$repo2Dir" commit -m Initial + [[ $(nix eval "$repo2Dir/flake1_sym#x") == \"Hello\\n\" ]] + rm -rf "$TEST_ROOT/repo1" "$TEST_ROOT/repo2" +} +test_symlink_from_repo_to_another From 803fb83f7ffb3bd5e2e1ee3bb9ce3ea3001bec2c Mon Sep 17 00:00:00 2001 From: Illia Bobyr Date: Mon, 13 Jan 2025 18:19:16 -0800 Subject: [PATCH 22/22] nix-profile.fish: Typo NIX_SS{H => L}_CERT_FILE --- scripts/nix-profile.fish.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nix-profile.fish.in b/scripts/nix-profile.fish.in index dd2fbe209..53ad8efd0 100644 --- a/scripts/nix-profile.fish.in +++ b/scripts/nix-profile.fish.in @@ -39,7 +39,7 @@ else end # Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work. -if test -n "$NIX_SSH_CERT_FILE" +if test -n "$NIX_SSL_CERT_FILE" : # Allow users to override the NIX_SSL_CERT_FILE else if test -e /etc/ssl/certs/ca-certificates.crt # NixOS, Ubuntu, Debian, Gentoo, Arch set --export NIX_SSL_CERT_FILE /etc/ssl/certs/ca-certificates.crt