1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-09-19 10:50:24 -04:00

Fetch Git submodules lazily

This isn't particularly useful right now, since we still copy the
entire Git input to the store. But once we have lazy trees, this will
avoid fetching submodules unless they're actually needed.
This commit is contained in:
Eelco Dolstra 2024-09-04 16:54:31 +02:00
parent 357cec93b6
commit 7455cbfda0
3 changed files with 93 additions and 16 deletions

View file

@ -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"
@ -645,6 +646,9 @@ struct GitInputScheme : InputScheme
std::map<CanonPath, nix::ref<SourceAccessor>> mounts;
for (auto & [submodule, submoduleRev] : repo->getSubmodules(rev, exportIgnore)) {
auto submoduleAccessor = make_ref<LazySourceAccessor>([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);
@ -657,10 +661,12 @@ struct GitInputScheme : InputScheme
attrs.insert_or_assign("exportIgnore", Explicit<bool>{ exportIgnore });
attrs.insert_or_assign("submodules", Explicit<bool>{ true });
attrs.insert_or_assign("allRefs", Explicit<bool>{ true });
auto submoduleInput = fetchers::Input::fromAttrs(*input.settings, std::move(attrs));
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);
}

View file

@ -0,0 +1,70 @@
#pragma once
#include "source-accessor.hh"
#include "sync.hh"
#include <variant>
namespace nix {
/**
* A wrapper `SourceAccessor` that lazily constructs an underlying
* `SourceAccessor`.
*/
struct LazySourceAccessor : SourceAccessor
{
using Fun = std::function<ref<SourceAccessor>()>;
Sync<std::variant<ref<SourceAccessor>, Fun>> next_;
LazySourceAccessor(Fun next)
: next_{{std::move(next)}}
{
}
ref<SourceAccessor> getNext()
{
auto next(next_.lock());
if (auto accessor = std::get_if<ref<SourceAccessor>>(&*next))
return *accessor;
else {
auto fun = std::get<Fun>(*next);
auto acc = fun();
*next = acc;
return acc;
}
abort();
}
std::string readFile(const CanonPath & path) override
{
return getNext()->readFile(path);
}
void readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback) override
{
return getNext()->readFile(path, sink, sizeCallback);
}
bool pathExists(const CanonPath & path) override
{
return getNext()->pathExists(path);
}
std::optional<Stat> 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);
}
};
}

View file

@ -202,6 +202,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',