forked from lix-project/lix
Move most of InputAccessor into libutil
This commit is contained in:
parent
06c57899e3
commit
fb6a3910c4
|
@ -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};
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
108
src/libutil/source-accessor.cc
Normal file
108
src/libutil/source-accessor.cc
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
96
src/libutil/source-accessor.hh
Normal file
96
src/libutil/source-accessor.hh
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue