diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 2ebfac3e6..1c414e9e2 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -40,7 +40,7 @@ void completeFlakeInputAttrPath( std::string_view prefix) { for (auto & flakeRef : flakeRefs) { - auto flake = flake::getFlake(*evalState, flakeRef, true); + auto flake = flake::getFlake(*evalState, flakeRef, fetchers::UseRegistries::All); for (auto & input : flake.inputs) if (hasPrefix(input.first, prefix)) completions.add(input.first); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 0be9f4bdc..745705e04 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -181,7 +181,7 @@ static void fetchTree( } if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes)) - input = lookupInRegistries(state.store, input).first; + input = lookupInRegistries(state.store, input, fetchers::UseRegistries::Limited).first; if (state.settings.pureEval && !input.isLocked()) { if (input.getNarHash()) diff --git a/src/libfetchers/include/nix/fetchers/input-cache.hh b/src/libfetchers/include/nix/fetchers/input-cache.hh index 869c7d41e..9b1c5a310 100644 --- a/src/libfetchers/include/nix/fetchers/input-cache.hh +++ b/src/libfetchers/include/nix/fetchers/input-cache.hh @@ -2,6 +2,8 @@ namespace nix::fetchers { +enum class UseRegistries : int; + struct InputCache { struct CachedResult @@ -11,7 +13,7 @@ struct InputCache Input lockedInput; }; - CachedResult getAccessor(ref store, const Input & originalInput, bool useRegistries); + CachedResult getAccessor(ref store, const Input & originalInput, UseRegistries useRegistries); struct CachedInput { diff --git a/src/libfetchers/include/nix/fetchers/registry.hh b/src/libfetchers/include/nix/fetchers/registry.hh index 47ff9e86f..efbfe07c8 100644 --- a/src/libfetchers/include/nix/fetchers/registry.hh +++ b/src/libfetchers/include/nix/fetchers/registry.hh @@ -65,7 +65,11 @@ void overrideRegistry( const Input & to, const Attrs & extraAttrs); -using RegistryFilter = std::function; +enum class UseRegistries : int { + No, + All, + Limited, // global and flag registry only +}; /** * Rewrite a flakeref using the registries. If `filter` is set, only @@ -74,6 +78,6 @@ using RegistryFilter = std::function; std::pair lookupInRegistries( ref store, const Input & input, - const RegistryFilter & filter = {}); + UseRegistries useRegistries); } diff --git a/src/libfetchers/input-cache.cc b/src/libfetchers/input-cache.cc index 716143899..1a4bb28a3 100644 --- a/src/libfetchers/input-cache.cc +++ b/src/libfetchers/input-cache.cc @@ -5,7 +5,8 @@ namespace nix::fetchers { -InputCache::CachedResult InputCache::getAccessor(ref store, const Input & originalInput, bool useRegistries) +InputCache::CachedResult +InputCache::getAccessor(ref store, const Input & originalInput, UseRegistries useRegistries) { auto fetched = lookup(originalInput); Input resolvedInput = originalInput; @@ -15,13 +16,8 @@ InputCache::CachedResult InputCache::getAccessor(ref store, const Input & 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; - }); + if (useRegistries != UseRegistries::No) { + auto [res, extraAttrs] = lookupInRegistries(store, originalInput, useRegistries); resolvedInput = std::move(res); fetched = lookup(resolvedInput); if (!fetched) { diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index e9b55f7f2..bfaf9569a 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -14,6 +14,8 @@ std::shared_ptr Registry::read( const Settings & settings, const Path & path, RegistryType type) { + debug("reading registry '%s'", path); + auto registry = std::make_shared(settings, type); if (!pathExists(path)) @@ -179,29 +181,36 @@ Registries getRegistries(const Settings & settings, ref store) std::pair lookupInRegistries( ref store, const Input & _input, - const RegistryFilter & filter) + UseRegistries useRegistries) { Attrs extraAttrs; int n = 0; Input input(_input); + if (useRegistries == UseRegistries::No) + return {input, extraAttrs}; + restart: n++; if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string()); for (auto & registry : getRegistries(*input.settings, store)) { - if (filter && !filter(registry->type)) continue; + if (useRegistries == UseRegistries::Limited + && !(registry->type == fetchers::Registry::Flag || registry->type == fetchers::Registry::Global)) + continue; // FIXME: O(n) for (auto & entry : registry->entries) { if (entry.exact) { if (entry.from == input) { + debug("resolved flakeref '%s' against registry %d exactly", input.to_string(), registry->type); input = entry.to; extraAttrs = entry.extraAttrs; goto restart; } } else { if (entry.from.contains(input)) { + debug("resolved flakeref '%s' against registry %d", input.to_string(), registry->type); input = entry.to.applyOverrides( !entry.from.getRef() && input.getRef() ? input.getRef() : std::optional(), !entry.from.getRev() && input.getRev() ? input.getRev() : std::optional()); diff --git a/src/libflake/flake.cc b/src/libflake/flake.cc index afeefdaec..818b2fb75 100644 --- a/src/libflake/flake.cc +++ b/src/libflake/flake.cc @@ -337,7 +337,7 @@ static FlakeRef applySelfAttrs( static Flake getFlake( EvalState & state, const FlakeRef & originalRef, - bool useRegistries, + fetchers::UseRegistries useRegistries, const InputAttrPath & lockRootAttrPath) { // Fetch a lazy tree first. @@ -368,7 +368,7 @@ static Flake getFlake( return readFlake(state, originalRef, resolvedRef, lockedRef, state.storePath(storePath), lockRootAttrPath); } -Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries) +Flake getFlake(EvalState & state, const FlakeRef & originalRef, fetchers::UseRegistries useRegistries) { return getFlake(state, originalRef, useRegistries, {}); } @@ -393,8 +393,14 @@ LockedFlake lockFlake( experimentalFeatureSettings.require(Xp::Flakes); auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries); + auto useRegistriesTop = useRegistries ? fetchers::UseRegistries::All : fetchers::UseRegistries::No; + auto useRegistriesInputs = useRegistries ? fetchers::UseRegistries::Limited : fetchers::UseRegistries::No; - auto flake = getFlake(state, topRef, useRegistries, {}); + auto flake = getFlake( + state, + topRef, + useRegistriesTop, + {}); if (lockFlags.applyNixConfig) { flake.config.apply(settings); @@ -569,7 +575,11 @@ LockedFlake lockFlake( if (auto resolvedPath = resolveRelativePath()) { return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath); } else { - return getFlake(state, ref, useRegistries, inputAttrPath); + return getFlake( + state, + ref, + useRegistriesInputs, + inputAttrPath); } }; @@ -717,7 +727,10 @@ LockedFlake lockFlake( if (auto resolvedPath = resolveRelativePath()) { return {*resolvedPath, *input.ref}; } else { - auto cachedInput = state.inputCache->getAccessor(state.store, input.ref->input, useRegistries); + auto cachedInput = state.inputCache->getAccessor( + state.store, + input.ref->input, + useRegistriesInputs); auto lockedRef = FlakeRef(std::move(cachedInput.lockedInput), input.ref->subdir); @@ -834,7 +847,10 @@ LockedFlake lockFlake( repo, so we should re-read it. FIXME: we could also just clear the 'rev' field... */ auto prevLockedRef = flake.lockedRef; - flake = getFlake(state, topRef, useRegistries); + flake = getFlake( + state, + topRef, + useRegistriesTop); if (lockFlags.commitLockFile && flake.lockedRef.input.getRev() && diff --git a/src/libflake/flakeref.cc b/src/libflake/flakeref.cc index 1580c2846..a8b139d65 100644 --- a/src/libflake/flakeref.cc +++ b/src/libflake/flakeref.cc @@ -37,9 +37,9 @@ std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef) FlakeRef FlakeRef::resolve( ref store, - const fetchers::RegistryFilter & filter) const + fetchers::UseRegistries useRegistries) const { - auto [input2, extraAttrs] = lookupInRegistries(store, input, filter); + auto [input2, extraAttrs] = lookupInRegistries(store, input, useRegistries); return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir)); } diff --git a/src/libflake/include/nix/flake/flake.hh b/src/libflake/include/nix/flake/flake.hh index 3b98f1400..f90498b7c 100644 --- a/src/libflake/include/nix/flake/flake.hh +++ b/src/libflake/include/nix/flake/flake.hh @@ -115,7 +115,7 @@ struct Flake } }; -Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool useRegistries); +Flake getFlake(EvalState & state, const FlakeRef & flakeRef, fetchers::UseRegistries useRegistries); /** * Fingerprint of a locked flake; used as a cache key. diff --git a/src/libflake/include/nix/flake/flakeref.hh b/src/libflake/include/nix/flake/flakeref.hh index 0fd1fec4d..8c15f9d95 100644 --- a/src/libflake/include/nix/flake/flakeref.hh +++ b/src/libflake/include/nix/flake/flakeref.hh @@ -65,7 +65,7 @@ struct FlakeRef FlakeRef resolve( ref store, - const fetchers::RegistryFilter & filter = {}) const; + fetchers::UseRegistries useRegistries = fetchers::UseRegistries::All) const; static FlakeRef fromAttrs( const fetchers::Settings & fetchSettings, diff --git a/tests/functional/flakes/flakes.sh b/tests/functional/flakes/flakes.sh index b67a0964a..aac505d41 100755 --- a/tests/functional/flakes/flakes.sh +++ b/tests/functional/flakes/flakes.sh @@ -223,7 +223,7 @@ mv "$registry.tmp" "$registry" # Ensure that locking ignores the user registry. mkdir -p "$TEST_HOME/.config/nix" ln -sfn "$registry" "$TEST_HOME/.config/nix/registry.json" -nix flake metadata flake1 +nix flake metadata --flake-registry '' flake1 expectStderr 1 nix flake update --flake-registry '' --flake "$flake3Dir" | grepQuiet "cannot find flake 'flake:flake1' in the flake registries" rm "$TEST_HOME/.config/nix/registry.json"