diff --git a/lix/libcmd/installables.cc b/lix/libcmd/installables.cc index 2d9dfb45d..7a64cc044 100644 --- a/lix/libcmd/installables.cc +++ b/lix/libcmd/installables.cc @@ -363,7 +363,7 @@ void completeFlakeRef( Args::completeDir(completions, 0, prefix); /* Look for registry entries that match the prefix. */ - for (auto & registry : fetchers::getRegistries(store)) { + for (auto & registry : aio.blockOn(fetchers::getRegistries(store))) { for (auto & entry : registry->entries) { auto from = entry.from.to_string(); if (!prefix.starts_with("flake:") && from.starts_with("flake:")) { diff --git a/lix/libexpr/flake/flakeref.cc b/lix/libexpr/flake/flakeref.cc index 58bce900f..1e9091e91 100644 --- a/lix/libexpr/flake/flakeref.cc +++ b/lix/libexpr/flake/flakeref.cc @@ -44,7 +44,7 @@ bool FlakeRef::operator ==(const FlakeRef & other) const kj::Promise> FlakeRef::resolve(ref store) const try { - auto [input2, extraAttrs] = lookupInRegistries(store, input); + auto [input2, extraAttrs] = TRY_AWAIT(lookupInRegistries(store, input)); co_return FlakeRef( std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir) ); diff --git a/lix/libexpr/primops/fetchTree.cc b/lix/libexpr/primops/fetchTree.cc index 8c3348496..e1c680f82 100644 --- a/lix/libexpr/primops/fetchTree.cc +++ b/lix/libexpr/primops/fetchTree.cc @@ -186,7 +186,7 @@ static void fetchTree( } if (!evalSettings.pureEval && !input.isDirect()) - input = lookupInRegistries(state.ctx.store, input).first; + input = state.aio.blockOn(lookupInRegistries(state.ctx.store, input)).first; if (evalSettings.pureEval && !input.isLocked()) { state.ctx.errors.make("in pure evaluation mode, 'fetchTree' requires a locked input").atPos(pos).debugThrow(); diff --git a/lix/libfetchers/registry.cc b/lix/libfetchers/registry.cc index 3697682a0..732d87421 100644 --- a/lix/libfetchers/registry.cc +++ b/lix/libfetchers/registry.cc @@ -1,5 +1,7 @@ #include "lix/libfetchers/registry.hh" #include "lix/libfetchers/fetchers.hh" +#include "lix/libutil/async.hh" +#include "lix/libutil/types.hh" #include "lix/libutil/users.hh" #include "lix/libstore/globals.hh" #include "lix/libstore/store-api.hh" @@ -7,7 +9,10 @@ #include "lix/libfetchers/fetch-settings.hh" +#include +#include #include +#include namespace nix::fetchers { @@ -153,45 +158,62 @@ void overrideRegistry( flagRegistry->add(from, to, extraAttrs); } -static std::shared_ptr getGlobalRegistry(ref store) -{ - static auto reg = [&]() { +static kj::Promise>> getGlobalRegistry(ref store) +try { + static std::shared_mutex mtx; + static std::shared_ptr reg; + + if (std::shared_lock l(mtx); reg) { + co_return reg; + } + + std::scoped_lock l(mtx); + + if (!reg) { auto path = fetchSettings.flakeRegistry.get(); if (path == "") { - return std::make_shared(Registry::Global); // empty registry + reg = std::make_shared(Registry::Global); // empty registry } else if (path == "vendored") { - return Registry::read(settings.nixDataDir + "/flake-registry.json", Registry::Global); + reg = Registry::read(settings.nixDataDir + "/flake-registry.json", Registry::Global); + } else { + if (!path.starts_with("/")) { + warn( + "config option flake-registry referring to a URL is deprecated and will be " + "removed in Lix 3.0; yours is: `%s'", + path + ); + + auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath; + if (auto store2 = store.dynamic_pointer_cast()) + store2->addPermRoot(storePath, getCacheDir() + "/nix/flake-registry.json"); + path = store->toRealPath(storePath); + } + + reg = Registry::read(path, Registry::Global); } + }; - if (!path.starts_with("/")) { - warn("config option flake-registry referring to a URL is deprecated and will be removed in Lix 3.0; yours is: `%s'", path); - - auto storePath = downloadFile(store, path, "flake-registry.json", false).storePath; - if (auto store2 = store.dynamic_pointer_cast()) - store2->addPermRoot(storePath, getCacheDir() + "/nix/flake-registry.json"); - path = store->toRealPath(storePath); - } - - return Registry::read(path, Registry::Global); - }(); - - return reg; + co_return reg; +} catch (...) { + co_return result::current_exception(); } -Registries getRegistries(ref store) -{ +kj::Promise> getRegistries(ref store) +try { Registries registries; registries.push_back(getFlagRegistry()); registries.push_back(getUserRegistry()); registries.push_back(getSystemRegistry()); - registries.push_back(getGlobalRegistry(store)); - return registries; + registries.push_back(TRY_AWAIT(getGlobalRegistry(store))); + co_return registries; +} catch (...) { + co_return result::current_exception(); } -std::pair lookupInRegistries( +kj::Promise>> lookupInRegistries( ref store, const Input & _input) -{ +try { Attrs extraAttrs; int n = 0; Input input(_input); @@ -201,7 +223,7 @@ std::pair lookupInRegistries( n++; if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string()); - for (auto & registry : getRegistries(store)) { + for (auto & registry : TRY_AWAIT(getRegistries(store))) { // FIXME: O(n) for (auto & entry : registry->entries) { if (entry.exact) { @@ -227,7 +249,9 @@ std::pair lookupInRegistries( debug("looked up '%s' -> '%s'", _input.to_string(), input.to_string()); - return {input, extraAttrs}; + co_return {input, extraAttrs}; +} catch (...) { + co_return result::current_exception(); } } diff --git a/lix/libfetchers/registry.hh b/lix/libfetchers/registry.hh index 732568661..bd7b16f67 100644 --- a/lix/libfetchers/registry.hh +++ b/lix/libfetchers/registry.hh @@ -54,14 +54,14 @@ std::shared_ptr getCustomRegistry(const Path & p); Path getUserRegistryPath(); -Registries getRegistries(ref store); +kj::Promise> getRegistries(ref store); void overrideRegistry( const Input & from, const Input & to, const Attrs & extraAttrs); -std::pair lookupInRegistries( +kj::Promise>> lookupInRegistries( ref store, const Input & input); diff --git a/lix/nix/registry.cc b/lix/nix/registry.cc index 6e14a778e..d0b0400c6 100644 --- a/lix/nix/registry.cc +++ b/lix/nix/registry.cc @@ -69,7 +69,7 @@ struct CmdRegistryList : StoreCommand { using namespace fetchers; - auto registries = getRegistries(store); + auto registries = aio().blockOn(getRegistries(store)); for (auto & registry : registries) { for (auto & entry : registry->entries) {