From a554f523db34a5d6a8281c5228acfc128a8bd589 Mon Sep 17 00:00:00 2001 From: Nick Van den Broeck Date: Thu, 21 Mar 2019 09:30:16 +0100 Subject: [PATCH] Combining registries properly --- src/libexpr/eval.hh | 4 +- src/libexpr/primops/flake.cc | 104 +++++++++++++++++++++-------------- src/libexpr/primops/flake.hh | 4 +- src/nix/flake.cc | 8 ++- 4 files changed, 73 insertions(+), 47 deletions(-) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 35c01b97a..f6c894cad 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -316,10 +316,10 @@ private: public: - const FlakeRegistry & getFlakeRegistry(); + const std::vector> getFlakeRegistries(); private: - std::unique_ptr _flakeRegistry; + std::shared_ptr _flakeRegistry; std::once_flag _flakeRegistryInit; }; diff --git a/src/libexpr/primops/flake.cc b/src/libexpr/primops/flake.cc index b74e0b4b7..9a528ce82 100644 --- a/src/libexpr/primops/flake.cc +++ b/src/libexpr/primops/flake.cc @@ -12,16 +12,11 @@ namespace nix { -Path getUserRegistryPath() -{ - return getHome() + "/.config/nix/registry.json"; -} - /* Read the registry or a lock file. (Currently they have an identical format. */ -std::unique_ptr readRegistry(const Path & path) +std::shared_ptr readRegistry(const Path & path) { - auto registry = std::make_unique(); + auto registry = std::make_shared(); auto json = nlohmann::json::parse(readFile(path)); @@ -50,37 +45,71 @@ void writeRegistry(FlakeRegistry registry, Path path) writeFile(path, json.dump(4)); // The '4' is the number of spaces used in the indentation in the json file. } -const FlakeRegistry & EvalState::getFlakeRegistry() +Path getUserRegistryPath() { - std::call_once(_flakeRegistryInit, [&]() - { -#if 0 - auto registryUri = "file:///home/eelco/Dev/gists/nix-flakes/registry.json"; + return getHome() + "/.config/nix/registry.json"; +} - auto registryFile = getDownloader()->download(DownloadRequest(registryUri)); -#endif +std::shared_ptr getGlobalRegistry() +{ + // TODO: Make a global registry, and return it here. + return std::make_shared(); +} - auto registryFile = settings.nixDataDir + "/nix/flake-registry.json"; +std::shared_ptr getUserRegistry() +{ + return readRegistry(getUserRegistryPath()); +} - _flakeRegistry = readRegistry(registryFile); - }); +// Project-specific registry saved in flake-registry.json. +std::shared_ptr getLocalRegistry() +{ + Path registryFile = settings.nixDataDir + "/nix/flake-registry.json"; + return readRegistry(registryFile); +} - return *_flakeRegistry; +std::shared_ptr getFlagRegistry() +{ + return std::make_shared(); + // TODO: Implement this once the right flags are implemented. +} + +// This always returns a vector with globalReg, userReg, localReg, flakeReg. +// If one of them doesn't exist, the registry is left empty but does exist. +const std::vector> EvalState::getFlakeRegistries() +{ + std::vector> registries; + if (!evalSettings.pureEval) { + registries.push_back(std::make_shared()); // global + registries.push_back(std::make_shared()); // user + registries.push_back(std::make_shared()); // local + } else { + registries.push_back(getGlobalRegistry()); + registries.push_back(getUserRegistry()); + registries.push_back(getLocalRegistry()); + } + registries.push_back(getFlagRegistry()); + return registries; } Value * makeFlakeRegistryValue(EvalState & state) { auto v = state.allocValue(); - auto registry = state.getFlakeRegistry(); + auto registries = state.getFlakeRegistries(); - state.mkAttrs(*v, registry.entries.size()); + int size = 0; + for (auto registry : registries) + size += registry->entries.size(); + state.mkAttrs(*v, size); - for (auto & entry : registry.entries) { - auto vEntry = state.allocAttr(*v, entry.first); - state.mkAttrs(*vEntry, 2); - mkString(*state.allocAttr(*vEntry, state.symbols.create("uri")), entry.second.ref.to_string()); - vEntry->attrs->sort(); + for (auto & registry : registries) { + for (auto & entry : registry->entries) { + auto vEntry = state.allocAttr(*v, entry.first); + state.mkAttrs(*vEntry, 2); + mkString(*state.allocAttr(*vEntry, state.symbols.create("uri")), entry.second.ref.to_string()); + vEntry->attrs->sort(); + } } v->attrs->sort(); @@ -89,7 +118,7 @@ Value * makeFlakeRegistryValue(EvalState & state) } static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef, - std::vector registries) + std::vector> registries) { if (auto refData = std::get_if(&flakeRef.data)) { for (auto registry : registries) { @@ -117,13 +146,7 @@ static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef & flakeRef) FlakeRef directFlakeRef = FlakeRef(flakeRef); if (!flakeRef.isDirect()) { - std::vector registries; - // 'pureEval' is a setting which cannot be changed in `nix flake`, - // but without flagging it off, we can't use any FlakeIds. - // if (!evalSettings.pureEval) { - registries.push_back(&state.getFlakeRegistry()); - // } - directFlakeRef = lookupFlake(state, flakeRef, registries); + directFlakeRef = lookupFlake(state, flakeRef, state.getFlakeRegistries()); } assert(directFlakeRef.isDirect()); // NOTE FROM NICK: I don't see why one wouldn't fetch FlakeId flakes.. @@ -246,11 +269,8 @@ static std::tuple> resolveFlake(EvalState & st std::optional topFlakeId; /// FIXME: ambiguous todo.push({topRef, true}); - std::vector registries; - FlakeRegistry localRegistry; - registries.push_back(&localRegistry); - if (!evalSettings.pureEval) - registries.push_back(&state.getFlakeRegistry()); + std::vector> registries = state.getFlakeRegistries(); + std::shared_ptr localRegistry = registries.at(2); while (!todo.empty()) { auto [flakeRef, toplevel] = todo.front(); @@ -259,6 +279,7 @@ static std::tuple> resolveFlake(EvalState & st if (auto refData = std::get_if(&flakeRef.data)) { if (done.count(refData->id)) continue; // optimization flakeRef = lookupFlake(state, flakeRef, registries); + // This is why we need the `registries`. } if (evalSettings.pureEval && !flakeRef.isImmutable() && (!toplevel || !impureTopRef)) @@ -273,10 +294,13 @@ static std::tuple> resolveFlake(EvalState & st for (auto & require : flake.requires) todo.push({require, false}); + // The following piece of code basically adds the FlakeRefs from + // the lockfiles of dependencies to the localRegistry. This is used + // to resolve future `FlakeId`s, in `lookupFlake` a bit above this. if (flake.lockFile) for (auto & entry : flake.lockFile->entries) { - if (localRegistry.entries.count(entry.first)) continue; - localRegistry.entries.emplace(entry.first, entry.second); + if (localRegistry->entries.count(entry.first)) continue; + localRegistry->entries.emplace(entry.first, entry.second); } done.emplace(flake.id, std::move(flake)); diff --git a/src/libexpr/primops/flake.hh b/src/libexpr/primops/flake.hh index 4e49becc7..53cea1cc2 100644 --- a/src/libexpr/primops/flake.hh +++ b/src/libexpr/primops/flake.hh @@ -25,7 +25,7 @@ Value * makeFlakeRegistryValue(EvalState & state); Value * makeFlakeValue(EvalState & state, std::string flakeUri, Value & v); -std::unique_ptr readRegistry(const Path &); +std::shared_ptr readRegistry(const Path &); void writeRegistry(FlakeRegistry, Path); @@ -36,7 +36,7 @@ struct Flake std::string description; Path path; std::vector requires; - std::unique_ptr lockFile; + std::shared_ptr lockFile; Value * vProvides; // FIXME: gc // commit hash // date diff --git a/src/nix/flake.cc b/src/nix/flake.cc index fda903944..470dfdc08 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -24,12 +24,14 @@ struct CmdFlakeList : StoreCommand, MixEvalArgs { auto evalState = std::make_shared(searchPath, store); - auto registry = evalState->getFlakeRegistry(); + auto registries = evalState->getFlakeRegistries(); stopProgressBar(); - for (auto & entry : registry.entries) { - std::cout << entry.first << " " << entry.second.ref.to_string() << "\n"; + for (auto & registry : registries) { + for (auto & entry : registry->entries) { + std::cout << entry.first << " " << entry.second.ref.to_string() << "\n"; + } } } };