From 5b7c240ebd013fd20741487f73d15a9478a52507 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 19 Feb 2025 12:45:59 +0100 Subject: [PATCH] Add a UnionSourceAccessor --- src/libutil/meson.build | 1 + src/libutil/source-accessor.hh | 6 ++ src/libutil/union-source-accessor.cc | 82 ++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/libutil/union-source-accessor.cc diff --git a/src/libutil/meson.build b/src/libutil/meson.build index b6a33135a..df459f0e5 100644 --- a/src/libutil/meson.build +++ b/src/libutil/meson.build @@ -167,6 +167,7 @@ sources = files( 'tarfile.cc', 'terminal.cc', 'thread-pool.cc', + 'union-source-accessor.cc', 'unix-domain-socket.cc', 'url.cc', 'users.cc', diff --git a/src/libutil/source-accessor.hh b/src/libutil/source-accessor.hh index b79f8af92..79ae092ac 100644 --- a/src/libutil/source-accessor.hh +++ b/src/libutil/source-accessor.hh @@ -216,4 +216,10 @@ ref makeFSSourceAccessor(std::filesystem::path root); ref makeMountedSourceAccessor(std::map> mounts); +/** + * Construct an accessor that presents a "union" view of a vector of + * underlying accessors. Earlier accessors take precedence over later. + */ +ref makeUnionSourceAccessor(std::vector> && accessors); + } diff --git a/src/libutil/union-source-accessor.cc b/src/libutil/union-source-accessor.cc new file mode 100644 index 000000000..cf16f20fb --- /dev/null +++ b/src/libutil/union-source-accessor.cc @@ -0,0 +1,82 @@ +#include "source-accessor.hh" + +namespace nix { + +struct UnionSourceAccessor : SourceAccessor +{ + std::vector> accessors; + + UnionSourceAccessor(std::vector> _accessors) + : accessors(std::move(_accessors)) + { + displayPrefix.clear(); + } + + std::string readFile(const CanonPath & path) override + { + for (auto & accessor : accessors) { + auto st = accessor->maybeLstat(path); + if (st && st->type == Type::tRegular) + return accessor->readFile(path); + } + throw FileNotFound("path '%s' does not exist", showPath(path)); + } + + std::optional maybeLstat(const CanonPath & path) override + { + for (auto & accessor : accessors) { + auto st = accessor->maybeLstat(path); + if (st) + return st; + } + return std::nullopt; + } + + DirEntries readDirectory(const CanonPath & path) override + { + DirEntries result; + for (auto & accessor : accessors) { + auto st = accessor->maybeLstat(path); + if (!st || st->type != Type::tDirectory) + continue; + for (auto & entry : accessor->readDirectory(path)) + // Don't override entries from previous accessors. + result.insert(entry); + } + return result; + } + + std::string readLink(const CanonPath & path) override + { + for (auto & accessor : accessors) { + auto st = accessor->maybeLstat(path); + if (st && st->type == Type::tSymlink) + return accessor->readLink(path); + } + throw FileNotFound("path '%s' does not exist", showPath(path)); + } + + std::string showPath(const CanonPath & path) override + { + for (auto & accessor : accessors) + return accessor->showPath(path); + return SourceAccessor::showPath(path); + } + + std::optional getPhysicalPath(const CanonPath & path) override + { + for (auto & accessor : accessors) { + auto p = accessor->getPhysicalPath(path); + if (p) + return p; + } + return std::nullopt; + } +}; + +ref makeUnionSourceAccessor(std::vector> && accessors) +{ + return make_ref(std::move(accessors)); +} + +}