diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 99d91919e..68793c828 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -10,6 +10,7 @@ #include "processes.hh" #include "git.hh" #include "mounted-source-accessor.hh" +#include "lazy-source-accessor.hh" #include "git-utils.hh" #include "logging.hh" #include "finally.hh" @@ -646,22 +647,27 @@ struct GitInputScheme : InputScheme std::map> mounts; for (auto & [submodule, submoduleRev] : repo->getSubmodules(rev, exportIgnore)) { - auto resolved = repo->resolveSubmoduleUrl(submodule.url); - debug("Git submodule %s: %s %s %s -> %s", - submodule.path, submodule.url, submodule.branch, submoduleRev.gitRev(), resolved); - fetchers::Attrs attrs; - attrs.insert_or_assign("type", "git"); - attrs.insert_or_assign("url", resolved); - if (submodule.branch != "") - attrs.insert_or_assign("ref", submodule.branch); - attrs.insert_or_assign("rev", submoduleRev.gitRev()); - attrs.insert_or_assign("exportIgnore", Explicit{ exportIgnore }); - attrs.insert_or_assign("submodules", Explicit{ true }); - attrs.insert_or_assign("allRefs", Explicit{ true }); - auto submoduleInput = fetchers::Input::fromAttrs(*input.settings, std::move(attrs)); - auto [submoduleAccessor, submoduleInput2] = - submoduleInput.getAccessor(store); - submoduleAccessor->setPathDisplay("«" + submoduleInput.to_string() + "»"); + auto submoduleAccessor = make_ref([repoDir, submodule, submoduleRev, exportIgnore, store, settings(input.settings)]() + { + auto repo = GitRepo::openRepo(repoDir); + auto resolved = repo->resolveSubmoduleUrl(submodule.url); + debug("Git submodule %s: %s %s %s -> %s", + submodule.path, submodule.url, submodule.branch, submoduleRev.gitRev(), resolved); + fetchers::Attrs attrs; + attrs.insert_or_assign("type", "git"); + attrs.insert_or_assign("url", resolved); + if (submodule.branch != "") + attrs.insert_or_assign("ref", submodule.branch); + attrs.insert_or_assign("rev", submoduleRev.gitRev()); + attrs.insert_or_assign("exportIgnore", Explicit{ exportIgnore }); + attrs.insert_or_assign("submodules", Explicit{ true }); + attrs.insert_or_assign("allRefs", Explicit{ true }); + auto submoduleInput = fetchers::Input::fromAttrs(*settings, std::move(attrs)); + auto [submoduleAccessor, submoduleInput2] = + submoduleInput.getAccessor(store); + submoduleAccessor->setPathDisplay("«" + submoduleInput.to_string() + "»"); + return submoduleAccessor; + }); mounts.insert_or_assign(submodule.path, submoduleAccessor); } diff --git a/src/libutil/lazy-source-accessor.hh b/src/libutil/lazy-source-accessor.hh new file mode 100644 index 000000000..544407b63 --- /dev/null +++ b/src/libutil/lazy-source-accessor.hh @@ -0,0 +1,69 @@ +#pragma once + +#include "source-accessor.hh" +#include "sync.hh" + +#include + +namespace nix { + +/** + * A wrapper `SourceAccessor` that lazily constructs an underlying + * `SourceAccessor`. + */ +struct LazySourceAccessor : SourceAccessor +{ + using Fun = std::function()>; + + Sync, Fun>> next_; + + LazySourceAccessor(Fun next) + : next_{{std::move(next)}} + { + } + + ref getNext() + { + auto next(next_.lock()); + if (auto accessor = std::get_if>(&*next)) + return *accessor; + else { + auto fun = std::get(*next); + auto acc = fun(); + *next = acc; + return acc; + } + } + + std::string readFile(const CanonPath & path) override + { + return getNext()->readFile(path); + } + + void readFile(const CanonPath & path, Sink & sink, std::function sizeCallback) override + { + return getNext()->readFile(path, sink, sizeCallback); + } + + bool pathExists(const CanonPath & path) override + { + return getNext()->pathExists(path); + } + + std::optional maybeLstat(const CanonPath & path) override + { + return getNext()->maybeLstat(path); + } + + DirEntries readDirectory(const CanonPath & path) override + { + return getNext()->readDirectory(path); + } + + std::string readLink(const CanonPath & path) override + { + return getNext()->readLink(path); + } +}; + +} diff --git a/src/libutil/meson.build b/src/libutil/meson.build index 57b741a50..22b58a830 100644 --- a/src/libutil/meson.build +++ b/src/libutil/meson.build @@ -211,6 +211,7 @@ headers = [config_h] + files( 'hilite.hh', 'json-impls.hh', 'json-utils.hh', + 'lazy-source-accessor.hh', 'logging.hh', 'lru-cache.hh', 'memory-source-accessor.hh',