diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 424343ffc..c5cb70b44 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -10,6 +10,7 @@ #include "nix/util/url.hh" #include "nix/expr/value-to-json.hh" #include "nix/fetchers/fetch-to-store.hh" +#include "nix/fetchers/input-cache.hh" #include "nix/util/mounted-source-accessor.hh" #include @@ -201,16 +202,15 @@ static void fetchTree( throw Error("input '%s' is not allowed to use the '__final' attribute", input.to_string()); } - // FIXME: use fetchOrSubstituteTree(). - auto [accessor, lockedInput] = input.getAccessor(state.store); + auto cachedInput = fetchers::InputCache::getCache()->getAccessor(state.store, input, false); auto storePath = StorePath::random(input.getName()); state.allowPath(storePath); - state.storeFS->mount(CanonPath(state.store->printStorePath(storePath)), accessor); + state.storeFS->mount(CanonPath(state.store->printStorePath(storePath)), cachedInput.accessor); - emitTreeAttrs(state, storePath, lockedInput, v, params.emptyRevFallback, false); + emitTreeAttrs(state, storePath, cachedInput.lockedInput, v, params.emptyRevFallback, false); } static void prim_fetchTree(EvalState & state, const PosIdx pos, Value * * args, Value & v) diff --git a/src/libfetchers/include/nix/fetchers/input-cache.hh b/src/libfetchers/include/nix/fetchers/input-cache.hh index 62092baef..6a7194741 100644 --- a/src/libfetchers/include/nix/fetchers/input-cache.hh +++ b/src/libfetchers/include/nix/fetchers/input-cache.hh @@ -2,14 +2,23 @@ namespace nix::fetchers { -struct CachedInput -{ - Input lockedInput; - ref accessor; -}; - struct InputCache { + struct CachedResult + { + ref accessor; + Input resolvedInput; + Input lockedInput; + }; + + CachedResult getAccessor(ref store, const Input & originalInput, bool useRegistries); + + struct CachedInput + { + Input lockedInput; + ref accessor; + }; + virtual std::optional lookup(const Input & originalInput) const = 0; virtual void upsert(Input key, CachedInput cachedInput) = 0; diff --git a/src/libfetchers/input-cache.cc b/src/libfetchers/input-cache.cc index 44d33428d..6772d67c7 100644 --- a/src/libfetchers/input-cache.cc +++ b/src/libfetchers/input-cache.cc @@ -1,8 +1,48 @@ #include "nix/fetchers/input-cache.hh" +#include "nix/fetchers/registry.hh" #include "nix/util/sync.hh" +#include "nix/util/source-path.hh" namespace nix::fetchers { +InputCache::CachedResult InputCache::getAccessor(ref store, const Input & originalInput, bool useRegistries) +{ + auto fetched = lookup(originalInput); + Input resolvedInput = originalInput; + + if (!fetched) { + if (originalInput.isDirect()) { + auto [accessor, lockedInput] = originalInput.getAccessor(store); + fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor}); + } else { + if (useRegistries) { + auto [res, extraAttrs] = + lookupInRegistries(store, originalInput, [](fetchers::Registry::RegistryType type) { + /* Only use the global registry and CLI flags + to resolve indirect flakerefs. */ + return type == fetchers::Registry::Flag || type == fetchers::Registry::Global; + }); + resolvedInput = std::move(res); + fetched = lookup(resolvedInput); + if (!fetched) { + auto [accessor, lockedInput] = resolvedInput.getAccessor(store); + fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor}); + } + upsert(resolvedInput, *fetched); + } else { + throw Error( + "'%s' is an indirect flake reference, but registry lookups are not allowed", + originalInput.to_string()); + } + } + upsert(originalInput, *fetched); + } + + debug("got tree '%s' from '%s'", fetched->accessor, fetched->lockedInput.to_string()); + + return {fetched->accessor, resolvedInput, fetched->lockedInput}; +} + struct InputCacheImpl : InputCache { Sync> cache_; diff --git a/src/libflake/flake/flake.cc b/src/libflake/flake/flake.cc index 6214ca57d..34eab755a 100644 --- a/src/libflake/flake/flake.cc +++ b/src/libflake/flake/flake.cc @@ -26,48 +26,6 @@ using namespace fetchers; namespace flake { -static std::tuple, Input, Input> getAccessorCached( - EvalState & state, - const Input & originalInput, - bool useRegistries) -{ - auto inputCache = InputCache::getCache(); - - auto fetched = inputCache->lookup(originalInput); - Input resolvedInput = originalInput; - - if (!fetched) { - if (originalInput.isDirect()) { - auto [accessor, lockedInput] = originalInput.getAccessor(state.store); - fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor}); - } else { - if (useRegistries) { - auto [res, extraAttrs] = lookupInRegistries(state.store, originalInput, - [](fetchers::Registry::RegistryType type) { - /* Only use the global registry and CLI flags - to resolve indirect flakerefs. */ - return type == fetchers::Registry::Flag || type == fetchers::Registry::Global; - }); - resolvedInput = std::move(res); - fetched = inputCache->lookup(resolvedInput); - if (!fetched) { - auto [accessor, lockedInput] = resolvedInput.getAccessor(state.store); - fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor}); - } - inputCache->upsert(resolvedInput, *fetched); - } - else { - throw Error("'%s' is an indirect flake reference, but registry lookups are not allowed", originalInput.to_string()); - } - } - inputCache->upsert(originalInput, *fetched); - } - - debug("got tree '%s' from '%s'", fetched->accessor, fetched->lockedInput.to_string()); - - return {fetched->accessor, resolvedInput, fetched->lockedInput}; -} - static StorePath mountInput( EvalState & state, fetchers::Input & input, @@ -395,14 +353,13 @@ static Flake getFlake( CopyMode copyMode) { // Fetch a lazy tree first. - auto [accessor, resolvedInput, lockedInput] = getAccessorCached( - state, originalRef.input, useRegistries); + auto cachedInput = fetchers::InputCache::getCache()->getAccessor(state.store, originalRef.input, useRegistries); - auto resolvedRef = FlakeRef(std::move(resolvedInput), originalRef.subdir); - auto lockedRef = FlakeRef(std::move(lockedInput), originalRef.subdir); + auto resolvedRef = FlakeRef(std::move(cachedInput.resolvedInput), originalRef.subdir); + auto lockedRef = FlakeRef(std::move(cachedInput.lockedInput), originalRef.subdir); // Parse/eval flake.nix to get at the input.self attributes. - auto flake = readFlake(state, originalRef, resolvedRef, lockedRef, {accessor}, lockRootAttrPath); + auto flake = readFlake(state, originalRef, resolvedRef, lockedRef, {cachedInput.accessor}, lockRootAttrPath); // Re-fetch the tree if necessary. auto newLockedRef = applySelfAttrs(lockedRef, flake); @@ -411,16 +368,15 @@ static Flake getFlake( debug("refetching input '%s' due to self attribute", newLockedRef); // FIXME: need to remove attrs that are invalidated by the changed input attrs, such as 'narHash'. newLockedRef.input.attrs.erase("narHash"); - auto [accessor2, resolvedInput2, lockedInput2] = getAccessorCached( - state, newLockedRef.input, false); - accessor = accessor2; - lockedRef = FlakeRef(std::move(lockedInput2), newLockedRef.subdir); + auto cachedInput2 = fetchers::InputCache::getCache()->getAccessor(state.store, newLockedRef.input, useRegistries); + cachedInput.accessor = cachedInput2.accessor; + lockedRef = FlakeRef(std::move(cachedInput2.lockedInput), newLockedRef.subdir); } // Re-parse flake.nix from the store. return readFlake( state, originalRef, resolvedRef, lockedRef, - state.storePath(mountInput(state, lockedRef.input, originalRef.input, accessor, copyMode)), + state.storePath(mountInput(state, lockedRef.input, originalRef.input, cachedInput.accessor, copyMode)), lockRootAttrPath); } @@ -778,13 +734,12 @@ LockedFlake lockFlake( if (auto resolvedPath = resolveRelativePath()) { return {*resolvedPath, *input.ref}; } else { - auto [accessor, resolvedInput, lockedInput] = getAccessorCached( - state, input.ref->input, useRegistries); + auto cachedInput = fetchers::InputCache::getCache()->getAccessor(state.store, input.ref->input, useRegistries); - auto lockedRef = FlakeRef(std::move(lockedInput), input.ref->subdir); + auto lockedRef = FlakeRef(std::move(cachedInput.lockedInput), input.ref->subdir); return { - state.storePath(mountInput(state, lockedRef.input, input.ref->input, accessor, inputCopyMode)), + state.storePath(mountInput(state, lockedRef.input, input.ref->input, cachedInput.accessor, inputCopyMode)), lockedRef }; }