Move most of InputAccessor into libutil

This commit is contained in:
Eelco Dolstra 2023-10-19 14:45:26 +02:00
parent 06c57899e3
commit fb6a3910c4
4 changed files with 206 additions and 185 deletions

View file

@ -3,95 +3,6 @@
namespace nix { namespace nix {
static std::atomic<size_t> nextNumber{0};
InputAccessor::InputAccessor()
: number(++nextNumber)
{
}
// FIXME: merge with archive.cc.
void InputAccessor::dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter)
{
auto dumpContents = [&](const CanonPath & path)
{
// FIXME: pipe
auto s = readFile(path);
sink << "contents" << s.size();
sink(s);
writePadding(s.size(), sink);
};
std::function<void(const CanonPath & path)> dump;
dump = [&](const CanonPath & path) {
checkInterrupt();
auto st = lstat(path);
sink << "(";
if (st.type == tRegular) {
sink << "type" << "regular";
if (st.isExecutable)
sink << "executable" << "";
dumpContents(path);
}
else if (st.type == tDirectory) {
sink << "type" << "directory";
/* If we're on a case-insensitive system like macOS, undo
the case hack applied by restorePath(). */
std::map<std::string, std::string> unhacked;
for (auto & i : readDirectory(path))
if (/* archiveSettings.useCaseHack */ false) { // FIXME
std::string name(i.first);
size_t pos = i.first.find(caseHackSuffix);
if (pos != std::string::npos) {
debug("removing case hack suffix from '%s'", path + i.first);
name.erase(pos);
}
if (!unhacked.emplace(name, i.first).second)
throw Error("file name collision in between '%s' and '%s'",
(path + unhacked[name]),
(path + i.first));
} else
unhacked.emplace(i.first, i.first);
for (auto & i : unhacked)
if (filter((path + i.first).abs())) {
sink << "entry" << "(" << "name" << i.first << "node";
dump(path + i.second);
sink << ")";
}
}
else if (st.type == tSymlink)
sink << "type" << "symlink" << "target" << readLink(path);
else throw Error("file '%s' has an unsupported type", path);
sink << ")";
};
sink << narVersionMagic1;
dump(path);
}
Hash InputAccessor::hashPath(
const CanonPath & path,
PathFilter & filter,
HashType ht)
{
HashSink sink(ht);
dumpPath(path, sink, filter);
return sink.finish().first;
}
StorePath InputAccessor::fetchToStore( StorePath InputAccessor::fetchToStore(
ref<Store> store, ref<Store> store,
const CanonPath & path, const CanonPath & path,
@ -114,19 +25,6 @@ StorePath InputAccessor::fetchToStore(
return storePath; return storePath;
} }
std::optional<InputAccessor::Stat> InputAccessor::maybeLstat(const CanonPath & path)
{
// FIXME: merge these into one operation.
if (!pathExists(path))
return {};
return lstat(path);
}
std::string InputAccessor::showPath(const CanonPath & path)
{
return path.abs();
}
SourcePath InputAccessor::root() SourcePath InputAccessor::root()
{ {
return {ref(shared_from_this()), CanonPath::root}; return {ref(shared_from_this()), CanonPath::root};

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
#include "source-accessor.hh"
#include "ref.hh" #include "ref.hh"
#include "types.hh" #include "types.hh"
#include "archive.hh"
#include "canon-path.hh"
#include "repair-flag.hh" #include "repair-flag.hh"
#include "hash.hh"
#include "content-address.hh" #include "content-address.hh"
namespace nix { namespace nix {
@ -16,60 +14,8 @@ struct SourcePath;
class StorePath; class StorePath;
class Store; class Store;
struct InputAccessor : public std::enable_shared_from_this<InputAccessor> struct InputAccessor : SourceAccessor, std::enable_shared_from_this<InputAccessor>
{ {
const size_t number;
InputAccessor();
virtual ~InputAccessor()
{ }
virtual std::string readFile(const CanonPath & path) = 0;
virtual bool pathExists(const CanonPath & path) = 0;
enum Type {
tRegular, tSymlink, tDirectory,
/**
Any other node types that may be encountered on the file system, such as device nodes, sockets, named pipe, and possibly even more exotic things.
Responsible for `"unknown"` from `builtins.readFileType "/dev/null"`.
Unlike `DT_UNKNOWN`, this must not be used for deferring the lookup of types.
*/
tMisc
};
struct Stat
{
Type type = tMisc;
//uint64_t fileSize = 0; // regular files only
bool isExecutable = false; // regular files only
};
virtual Stat lstat(const CanonPath & path) = 0;
std::optional<Stat> maybeLstat(const CanonPath & path);
typedef std::optional<Type> DirEntry;
typedef std::map<std::string, DirEntry> DirEntries;
virtual DirEntries readDirectory(const CanonPath & path) = 0;
virtual std::string readLink(const CanonPath & path) = 0;
virtual void dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter = defaultPathFilter);
Hash hashPath(
const CanonPath & path,
PathFilter & filter = defaultPathFilter,
HashType ht = htSHA256);
StorePath fetchToStore( StorePath fetchToStore(
ref<Store> store, ref<Store> store,
const CanonPath & path, const CanonPath & path,
@ -78,34 +24,7 @@ struct InputAccessor : public std::enable_shared_from_this<InputAccessor>
PathFilter * filter = nullptr, PathFilter * filter = nullptr,
RepairFlag repair = NoRepair); RepairFlag repair = NoRepair);
/* Return a corresponding path in the root filesystem, if
possible. This is only possible for inputs that are
materialized in the root filesystem. */
virtual std::optional<CanonPath> getPhysicalPath(const CanonPath & path)
{ return std::nullopt; }
bool operator == (const InputAccessor & x) const
{
return number == x.number;
}
bool operator < (const InputAccessor & x) const
{
return number < x.number;
}
void setPathDisplay(std::string displayPrefix, std::string displaySuffix = "");
virtual std::string showPath(const CanonPath & path);
SourcePath root(); SourcePath root();
/* Return the maximum last-modified time of the files in this
tree, if available. */
virtual std::optional<time_t> getLastModified()
{
return std::nullopt;
}
}; };
/** /**

View file

@ -0,0 +1,108 @@
#include "source-accessor.hh"
#include "archive.hh"
namespace nix {
static std::atomic<size_t> nextNumber{0};
SourceAccessor::SourceAccessor()
: number(++nextNumber)
{
}
// FIXME: merge with archive.cc.
void SourceAccessor::dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter)
{
auto dumpContents = [&](const CanonPath & path)
{
// FIXME: pipe
auto s = readFile(path);
sink << "contents" << s.size();
sink(s);
writePadding(s.size(), sink);
};
std::function<void(const CanonPath & path)> dump;
dump = [&](const CanonPath & path) {
checkInterrupt();
auto st = lstat(path);
sink << "(";
if (st.type == tRegular) {
sink << "type" << "regular";
if (st.isExecutable)
sink << "executable" << "";
dumpContents(path);
}
else if (st.type == tDirectory) {
sink << "type" << "directory";
/* If we're on a case-insensitive system like macOS, undo
the case hack applied by restorePath(). */
std::map<std::string, std::string> unhacked;
for (auto & i : readDirectory(path))
if (/* archiveSettings.useCaseHack */ false) { // FIXME
std::string name(i.first);
size_t pos = i.first.find(caseHackSuffix);
if (pos != std::string::npos) {
debug("removing case hack suffix from '%s'", path + i.first);
name.erase(pos);
}
if (!unhacked.emplace(name, i.first).second)
throw Error("file name collision in between '%s' and '%s'",
(path + unhacked[name]),
(path + i.first));
} else
unhacked.emplace(i.first, i.first);
for (auto & i : unhacked)
if (filter((path + i.first).abs())) {
sink << "entry" << "(" << "name" << i.first << "node";
dump(path + i.second);
sink << ")";
}
}
else if (st.type == tSymlink)
sink << "type" << "symlink" << "target" << readLink(path);
else throw Error("file '%s' has an unsupported type", path);
sink << ")";
};
sink << narVersionMagic1;
dump(path);
}
Hash SourceAccessor::hashPath(
const CanonPath & path,
PathFilter & filter,
HashType ht)
{
HashSink sink(ht);
dumpPath(path, sink, filter);
return sink.finish().first;
}
std::optional<SourceAccessor::Stat> SourceAccessor::maybeLstat(const CanonPath & path)
{
// FIXME: merge these into one operation.
if (!pathExists(path))
return {};
return lstat(path);
}
std::string SourceAccessor::showPath(const CanonPath & path)
{
return path.abs();
}
}

View file

@ -0,0 +1,96 @@
#pragma once
#include "canon-path.hh"
#include "hash.hh"
namespace nix {
/**
* A read-only filesystem abstraction. This is used by the Nix
* evaluator and elsewhere for accessing sources in various
* filesystem-like entities (such as the real filesystem, tarballs or
* Git repositories).
*/
struct SourceAccessor
{
const size_t number;
SourceAccessor();
virtual ~SourceAccessor()
{ }
virtual std::string readFile(const CanonPath & path) = 0;
virtual bool pathExists(const CanonPath & path) = 0;
enum Type {
tRegular, tSymlink, tDirectory,
/**
Any other node types that may be encountered on the file system, such as device nodes, sockets, named pipe, and possibly even more exotic things.
Responsible for `"unknown"` from `builtins.readFileType "/dev/null"`.
Unlike `DT_UNKNOWN`, this must not be used for deferring the lookup of types.
*/
tMisc
};
struct Stat
{
Type type = tMisc;
//uint64_t fileSize = 0; // regular files only
bool isExecutable = false; // regular files only
};
virtual Stat lstat(const CanonPath & path) = 0;
std::optional<Stat> maybeLstat(const CanonPath & path);
typedef std::optional<Type> DirEntry;
typedef std::map<std::string, DirEntry> DirEntries;
virtual DirEntries readDirectory(const CanonPath & path) = 0;
virtual std::string readLink(const CanonPath & path) = 0;
virtual void dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter = defaultPathFilter);
Hash hashPath(
const CanonPath & path,
PathFilter & filter = defaultPathFilter,
HashType ht = htSHA256);
/* Return a corresponding path in the root filesystem, if
possible. This is only possible for filesystems that are
materialized in the root filesystem. */
virtual std::optional<CanonPath> getPhysicalPath(const CanonPath & path)
{ return std::nullopt; }
bool operator == (const SourceAccessor & x) const
{
return number == x.number;
}
bool operator < (const SourceAccessor & x) const
{
return number < x.number;
}
void setPathDisplay(std::string displayPrefix, std::string displaySuffix = "");
virtual std::string showPath(const CanonPath & path);
/* Return the maximum last-modified time of the files in this
tree, if available. */
virtual std::optional<time_t> getLastModified()
{
return std::nullopt;
}
};
}