From 28dd3929482a48e4732a6b4fe900ada70b3fc8d2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 20 Feb 2024 10:36:36 +0100 Subject: [PATCH] fetchToStore(): Don't always respect settings.readOnlyMode It's now up to the caller whether readOnlyMode should be applied. In some contexts (like InputScheme::fetch()), we always need to fetch. (cherry picked from commit 7cb4d0c5b7dee435ea4b25e0c6dec4d60ad3675f) --- src/libcmd/installable-value.cc | 2 +- src/libexpr/eval.cc | 9 ++++++++- src/libexpr/primops.cc | 9 ++++++++- src/libfetchers/fetch-to-store.cc | 9 ++++----- src/libfetchers/fetch-to-store.hh | 3 +++ src/libfetchers/fetchers.cc | 2 +- tests/functional/fetchGit.sh | 5 ++++- 7 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/libcmd/installable-value.cc b/src/libcmd/installable-value.cc index c8a3e1b21..1aa2e65c1 100644 --- a/src/libcmd/installable-value.cc +++ b/src/libcmd/installable-value.cc @@ -45,7 +45,7 @@ ref InstallableValue::require(ref installable) std::optional InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx) { if (v.type() == nPath) { - auto storePath = fetchToStore(*state->store, v.path()); + auto storePath = fetchToStore(*state->store, v.path(), FetchMode::Copy); return {{ .path = DerivedPath::Opaque { .path = std::move(storePath), diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 91fd3ddf8..6d53b3f82 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -2338,7 +2338,14 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat auto dstPath = i != srcToStore.end() ? i->second : [&]() { - auto dstPath = fetchToStore(*store, path.resolveSymlinks(), path.baseName(), FileIngestionMethod::Recursive, nullptr, repair); + auto dstPath = fetchToStore( + *store, + path.resolveSymlinks(), + settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy, + path.baseName(), + FileIngestionMethod::Recursive, + nullptr, + repair); allowPath(dstPath); srcToStore.insert_or_assign(path, dstPath); printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath)); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index c10bee459..4b6715b40 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -2244,7 +2244,14 @@ static void addPath( }); if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) { - auto dstPath = fetchToStore(*state.store, path.resolveSymlinks(), name, method, filter.get(), state.repair); + auto dstPath = fetchToStore( + *state.store, + path.resolveSymlinks(), + settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy, + name, + method, + filter.get(), + state.repair); if (expectedHash && expectedStorePath != dstPath) state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path)); state.allowAndSetStorePathString(dstPath, v); diff --git a/src/libfetchers/fetch-to-store.cc b/src/libfetchers/fetch-to-store.cc index 547752fe8..7c88f2c60 100644 --- a/src/libfetchers/fetch-to-store.cc +++ b/src/libfetchers/fetch-to-store.cc @@ -7,6 +7,7 @@ namespace nix { StorePath fetchToStore( Store & store, const SourcePath & path, + FetchMode mode, std::string_view name, ContentAddressMethod method, PathFilter * filter, @@ -47,21 +48,19 @@ StorePath fetchToStore( } else debug("source path '%s' is uncacheable", path); - auto readOnly = settings.readOnlyMode; - Activity act(*logger, lvlChatty, actUnknown, - fmt(readOnly ? "hashing '%s'" : "copying '%s' to the store", path)); + fmt(mode == FetchMode::DryRun ? "hashing '%s'" : "copying '%s' to the store", path)); auto filter2 = filter ? *filter : defaultPathFilter; auto storePath = - readOnly + mode == FetchMode::DryRun ? store.computeStorePath( name, *path.accessor, path.path, method, HashAlgorithm::SHA256, {}, filter2).first : store.addToStore( name, *path.accessor, path.path, method, HashAlgorithm::SHA256, {}, filter2, repair); - if (cacheKey) + if (cacheKey && mode == FetchMode::Copy) fetchers::getCache()->add(store, *cacheKey, {}, storePath, true); return storePath; diff --git a/src/libfetchers/fetch-to-store.hh b/src/libfetchers/fetch-to-store.hh index e5e039340..81af1e240 100644 --- a/src/libfetchers/fetch-to-store.hh +++ b/src/libfetchers/fetch-to-store.hh @@ -8,12 +8,15 @@ namespace nix { +enum struct FetchMode { DryRun, Copy }; + /** * Copy the `path` to the Nix store. */ StorePath fetchToStore( Store & store, const SourcePath & path, + FetchMode mode, std::string_view name = "source", ContentAddressMethod method = FileIngestionMethod::Recursive, PathFilter * filter = nullptr, diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 7f282c972..9a534c1e2 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -376,7 +376,7 @@ void InputScheme::clone(const Input & input, const Path & destDir) const std::pair InputScheme::fetch(ref store, const Input & input) { auto [accessor, input2] = getAccessor(store, input); - auto storePath = fetchToStore(*store, SourcePath(accessor), input2.getName()); + auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy, input2.getName()); return {storePath, input2}; } diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh index c6a482035..4b7e8c2c8 100644 --- a/tests/functional/fetchGit.sh +++ b/tests/functional/fetchGit.sh @@ -30,7 +30,10 @@ echo hello >> $TEST_ROOT/worktree/hello rev2=$(git -C $repo rev-parse HEAD) git -C $repo tag -a tag2 -m tag2 -# Fetch a worktree +# Check whether fetching in read-only mode works. +nix-instantiate --eval -E "builtins.readFile ((builtins.fetchGit file://$TEST_ROOT/worktree) + \"/hello\") == \"utrecht\\n\"" + +# Fetch a worktree. unset _NIX_FORCE_HTTP 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")