mirror of
https://github.com/NixOS/nix
synced 2025-06-25 14:51:16 +02:00
lockFlake(): Allow registry lookups for the top-level flake
Fixes #13050.
This commit is contained in:
parent
dda265f09a
commit
68de26d38a
11 changed files with 53 additions and 26 deletions
|
@ -40,7 +40,7 @@ void completeFlakeInputAttrPath(
|
||||||
std::string_view prefix)
|
std::string_view prefix)
|
||||||
{
|
{
|
||||||
for (auto & flakeRef : flakeRefs) {
|
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)
|
for (auto & input : flake.inputs)
|
||||||
if (hasPrefix(input.first, prefix))
|
if (hasPrefix(input.first, prefix))
|
||||||
completions.add(input.first);
|
completions.add(input.first);
|
||||||
|
|
|
@ -181,7 +181,7 @@ static void fetchTree(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes))
|
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 (state.settings.pureEval && !input.isLocked()) {
|
||||||
if (input.getNarHash())
|
if (input.getNarHash())
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace nix::fetchers {
|
namespace nix::fetchers {
|
||||||
|
|
||||||
|
enum class UseRegistries : int;
|
||||||
|
|
||||||
struct InputCache
|
struct InputCache
|
||||||
{
|
{
|
||||||
struct CachedResult
|
struct CachedResult
|
||||||
|
@ -11,7 +13,7 @@ struct InputCache
|
||||||
Input lockedInput;
|
Input lockedInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
CachedResult getAccessor(ref<Store> store, const Input & originalInput, bool useRegistries);
|
CachedResult getAccessor(ref<Store> store, const Input & originalInput, UseRegistries useRegistries);
|
||||||
|
|
||||||
struct CachedInput
|
struct CachedInput
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,7 +65,11 @@ void overrideRegistry(
|
||||||
const Input & to,
|
const Input & to,
|
||||||
const Attrs & extraAttrs);
|
const Attrs & extraAttrs);
|
||||||
|
|
||||||
using RegistryFilter = std::function<bool(Registry::RegistryType)>;
|
enum class UseRegistries : int {
|
||||||
|
No,
|
||||||
|
All,
|
||||||
|
Limited, // global and flag registry only
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rewrite a flakeref using the registries. If `filter` is set, only
|
* Rewrite a flakeref using the registries. If `filter` is set, only
|
||||||
|
@ -74,6 +78,6 @@ using RegistryFilter = std::function<bool(Registry::RegistryType)>;
|
||||||
std::pair<Input, Attrs> lookupInRegistries(
|
std::pair<Input, Attrs> lookupInRegistries(
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
const Input & input,
|
const Input & input,
|
||||||
const RegistryFilter & filter = {});
|
UseRegistries useRegistries);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
namespace nix::fetchers {
|
namespace nix::fetchers {
|
||||||
|
|
||||||
InputCache::CachedResult InputCache::getAccessor(ref<Store> store, const Input & originalInput, bool useRegistries)
|
InputCache::CachedResult
|
||||||
|
InputCache::getAccessor(ref<Store> store, const Input & originalInput, UseRegistries useRegistries)
|
||||||
{
|
{
|
||||||
auto fetched = lookup(originalInput);
|
auto fetched = lookup(originalInput);
|
||||||
Input resolvedInput = originalInput;
|
Input resolvedInput = originalInput;
|
||||||
|
@ -15,13 +16,8 @@ InputCache::CachedResult InputCache::getAccessor(ref<Store> store, const Input &
|
||||||
auto [accessor, lockedInput] = originalInput.getAccessor(store);
|
auto [accessor, lockedInput] = originalInput.getAccessor(store);
|
||||||
fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor});
|
fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor});
|
||||||
} else {
|
} else {
|
||||||
if (useRegistries) {
|
if (useRegistries != UseRegistries::No) {
|
||||||
auto [res, extraAttrs] =
|
auto [res, extraAttrs] = lookupInRegistries(store, originalInput, useRegistries);
|
||||||
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);
|
resolvedInput = std::move(res);
|
||||||
fetched = lookup(resolvedInput);
|
fetched = lookup(resolvedInput);
|
||||||
if (!fetched) {
|
if (!fetched) {
|
||||||
|
|
|
@ -14,6 +14,8 @@ std::shared_ptr<Registry> Registry::read(
|
||||||
const Settings & settings,
|
const Settings & settings,
|
||||||
const Path & path, RegistryType type)
|
const Path & path, RegistryType type)
|
||||||
{
|
{
|
||||||
|
debug("reading registry '%s'", path);
|
||||||
|
|
||||||
auto registry = std::make_shared<Registry>(settings, type);
|
auto registry = std::make_shared<Registry>(settings, type);
|
||||||
|
|
||||||
if (!pathExists(path))
|
if (!pathExists(path))
|
||||||
|
@ -179,29 +181,36 @@ Registries getRegistries(const Settings & settings, ref<Store> store)
|
||||||
std::pair<Input, Attrs> lookupInRegistries(
|
std::pair<Input, Attrs> lookupInRegistries(
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
const Input & _input,
|
const Input & _input,
|
||||||
const RegistryFilter & filter)
|
UseRegistries useRegistries)
|
||||||
{
|
{
|
||||||
Attrs extraAttrs;
|
Attrs extraAttrs;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
Input input(_input);
|
Input input(_input);
|
||||||
|
|
||||||
|
if (useRegistries == UseRegistries::No)
|
||||||
|
return {input, extraAttrs};
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string());
|
if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string());
|
||||||
|
|
||||||
for (auto & registry : getRegistries(*input.settings, store)) {
|
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)
|
// FIXME: O(n)
|
||||||
for (auto & entry : registry->entries) {
|
for (auto & entry : registry->entries) {
|
||||||
if (entry.exact) {
|
if (entry.exact) {
|
||||||
if (entry.from == input) {
|
if (entry.from == input) {
|
||||||
|
debug("resolved flakeref '%s' against registry %d exactly", input.to_string(), registry->type);
|
||||||
input = entry.to;
|
input = entry.to;
|
||||||
extraAttrs = entry.extraAttrs;
|
extraAttrs = entry.extraAttrs;
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (entry.from.contains(input)) {
|
if (entry.from.contains(input)) {
|
||||||
|
debug("resolved flakeref '%s' against registry %d", input.to_string(), registry->type);
|
||||||
input = entry.to.applyOverrides(
|
input = entry.to.applyOverrides(
|
||||||
!entry.from.getRef() && input.getRef() ? input.getRef() : std::optional<std::string>(),
|
!entry.from.getRef() && input.getRef() ? input.getRef() : std::optional<std::string>(),
|
||||||
!entry.from.getRev() && input.getRev() ? input.getRev() : std::optional<Hash>());
|
!entry.from.getRev() && input.getRev() ? input.getRev() : std::optional<Hash>());
|
||||||
|
|
|
@ -337,7 +337,7 @@ static FlakeRef applySelfAttrs(
|
||||||
static Flake getFlake(
|
static Flake getFlake(
|
||||||
EvalState & state,
|
EvalState & state,
|
||||||
const FlakeRef & originalRef,
|
const FlakeRef & originalRef,
|
||||||
bool useRegistries,
|
fetchers::UseRegistries useRegistries,
|
||||||
const InputAttrPath & lockRootAttrPath)
|
const InputAttrPath & lockRootAttrPath)
|
||||||
{
|
{
|
||||||
// Fetch a lazy tree first.
|
// Fetch a lazy tree first.
|
||||||
|
@ -368,7 +368,7 @@ static Flake getFlake(
|
||||||
return readFlake(state, originalRef, resolvedRef, lockedRef, state.storePath(storePath), lockRootAttrPath);
|
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, {});
|
return getFlake(state, originalRef, useRegistries, {});
|
||||||
}
|
}
|
||||||
|
@ -393,8 +393,14 @@ LockedFlake lockFlake(
|
||||||
experimentalFeatureSettings.require(Xp::Flakes);
|
experimentalFeatureSettings.require(Xp::Flakes);
|
||||||
|
|
||||||
auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries);
|
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) {
|
if (lockFlags.applyNixConfig) {
|
||||||
flake.config.apply(settings);
|
flake.config.apply(settings);
|
||||||
|
@ -569,7 +575,11 @@ LockedFlake lockFlake(
|
||||||
if (auto resolvedPath = resolveRelativePath()) {
|
if (auto resolvedPath = resolveRelativePath()) {
|
||||||
return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath);
|
return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath);
|
||||||
} else {
|
} else {
|
||||||
return getFlake(state, ref, useRegistries, inputAttrPath);
|
return getFlake(
|
||||||
|
state,
|
||||||
|
ref,
|
||||||
|
useRegistriesInputs,
|
||||||
|
inputAttrPath);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -717,7 +727,10 @@ LockedFlake lockFlake(
|
||||||
if (auto resolvedPath = resolveRelativePath()) {
|
if (auto resolvedPath = resolveRelativePath()) {
|
||||||
return {*resolvedPath, *input.ref};
|
return {*resolvedPath, *input.ref};
|
||||||
} else {
|
} 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);
|
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
|
repo, so we should re-read it. FIXME: we could
|
||||||
also just clear the 'rev' field... */
|
also just clear the 'rev' field... */
|
||||||
auto prevLockedRef = flake.lockedRef;
|
auto prevLockedRef = flake.lockedRef;
|
||||||
flake = getFlake(state, topRef, useRegistries);
|
flake = getFlake(
|
||||||
|
state,
|
||||||
|
topRef,
|
||||||
|
useRegistriesTop);
|
||||||
|
|
||||||
if (lockFlags.commitLockFile &&
|
if (lockFlags.commitLockFile &&
|
||||||
flake.lockedRef.input.getRev() &&
|
flake.lockedRef.input.getRev() &&
|
||||||
|
|
|
@ -37,9 +37,9 @@ std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef)
|
||||||
|
|
||||||
FlakeRef FlakeRef::resolve(
|
FlakeRef FlakeRef::resolve(
|
||||||
ref<Store> store,
|
ref<Store> 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));
|
return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
* Fingerprint of a locked flake; used as a cache key.
|
||||||
|
|
|
@ -65,7 +65,7 @@ struct FlakeRef
|
||||||
|
|
||||||
FlakeRef resolve(
|
FlakeRef resolve(
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
const fetchers::RegistryFilter & filter = {}) const;
|
fetchers::UseRegistries useRegistries = fetchers::UseRegistries::All) const;
|
||||||
|
|
||||||
static FlakeRef fromAttrs(
|
static FlakeRef fromAttrs(
|
||||||
const fetchers::Settings & fetchSettings,
|
const fetchers::Settings & fetchSettings,
|
||||||
|
|
|
@ -223,7 +223,7 @@ mv "$registry.tmp" "$registry"
|
||||||
# Ensure that locking ignores the user registry.
|
# Ensure that locking ignores the user registry.
|
||||||
mkdir -p "$TEST_HOME/.config/nix"
|
mkdir -p "$TEST_HOME/.config/nix"
|
||||||
ln -sfn "$registry" "$TEST_HOME/.config/nix/registry.json"
|
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"
|
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"
|
rm "$TEST_HOME/.config/nix/registry.json"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue