mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-22 14:06:16 +02:00
Merge FSAccessor into SourceAccessor
This commit is contained in:
parent
581693bdea
commit
1a902f5fa7
25 changed files with 178 additions and 224 deletions
|
@ -2,7 +2,7 @@
|
||||||
#include "binary-cache-store.hh"
|
#include "binary-cache-store.hh"
|
||||||
#include "compression.hh"
|
#include "compression.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "fs-accessor.hh"
|
#include "source-accessor.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "nar-info.hh"
|
#include "nar-info.hh"
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
|
@ -143,7 +143,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||||
write the compressed NAR to disk), into a HashSink (to get the
|
write the compressed NAR to disk), into a HashSink (to get the
|
||||||
NAR hash), and into a NarAccessor (to get the NAR listing). */
|
NAR hash), and into a NarAccessor (to get the NAR listing). */
|
||||||
HashSink fileHashSink { htSHA256 };
|
HashSink fileHashSink { htSHA256 };
|
||||||
std::shared_ptr<FSAccessor> narAccessor;
|
std::shared_ptr<SourceAccessor> narAccessor;
|
||||||
HashSink narHashSink { htSHA256 };
|
HashSink narHashSink { htSHA256 };
|
||||||
{
|
{
|
||||||
FdSink fileSink(fdTemp.get());
|
FdSink fileSink(fdTemp.get());
|
||||||
|
@ -195,7 +195,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||||
if (writeNARListing) {
|
if (writeNARListing) {
|
||||||
nlohmann::json j = {
|
nlohmann::json j = {
|
||||||
{"version", 1},
|
{"version", 1},
|
||||||
{"root", listNar(ref<FSAccessor>(narAccessor), "", true)},
|
{"root", listNar(ref<SourceAccessor>(narAccessor), CanonPath::root, true)},
|
||||||
};
|
};
|
||||||
|
|
||||||
upsertFile(std::string(info.path.hashPart()) + ".ls", j.dump(), "application/json");
|
upsertFile(std::string(info.path.hashPart()) + ".ls", j.dump(), "application/json");
|
||||||
|
@ -206,9 +206,9 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||||
specify the NAR file and member containing the debug info. */
|
specify the NAR file and member containing the debug info. */
|
||||||
if (writeDebugInfo) {
|
if (writeDebugInfo) {
|
||||||
|
|
||||||
std::string buildIdDir = "/lib/debug/.build-id";
|
CanonPath buildIdDir("lib/debug/.build-id");
|
||||||
|
|
||||||
if (auto st = narAccessor->stat(buildIdDir); st && st->type == SourceAccessor::tDirectory) {
|
if (auto st = narAccessor->maybeLstat(buildIdDir); st && st->type == SourceAccessor::tDirectory) {
|
||||||
|
|
||||||
ThreadPool threadPool(25);
|
ThreadPool threadPool(25);
|
||||||
|
|
||||||
|
@ -232,16 +232,16 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||||
std::regex regex2("^[0-9a-f]{38}\\.debug$");
|
std::regex regex2("^[0-9a-f]{38}\\.debug$");
|
||||||
|
|
||||||
for (auto & [s1, _type] : narAccessor->readDirectory(buildIdDir)) {
|
for (auto & [s1, _type] : narAccessor->readDirectory(buildIdDir)) {
|
||||||
auto dir = buildIdDir + "/" + s1;
|
auto dir = buildIdDir + s1;
|
||||||
|
|
||||||
if (auto st = narAccessor->stat(dir); !st || st->type != SourceAccessor::tDirectory
|
if (narAccessor->lstat(dir).type != SourceAccessor::tDirectory
|
||||||
|| !std::regex_match(s1, regex1))
|
|| !std::regex_match(s1, regex1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (auto & [s2, _type] : narAccessor->readDirectory(dir)) {
|
for (auto & [s2, _type] : narAccessor->readDirectory(dir)) {
|
||||||
auto debugPath = dir + "/" + s2;
|
auto debugPath = dir + s2;
|
||||||
|
|
||||||
if (auto st = narAccessor->stat(debugPath); !st || st->type != SourceAccessor::tRegular
|
if ( narAccessor->lstat(debugPath).type != SourceAccessor::tRegular
|
||||||
|| !std::regex_match(s2, regex2))
|
|| !std::regex_match(s2, regex2))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||||
std::string key = "debuginfo/" + buildId;
|
std::string key = "debuginfo/" + buildId;
|
||||||
std::string target = "../" + narInfo->url;
|
std::string target = "../" + narInfo->url;
|
||||||
|
|
||||||
threadPool.enqueue(std::bind(doFile, std::string(debugPath, 1), key, target));
|
threadPool.enqueue(std::bind(doFile, std::string(debugPath.rel()), key, target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,9 +503,9 @@ void BinaryCacheStore::registerDrvOutput(const Realisation& info) {
|
||||||
upsertFile(filePath, info.toJSON().dump(), "application/json");
|
upsertFile(filePath, info.toJSON().dump(), "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<FSAccessor> BinaryCacheStore::getFSAccessor()
|
ref<SourceAccessor> BinaryCacheStore::getFSAccessor(bool requireValidPath)
|
||||||
{
|
{
|
||||||
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), localNarCache);
|
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()), requireValidPath, localNarCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryCacheStore::addSignatures(const StorePath & storePath, const StringSet & sigs)
|
void BinaryCacheStore::addSignatures(const StorePath & storePath, const StringSet & sigs)
|
||||||
|
|
|
@ -148,7 +148,7 @@ public:
|
||||||
|
|
||||||
void narFromPath(const StorePath & path, Sink & sink) override;
|
void narFromPath(const StorePath & path, Sink & sink) override;
|
||||||
|
|
||||||
ref<FSAccessor> getFSAccessor() override;
|
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override;
|
||||||
|
|
||||||
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
|
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "split.hh"
|
#include "split.hh"
|
||||||
#include "common-protocol.hh"
|
#include "common-protocol.hh"
|
||||||
#include "common-protocol-impl.hh"
|
#include "common-protocol-impl.hh"
|
||||||
#include "fs-accessor.hh"
|
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
|
||||||
Callback<std::shared_ptr<const Realisation>> callback) noexcept override
|
Callback<std::shared_ptr<const Realisation>> callback) noexcept override
|
||||||
{ callback(nullptr); }
|
{ callback(nullptr); }
|
||||||
|
|
||||||
virtual ref<FSAccessor> getFSAccessor() override
|
virtual ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
|
||||||
{ unsupported("getFSAccessor"); }
|
{ unsupported("getFSAccessor"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
#pragma once
|
|
||||||
///@file
|
|
||||||
|
|
||||||
#include "types.hh"
|
|
||||||
#include "source-accessor.hh"
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
namespace nix {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An abstract class for accessing a filesystem-like structure, such
|
|
||||||
* as a (possibly remote) Nix store or the contents of a NAR file.
|
|
||||||
*/
|
|
||||||
class FSAccessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Type = SourceAccessor::Type;
|
|
||||||
|
|
||||||
struct Stat
|
|
||||||
{
|
|
||||||
Type type;
|
|
||||||
/**
|
|
||||||
* For regular files only: the size of the file.
|
|
||||||
*/
|
|
||||||
std::optional<uint64_t> fileSize;
|
|
||||||
/**
|
|
||||||
* For regular files only: whether this is an executable.
|
|
||||||
*/
|
|
||||||
bool isExecutable = false;
|
|
||||||
/**
|
|
||||||
* For regular files only: the position of the contents of this
|
|
||||||
* file in the NAR.
|
|
||||||
*/
|
|
||||||
std::optional<uint64_t> narOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~FSAccessor() { }
|
|
||||||
|
|
||||||
virtual std::optional<Stat> stat(const Path & path) = 0;
|
|
||||||
|
|
||||||
using DirEntries = SourceAccessor::DirEntries;
|
|
||||||
|
|
||||||
virtual DirEntries readDirectory(const Path & path) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a file inside the store.
|
|
||||||
*
|
|
||||||
* If `requireValidPath` is set to `true` (the default), the path must be
|
|
||||||
* inside a valid store path, otherwise it just needs to be physically
|
|
||||||
* present (but not necessarily properly registered)
|
|
||||||
*/
|
|
||||||
virtual std::string readFile(const Path & path, bool requireValidPath = true) = 0;
|
|
||||||
|
|
||||||
virtual std::string readLink(const Path & path) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -363,7 +363,7 @@ public:
|
||||||
void ensurePath(const StorePath & path) override
|
void ensurePath(const StorePath & path) override
|
||||||
{ unsupported("ensurePath"); }
|
{ unsupported("ensurePath"); }
|
||||||
|
|
||||||
virtual ref<FSAccessor> getFSAccessor() override
|
virtual ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
|
||||||
{ unsupported("getFSAccessor"); }
|
{ unsupported("getFSAccessor"); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "fs-accessor.hh"
|
#include "source-accessor.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "local-fs-store.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
|
@ -13,26 +13,31 @@ LocalFSStore::LocalFSStore(const Params & params)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LocalStoreAccessor : public FSAccessor
|
struct LocalStoreAccessor : public SourceAccessor
|
||||||
{
|
{
|
||||||
ref<LocalFSStore> store;
|
ref<LocalFSStore> store;
|
||||||
|
bool requireValidPath;
|
||||||
|
|
||||||
LocalStoreAccessor(ref<LocalFSStore> store) : store(store) { }
|
LocalStoreAccessor(ref<LocalFSStore> store, bool requireValidPath)
|
||||||
|
: store(store)
|
||||||
|
, requireValidPath(requireValidPath)
|
||||||
|
{ }
|
||||||
|
|
||||||
Path toRealPath(const Path & path, bool requireValidPath = true)
|
Path toRealPath(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto storePath = store->toStorePath(path).first;
|
auto storePath = store->toStorePath(path.abs()).first;
|
||||||
if (requireValidPath && !store->isValidPath(storePath))
|
if (requireValidPath && !store->isValidPath(storePath))
|
||||||
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
|
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
|
||||||
return store->getRealStoreDir() + std::string(path, store->storeDir.size());
|
return store->getRealStoreDir() + path.abs().substr(store->storeDir.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FSAccessor::Stat> stat(const Path & path) override
|
std::optional<Stat> maybeLstat(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
auto realPath = toRealPath(path);
|
auto realPath = toRealPath(path);
|
||||||
|
|
||||||
|
// FIXME: use PosixSourceAccessor.
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(realPath.c_str(), &st)) {
|
if (::lstat(realPath.c_str(), &st)) {
|
||||||
if (errno == ENOENT || errno == ENOTDIR) return std::nullopt;
|
if (errno == ENOENT || errno == ENOTDIR) return std::nullopt;
|
||||||
throw SysError("getting status of '%1%'", path);
|
throw SysError("getting status of '%1%'", path);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +53,7 @@ struct LocalStoreAccessor : public FSAccessor
|
||||||
S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}};
|
S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}};
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntries readDirectory(const Path & path) override
|
DirEntries readDirectory(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
auto realPath = toRealPath(path);
|
auto realPath = toRealPath(path);
|
||||||
|
|
||||||
|
@ -61,21 +66,22 @@ struct LocalStoreAccessor : public FSAccessor
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readFile(const Path & path, bool requireValidPath = true) override
|
std::string readFile(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
return nix::readFile(toRealPath(path, requireValidPath));
|
return nix::readFile(toRealPath(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readLink(const Path & path) override
|
std::string readLink(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
return nix::readLink(toRealPath(path));
|
return nix::readLink(toRealPath(path));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ref<FSAccessor> LocalFSStore::getFSAccessor()
|
ref<SourceAccessor> LocalFSStore::getFSAccessor(bool requireValidPath)
|
||||||
{
|
{
|
||||||
return make_ref<LocalStoreAccessor>(ref<LocalFSStore>(
|
return make_ref<LocalStoreAccessor>(ref<LocalFSStore>(
|
||||||
std::dynamic_pointer_cast<LocalFSStore>(shared_from_this())));
|
std::dynamic_pointer_cast<LocalFSStore>(shared_from_this())),
|
||||||
|
requireValidPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalFSStore::narFromPath(const StorePath & path, Sink & sink)
|
void LocalFSStore::narFromPath(const StorePath & path, Sink & sink)
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
LocalFSStore(const Params & params);
|
LocalFSStore(const Params & params);
|
||||||
|
|
||||||
void narFromPath(const StorePath & path, Sink & sink) override;
|
void narFromPath(const StorePath & path, Sink & sink) override;
|
||||||
ref<FSAccessor> getFSAccessor() override;
|
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates symlink from the `gcRoot` to the `storePath` and
|
* Creates symlink from the `gcRoot` to the `storePath` and
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace nix {
|
||||||
|
|
||||||
struct NarMember
|
struct NarMember
|
||||||
{
|
{
|
||||||
FSAccessor::Stat stat;
|
SourceAccessor::Stat stat;
|
||||||
|
|
||||||
std::string target;
|
std::string target;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ struct NarMember
|
||||||
std::map<std::string, NarMember> children;
|
std::map<std::string, NarMember> children;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NarAccessor : public FSAccessor
|
struct NarAccessor : public SourceAccessor
|
||||||
{
|
{
|
||||||
std::optional<const std::string> nar;
|
std::optional<const std::string> nar;
|
||||||
|
|
||||||
|
@ -149,48 +149,36 @@ struct NarAccessor : public FSAccessor
|
||||||
recurse(root, v);
|
recurse(root, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
NarMember * find(const Path & path)
|
NarMember * find(const CanonPath & path)
|
||||||
{
|
{
|
||||||
Path canon = path == "" ? "" : canonPath(path);
|
|
||||||
NarMember * current = &root;
|
NarMember * current = &root;
|
||||||
auto end = path.end();
|
|
||||||
for (auto it = path.begin(); it != end; ) {
|
for (auto & i : path) {
|
||||||
// because it != end, the remaining component is non-empty so we need
|
|
||||||
// a directory
|
|
||||||
if (current->stat.type != Type::tDirectory) return nullptr;
|
if (current->stat.type != Type::tDirectory) return nullptr;
|
||||||
|
auto child = current->children.find(std::string(i));
|
||||||
// skip slash (canonPath above ensures that this is always a slash)
|
|
||||||
assert(*it == '/');
|
|
||||||
it += 1;
|
|
||||||
|
|
||||||
// lookup current component
|
|
||||||
auto next = std::find(it, end, '/');
|
|
||||||
auto child = current->children.find(std::string(it, next));
|
|
||||||
if (child == current->children.end()) return nullptr;
|
if (child == current->children.end()) return nullptr;
|
||||||
current = &child->second;
|
current = &child->second;
|
||||||
|
|
||||||
it = next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
NarMember & get(const Path & path) {
|
NarMember & get(const CanonPath & path) {
|
||||||
auto result = find(path);
|
auto result = find(path);
|
||||||
if (result == nullptr)
|
if (!result)
|
||||||
throw Error("NAR file does not contain path '%1%'", path);
|
throw Error("NAR file does not contain path '%1%'", path);
|
||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Stat> stat(const Path & path) override
|
std::optional<Stat> maybeLstat(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
auto i = find(path);
|
auto i = find(path);
|
||||||
if (i == nullptr)
|
if (!i)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return i->stat;
|
return i->stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntries readDirectory(const Path & path) override
|
DirEntries readDirectory(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
auto i = get(path);
|
auto i = get(path);
|
||||||
|
|
||||||
|
@ -204,7 +192,7 @@ struct NarAccessor : public FSAccessor
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readFile(const Path & path, bool requireValidPath = true) override
|
std::string readFile(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
auto i = get(path);
|
auto i = get(path);
|
||||||
if (i.stat.type != Type::tRegular)
|
if (i.stat.type != Type::tRegular)
|
||||||
|
@ -216,7 +204,7 @@ struct NarAccessor : public FSAccessor
|
||||||
return std::string(*nar, *i.stat.narOffset, *i.stat.fileSize);
|
return std::string(*nar, *i.stat.narOffset, *i.stat.fileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readLink(const Path & path) override
|
std::string readLink(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
auto i = get(path);
|
auto i = get(path);
|
||||||
if (i.stat.type != Type::tSymlink)
|
if (i.stat.type != Type::tSymlink)
|
||||||
|
@ -225,40 +213,38 @@ struct NarAccessor : public FSAccessor
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ref<FSAccessor> makeNarAccessor(std::string && nar)
|
ref<SourceAccessor> makeNarAccessor(std::string && nar)
|
||||||
{
|
{
|
||||||
return make_ref<NarAccessor>(std::move(nar));
|
return make_ref<NarAccessor>(std::move(nar));
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<FSAccessor> makeNarAccessor(Source & source)
|
ref<SourceAccessor> makeNarAccessor(Source & source)
|
||||||
{
|
{
|
||||||
return make_ref<NarAccessor>(source);
|
return make_ref<NarAccessor>(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<FSAccessor> makeLazyNarAccessor(const std::string & listing,
|
ref<SourceAccessor> makeLazyNarAccessor(const std::string & listing,
|
||||||
GetNarBytes getNarBytes)
|
GetNarBytes getNarBytes)
|
||||||
{
|
{
|
||||||
return make_ref<NarAccessor>(listing, getNarBytes);
|
return make_ref<NarAccessor>(listing, getNarBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse)
|
json listNar(ref<SourceAccessor> accessor, const CanonPath & path, bool recurse)
|
||||||
{
|
{
|
||||||
auto st = accessor->stat(path);
|
auto st = accessor->lstat(path);
|
||||||
if (!st)
|
|
||||||
throw Error("path '%s' does not exist in NAR", path);
|
|
||||||
|
|
||||||
json obj = json::object();
|
json obj = json::object();
|
||||||
|
|
||||||
switch (st->type) {
|
switch (st.type) {
|
||||||
case SourceAccessor::Type::tRegular:
|
case SourceAccessor::Type::tRegular:
|
||||||
obj["type"] = "regular";
|
obj["type"] = "regular";
|
||||||
if (st->fileSize)
|
if (st.fileSize)
|
||||||
obj["size"] = *st->fileSize;
|
obj["size"] = *st.fileSize;
|
||||||
if (st->isExecutable)
|
if (st.isExecutable)
|
||||||
obj["executable"] = true;
|
obj["executable"] = true;
|
||||||
if (st->narOffset && *st->narOffset)
|
if (st.narOffset && *st.narOffset)
|
||||||
obj["narOffset"] = *st->narOffset;
|
obj["narOffset"] = *st.narOffset;
|
||||||
break;
|
break;
|
||||||
case SourceAccessor::Type::tDirectory:
|
case SourceAccessor::Type::tDirectory:
|
||||||
obj["type"] = "directory";
|
obj["type"] = "directory";
|
||||||
|
@ -267,7 +253,7 @@ json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse)
|
||||||
json &res2 = obj["entries"];
|
json &res2 = obj["entries"];
|
||||||
for (auto & [name, type] : accessor->readDirectory(path)) {
|
for (auto & [name, type] : accessor->readDirectory(path)) {
|
||||||
if (recurse) {
|
if (recurse) {
|
||||||
res2[name] = listNar(accessor, path + "/" + name, true);
|
res2[name] = listNar(accessor, path + name, true);
|
||||||
} else
|
} else
|
||||||
res2[name] = json::object();
|
res2[name] = json::object();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
|
#include "source-accessor.hh"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include "fs-accessor.hh"
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -14,9 +15,9 @@ struct Source;
|
||||||
* Return an object that provides access to the contents of a NAR
|
* Return an object that provides access to the contents of a NAR
|
||||||
* file.
|
* file.
|
||||||
*/
|
*/
|
||||||
ref<FSAccessor> makeNarAccessor(std::string && nar);
|
ref<SourceAccessor> makeNarAccessor(std::string && nar);
|
||||||
|
|
||||||
ref<FSAccessor> makeNarAccessor(Source & source);
|
ref<SourceAccessor> makeNarAccessor(Source & source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a NAR accessor from a NAR listing (in the format produced by
|
* Create a NAR accessor from a NAR listing (in the format produced by
|
||||||
|
@ -26,7 +27,7 @@ ref<FSAccessor> makeNarAccessor(Source & source);
|
||||||
*/
|
*/
|
||||||
typedef std::function<std::string(uint64_t, uint64_t)> GetNarBytes;
|
typedef std::function<std::string(uint64_t, uint64_t)> GetNarBytes;
|
||||||
|
|
||||||
ref<FSAccessor> makeLazyNarAccessor(
|
ref<SourceAccessor> makeLazyNarAccessor(
|
||||||
const std::string & listing,
|
const std::string & listing,
|
||||||
GetNarBytes getNarBytes);
|
GetNarBytes getNarBytes);
|
||||||
|
|
||||||
|
@ -34,6 +35,6 @@ ref<FSAccessor> makeLazyNarAccessor(
|
||||||
* Write a JSON representation of the contents of a NAR (except file
|
* Write a JSON representation of the contents of a NAR (except file
|
||||||
* contents).
|
* contents).
|
||||||
*/
|
*/
|
||||||
nlohmann::json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse);
|
nlohmann::json listNar(ref<SourceAccessor> accessor, const CanonPath & path, bool recurse);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
RemoteFSAccessor::RemoteFSAccessor(ref<Store> store, const Path & cacheDir)
|
RemoteFSAccessor::RemoteFSAccessor(ref<Store> store, bool requireValidPath, const Path & cacheDir)
|
||||||
: store(store)
|
: store(store)
|
||||||
|
, requireValidPath(requireValidPath)
|
||||||
, cacheDir(cacheDir)
|
, cacheDir(cacheDir)
|
||||||
{
|
{
|
||||||
if (cacheDir != "")
|
if (cacheDir != "")
|
||||||
|
@ -22,7 +23,7 @@ Path RemoteFSAccessor::makeCacheFile(std::string_view hashPart, const std::strin
|
||||||
return fmt("%s/%s.%s", cacheDir, hashPart, ext);
|
return fmt("%s/%s.%s", cacheDir, hashPart, ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<FSAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std::string && nar)
|
ref<SourceAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std::string && nar)
|
||||||
{
|
{
|
||||||
if (cacheDir != "") {
|
if (cacheDir != "") {
|
||||||
try {
|
try {
|
||||||
|
@ -38,7 +39,7 @@ ref<FSAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std::str
|
||||||
|
|
||||||
if (cacheDir != "") {
|
if (cacheDir != "") {
|
||||||
try {
|
try {
|
||||||
nlohmann::json j = listNar(narAccessor, "", true);
|
nlohmann::json j = listNar(narAccessor, CanonPath::root, true);
|
||||||
writeFile(makeCacheFile(hashPart, "ls"), j.dump());
|
writeFile(makeCacheFile(hashPart, "ls"), j.dump());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ignoreException();
|
ignoreException();
|
||||||
|
@ -48,11 +49,10 @@ ref<FSAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std::str
|
||||||
return narAccessor;
|
return narAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_, bool requireValidPath)
|
std::pair<ref<SourceAccessor>, CanonPath> RemoteFSAccessor::fetch(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto path = canonPath(path_);
|
auto [storePath, restPath_] = store->toStorePath(path.abs());
|
||||||
|
auto restPath = CanonPath(restPath_);
|
||||||
auto [storePath, restPath] = store->toStorePath(path);
|
|
||||||
|
|
||||||
if (requireValidPath && !store->isValidPath(storePath))
|
if (requireValidPath && !store->isValidPath(storePath))
|
||||||
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
|
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
|
||||||
|
@ -63,7 +63,7 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_, boo
|
||||||
std::string listing;
|
std::string listing;
|
||||||
Path cacheFile;
|
Path cacheFile;
|
||||||
|
|
||||||
if (cacheDir != "" && pathExists(cacheFile = makeCacheFile(storePath.hashPart(), "nar"))) {
|
if (cacheDir != "" && nix::pathExists(cacheFile = makeCacheFile(storePath.hashPart(), "nar"))) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
listing = nix::readFile(makeCacheFile(storePath.hashPart(), "ls"));
|
listing = nix::readFile(makeCacheFile(storePath.hashPart(), "ls"));
|
||||||
|
@ -101,25 +101,25 @@ std::pair<ref<FSAccessor>, Path> RemoteFSAccessor::fetch(const Path & path_, boo
|
||||||
return {addToCache(storePath.hashPart(), std::move(sink.s)), restPath};
|
return {addToCache(storePath.hashPart(), std::move(sink.s)), restPath};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<FSAccessor::Stat> RemoteFSAccessor::stat(const Path & path)
|
std::optional<SourceAccessor::Stat> RemoteFSAccessor::maybeLstat(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto res = fetch(path);
|
auto res = fetch(path);
|
||||||
return res.first->stat(res.second);
|
return res.first->maybeLstat(res.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceAccessor::DirEntries RemoteFSAccessor::readDirectory(const Path & path)
|
SourceAccessor::DirEntries RemoteFSAccessor::readDirectory(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto res = fetch(path);
|
auto res = fetch(path);
|
||||||
return res.first->readDirectory(res.second);
|
return res.first->readDirectory(res.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RemoteFSAccessor::readFile(const Path & path, bool requireValidPath)
|
std::string RemoteFSAccessor::readFile(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto res = fetch(path, requireValidPath);
|
auto res = fetch(path);
|
||||||
return res.first->readFile(res.second);
|
return res.first->readFile(res.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RemoteFSAccessor::readLink(const Path & path)
|
std::string RemoteFSAccessor::readLink(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto res = fetch(path);
|
auto res = fetch(path);
|
||||||
return res.first->readLink(res.second);
|
return res.first->readLink(res.second);
|
||||||
|
|
|
@ -1,40 +1,43 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "fs-accessor.hh"
|
#include "source-accessor.hh"
|
||||||
#include "ref.hh"
|
#include "ref.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
class RemoteFSAccessor : public FSAccessor
|
class RemoteFSAccessor : public SourceAccessor
|
||||||
{
|
{
|
||||||
ref<Store> store;
|
ref<Store> store;
|
||||||
|
|
||||||
std::map<std::string, ref<FSAccessor>> nars;
|
std::map<std::string, ref<SourceAccessor>> nars;
|
||||||
|
|
||||||
|
bool requireValidPath;
|
||||||
|
|
||||||
Path cacheDir;
|
Path cacheDir;
|
||||||
|
|
||||||
std::pair<ref<FSAccessor>, Path> fetch(const Path & path_, bool requireValidPath = true);
|
std::pair<ref<SourceAccessor>, CanonPath> fetch(const CanonPath & path);
|
||||||
|
|
||||||
friend class BinaryCacheStore;
|
friend class BinaryCacheStore;
|
||||||
|
|
||||||
Path makeCacheFile(std::string_view hashPart, const std::string & ext);
|
Path makeCacheFile(std::string_view hashPart, const std::string & ext);
|
||||||
|
|
||||||
ref<FSAccessor> addToCache(std::string_view hashPart, std::string && nar);
|
ref<SourceAccessor> addToCache(std::string_view hashPart, std::string && nar);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RemoteFSAccessor(ref<Store> store,
|
RemoteFSAccessor(ref<Store> store,
|
||||||
|
bool requireValidPath = true,
|
||||||
const /* FIXME: use std::optional */ Path & cacheDir = "");
|
const /* FIXME: use std::optional */ Path & cacheDir = "");
|
||||||
|
|
||||||
std::optional<Stat> stat(const Path & path) override;
|
std::optional<Stat> maybeLstat(const CanonPath & path) override;
|
||||||
|
|
||||||
DirEntries readDirectory(const Path & path) override;
|
DirEntries readDirectory(const CanonPath & path) override;
|
||||||
|
|
||||||
std::string readFile(const Path & path, bool requireValidPath = true) override;
|
std::string readFile(const CanonPath & path) override;
|
||||||
|
|
||||||
std::string readLink(const Path & path) override;
|
std::string readLink(const CanonPath & path) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -970,7 +970,7 @@ void RemoteStore::narFromPath(const StorePath & path, Sink & sink)
|
||||||
copyNAR(conn->from, sink);
|
copyNAR(conn->from, sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<FSAccessor> RemoteStore::getFSAccessor()
|
ref<SourceAccessor> RemoteStore::getFSAccessor(bool requireValidPath)
|
||||||
{
|
{
|
||||||
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()));
|
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ protected:
|
||||||
|
|
||||||
friend struct ConnectionHandle;
|
friend struct ConnectionHandle;
|
||||||
|
|
||||||
virtual ref<FSAccessor> getFSAccessor() override;
|
virtual ref<SourceAccessor> getFSAccessor(bool requireValidPath) override;
|
||||||
|
|
||||||
virtual void narFromPath(const StorePath & path, Sink & sink) override;
|
virtual void narFromPath(const StorePath & path, Sink & sink) override;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "crypto.hh"
|
#include "crypto.hh"
|
||||||
#include "fs-accessor.hh"
|
#include "source-accessor.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
@ -1338,12 +1338,12 @@ Derivation Store::derivationFromPath(const StorePath & drvPath)
|
||||||
return readDerivation(drvPath);
|
return readDerivation(drvPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Derivation readDerivationCommon(Store& store, const StorePath& drvPath, bool requireValidPath)
|
static Derivation readDerivationCommon(Store & store, const StorePath & drvPath, bool requireValidPath)
|
||||||
{
|
{
|
||||||
auto accessor = store.getFSAccessor();
|
auto accessor = store.getFSAccessor(requireValidPath);
|
||||||
try {
|
try {
|
||||||
return parseDerivation(store,
|
return parseDerivation(store,
|
||||||
accessor->readFile(store.printStorePath(drvPath), requireValidPath),
|
accessor->readFile(CanonPath(store.printStorePath(drvPath))),
|
||||||
Derivation::nameFromPath(drvPath));
|
Derivation::nameFromPath(drvPath));
|
||||||
} catch (FormatError & e) {
|
} catch (FormatError & e) {
|
||||||
throw Error("error parsing derivation '%s': %s", store.printStorePath(drvPath), e.msg());
|
throw Error("error parsing derivation '%s': %s", store.printStorePath(drvPath), e.msg());
|
||||||
|
|
|
@ -70,7 +70,7 @@ MakeError(InvalidStoreURI, Error);
|
||||||
|
|
||||||
struct BasicDerivation;
|
struct BasicDerivation;
|
||||||
struct Derivation;
|
struct Derivation;
|
||||||
class FSAccessor;
|
struct SourceAccessor;
|
||||||
class NarInfoDiskCache;
|
class NarInfoDiskCache;
|
||||||
class Store;
|
class Store;
|
||||||
|
|
||||||
|
@ -703,7 +703,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return An object to access files in the Nix store.
|
* @return An object to access files in the Nix store.
|
||||||
*/
|
*/
|
||||||
virtual ref<FSAccessor> getFSAccessor() = 0;
|
virtual ref<SourceAccessor> getFSAccessor(bool requireValidPath = true) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repair the contents of the given path by redownloading it using
|
* Repair the contents of the given path by redownloading it using
|
||||||
|
|
|
@ -35,8 +35,8 @@ public:
|
||||||
static std::set<std::string> uriSchemes()
|
static std::set<std::string> uriSchemes()
|
||||||
{ return {"unix"}; }
|
{ return {"unix"}; }
|
||||||
|
|
||||||
ref<FSAccessor> getFSAccessor() override
|
ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
|
||||||
{ return LocalFSStore::getFSAccessor(); }
|
{ return LocalFSStore::getFSAccessor(requireValidPath); }
|
||||||
|
|
||||||
void narFromPath(const StorePath & path, Sink & sink) override
|
void narFromPath(const StorePath & path, Sink & sink) override
|
||||||
{ LocalFSStore::narFromPath(path, sink); }
|
{ LocalFSStore::narFromPath(path, sink); }
|
||||||
|
|
|
@ -10,6 +10,11 @@ SourceAccessor::SourceAccessor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SourceAccessor::pathExists(const CanonPath & path)
|
||||||
|
{
|
||||||
|
return maybeLstat(path).has_value();
|
||||||
|
}
|
||||||
|
|
||||||
std::string SourceAccessor::readFile(const CanonPath & path)
|
std::string SourceAccessor::readFile(const CanonPath & path)
|
||||||
{
|
{
|
||||||
StringSink sink;
|
StringSink sink;
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct SourceAccessor
|
||||||
Sink & sink,
|
Sink & sink,
|
||||||
std::function<void(uint64_t)> sizeCallback = [](uint64_t size){});
|
std::function<void(uint64_t)> sizeCallback = [](uint64_t size){});
|
||||||
|
|
||||||
virtual bool pathExists(const CanonPath & path) = 0;
|
virtual bool pathExists(const CanonPath & path);
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
tRegular, tSymlink, tDirectory,
|
tRegular, tSymlink, tDirectory,
|
||||||
|
@ -57,8 +57,24 @@ struct SourceAccessor
|
||||||
struct Stat
|
struct Stat
|
||||||
{
|
{
|
||||||
Type type = tMisc;
|
Type type = tMisc;
|
||||||
//uint64_t fileSize = 0; // regular files only
|
|
||||||
bool isExecutable = false; // regular files only
|
/**
|
||||||
|
* For regular files only: the size of the file. Not all
|
||||||
|
* accessors return this since it may be too expensive to
|
||||||
|
* compute.
|
||||||
|
*/
|
||||||
|
std::optional<uint64_t> fileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For regular files only: whether this is an executable.
|
||||||
|
*/
|
||||||
|
bool isExecutable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For regular files only: the position of the contents of this
|
||||||
|
* file in the NAR. Only returned by NAR accessors.
|
||||||
|
*/
|
||||||
|
std::optional<uint64_t> narOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
Stat lstat(const CanonPath & path);
|
Stat lstat(const CanonPath & path);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "local-fs-store.hh"
|
||||||
#include "fs-accessor.hh"
|
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "fs-accessor.hh"
|
|
||||||
#include "nar-accessor.hh"
|
#include "nar-accessor.hh"
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
@ -9,14 +8,12 @@ struct MixCat : virtual Args
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
void cat(ref<FSAccessor> accessor)
|
void cat(ref<SourceAccessor> accessor)
|
||||||
{
|
{
|
||||||
if (auto st = accessor->stat(path)) {
|
auto st = accessor->lstat(CanonPath(path));
|
||||||
if (st->type != FSAccessor::Type::tRegular)
|
if (st.type != SourceAccessor::Type::tRegular)
|
||||||
throw Error("path '%1%' is not a regular file", path);
|
throw Error("path '%1%' is not a regular file", path);
|
||||||
writeFull(STDOUT_FILENO, accessor->readFile(path));
|
writeFull(STDOUT_FILENO, accessor->readFile(CanonPath(path)));
|
||||||
} else
|
|
||||||
throw Error("path '%1%' does not exist", path);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "fs-accessor.hh"
|
|
||||||
#include "nar-accessor.hh"
|
#include "nar-accessor.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
@ -39,63 +38,58 @@ struct MixLs : virtual Args, MixJSON
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void listText(ref<FSAccessor> accessor)
|
void listText(ref<SourceAccessor> accessor)
|
||||||
{
|
{
|
||||||
std::function<void(const FSAccessor::Stat &, const Path &, const std::string &, bool)> doPath;
|
std::function<void(const SourceAccessor::Stat &, const CanonPath &, std::string_view, bool)> doPath;
|
||||||
|
|
||||||
auto showFile = [&](const Path & curPath, const std::string & relPath) {
|
auto showFile = [&](const CanonPath & curPath, std::string_view relPath) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
auto st = accessor->stat(curPath);
|
auto st = accessor->lstat(curPath);
|
||||||
assert(st);
|
|
||||||
std::string tp =
|
std::string tp =
|
||||||
st->type == FSAccessor::Type::tRegular ?
|
st.type == SourceAccessor::Type::tRegular ?
|
||||||
(st->isExecutable ? "-r-xr-xr-x" : "-r--r--r--") :
|
(st.isExecutable ? "-r-xr-xr-x" : "-r--r--r--") :
|
||||||
st->type == FSAccessor::Type::tSymlink ? "lrwxrwxrwx" :
|
st.type == SourceAccessor::Type::tSymlink ? "lrwxrwxrwx" :
|
||||||
"dr-xr-xr-x";
|
"dr-xr-xr-x";
|
||||||
auto line = fmt("%s %20d %s", tp, st->fileSize.value_or(0), relPath);
|
auto line = fmt("%s %20d %s", tp, st.fileSize.value_or(0), relPath);
|
||||||
if (st->type == FSAccessor::Type::tSymlink)
|
if (st.type == SourceAccessor::Type::tSymlink)
|
||||||
line += " -> " + accessor->readLink(curPath);
|
line += " -> " + accessor->readLink(curPath);
|
||||||
logger->cout(line);
|
logger->cout(line);
|
||||||
if (recursive && st->type == FSAccessor::Type::tDirectory)
|
if (recursive && st.type == SourceAccessor::Type::tDirectory)
|
||||||
doPath(*st, curPath, relPath, false);
|
doPath(st, curPath, relPath, false);
|
||||||
} else {
|
} else {
|
||||||
logger->cout(relPath);
|
logger->cout(relPath);
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
auto st = accessor->stat(curPath);
|
auto st = accessor->lstat(curPath);
|
||||||
assert(st);
|
if (st.type == SourceAccessor::Type::tDirectory)
|
||||||
if (st->type == FSAccessor::Type::tDirectory)
|
doPath(st, curPath, relPath, false);
|
||||||
doPath(*st, curPath, relPath, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
doPath = [&](const FSAccessor::Stat & st, const Path & curPath,
|
doPath = [&](const SourceAccessor::Stat & st, const CanonPath & curPath,
|
||||||
const std::string & relPath, bool showDirectory)
|
std::string_view relPath, bool showDirectory)
|
||||||
{
|
{
|
||||||
if (st.type == FSAccessor::Type::tDirectory && !showDirectory) {
|
if (st.type == SourceAccessor::Type::tDirectory && !showDirectory) {
|
||||||
auto names = accessor->readDirectory(curPath);
|
auto names = accessor->readDirectory(curPath);
|
||||||
for (auto & [name, type] : names)
|
for (auto & [name, type] : names)
|
||||||
showFile(curPath + "/" + name, relPath + "/" + name);
|
showFile(curPath + name, relPath + "/" + name);
|
||||||
} else
|
} else
|
||||||
showFile(curPath, relPath);
|
showFile(curPath, relPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto st = accessor->stat(path);
|
auto path2 = CanonPath(path);
|
||||||
if (!st)
|
auto st = accessor->lstat(path2);
|
||||||
throw Error("path '%1%' does not exist", path);
|
doPath(st, path2,
|
||||||
doPath(*st, path,
|
st.type == SourceAccessor::Type::tDirectory ? "." : path2.baseName().value_or(""),
|
||||||
st->type == FSAccessor::Type::tDirectory ? "." : std::string(baseNameOf(path)),
|
|
||||||
showDirectory);
|
showDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void list(ref<FSAccessor> accessor)
|
void list(ref<SourceAccessor> accessor)
|
||||||
{
|
{
|
||||||
if (path == "/") path = "";
|
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
if (showDirectory)
|
if (showDirectory)
|
||||||
throw UsageError("'--directory' is useless with '--json'");
|
throw UsageError("'--directory' is useless with '--json'");
|
||||||
logger->cout("%s", listNar(accessor, path, recursive));
|
logger->cout("%s", listNar(accessor, CanonPath(path), recursive));
|
||||||
} else
|
} else
|
||||||
listText(accessor);
|
listText(accessor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "local-store.hh"
|
#include "local-store.hh"
|
||||||
#include "finally.hh"
|
#include "finally.hh"
|
||||||
#include "fs-accessor.hh"
|
#include "source-accessor.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "build/personality.hh"
|
#include "build/personality.hh"
|
||||||
|
@ -119,9 +119,9 @@ struct CmdShell : InstallablesCommand, MixEnvironment
|
||||||
if (true)
|
if (true)
|
||||||
unixPath.push_front(store->printStorePath(path) + "/bin");
|
unixPath.push_front(store->printStorePath(path) + "/bin");
|
||||||
|
|
||||||
auto propPath = store->printStorePath(path) + "/nix-support/propagated-user-env-packages";
|
auto propPath = CanonPath(store->printStorePath(path)) + "nix-support" + "propagated-user-env-packages";
|
||||||
if (auto st = accessor->stat(propPath); st && st->type == SourceAccessor::tRegular) {
|
if (auto st = accessor->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) {
|
||||||
for (auto & p : tokenizeString<Paths>(readFile(propPath)))
|
for (auto & p : tokenizeString<Paths>(accessor->readFile(propPath)))
|
||||||
todo.push(store->parseStorePath(p));
|
todo.push(store->parseStorePath(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
#include "fs-accessor.hh"
|
#include "source-accessor.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
@ -175,7 +175,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
|
||||||
struct BailOut { };
|
struct BailOut { };
|
||||||
|
|
||||||
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
|
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
|
||||||
auto pathS = store->printStorePath(node.path);
|
CanonPath pathS(store->printStorePath(node.path));
|
||||||
|
|
||||||
assert(node.dist != inf);
|
assert(node.dist != inf);
|
||||||
if (precise) {
|
if (precise) {
|
||||||
|
@ -183,7 +183,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
|
||||||
firstPad,
|
firstPad,
|
||||||
node.visited ? "\e[38;5;244m" : "",
|
node.visited ? "\e[38;5;244m" : "",
|
||||||
firstPad != "" ? "→ " : "",
|
firstPad != "" ? "→ " : "",
|
||||||
pathS);
|
pathS.abs());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.path == dependencyPath && !all
|
if (node.path == dependencyPath && !all
|
||||||
|
@ -210,25 +210,25 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
|
||||||
contain the reference. */
|
contain the reference. */
|
||||||
std::map<std::string, Strings> hits;
|
std::map<std::string, Strings> hits;
|
||||||
|
|
||||||
std::function<void(const Path &)> visitPath;
|
std::function<void(const CanonPath &)> visitPath;
|
||||||
|
|
||||||
visitPath = [&](const Path & p) {
|
visitPath = [&](const CanonPath & p) {
|
||||||
auto st = accessor->stat(p);
|
auto st = accessor->maybeLstat(p);
|
||||||
assert(st);
|
assert(st);
|
||||||
|
|
||||||
auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1);
|
auto p2 = p == pathS ? "/" : p.abs().substr(pathS.abs().size() + 1);
|
||||||
|
|
||||||
auto getColour = [&](const std::string & hash) {
|
auto getColour = [&](const std::string & hash) {
|
||||||
return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
|
return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (st->type == FSAccessor::Type::tDirectory) {
|
if (st->type == SourceAccessor::Type::tDirectory) {
|
||||||
auto names = accessor->readDirectory(p);
|
auto names = accessor->readDirectory(p);
|
||||||
for (auto & [name, type] : names)
|
for (auto & [name, type] : names)
|
||||||
visitPath(p + "/" + name);
|
visitPath(p + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (st->type == FSAccessor::Type::tRegular) {
|
else if (st->type == SourceAccessor::Type::tRegular) {
|
||||||
auto contents = accessor->readFile(p);
|
auto contents = accessor->readFile(p);
|
||||||
|
|
||||||
for (auto & hash : hashes) {
|
for (auto & hash : hashes) {
|
||||||
|
@ -246,7 +246,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (st->type == FSAccessor::Type::tSymlink) {
|
else if (st->type == SourceAccessor::Type::tSymlink) {
|
||||||
auto target = accessor->readLink(p);
|
auto target = accessor->readLink(p);
|
||||||
|
|
||||||
for (auto & hash : hashes) {
|
for (auto & hash : hashes) {
|
||||||
|
|
|
@ -25,6 +25,12 @@ diff -u baz.cat-nar $storePath/foo/baz
|
||||||
nix store cat $storePath/foo/baz > baz.cat-nar
|
nix store cat $storePath/foo/baz > baz.cat-nar
|
||||||
diff -u baz.cat-nar $storePath/foo/baz
|
diff -u baz.cat-nar $storePath/foo/baz
|
||||||
|
|
||||||
|
# Check that 'nix store cat' fails on invalid store paths.
|
||||||
|
invalidPath="$(dirname $storePath)/99999999999999999999999999999999-foo"
|
||||||
|
mv $storePath $invalidPath
|
||||||
|
(! nix store cat $invalidPath/foo/baz)
|
||||||
|
mv $invalidPath $storePath
|
||||||
|
|
||||||
# Test --json.
|
# Test --json.
|
||||||
diff -u \
|
diff -u \
|
||||||
<(nix nar ls --json $narFile / | jq -S) \
|
<(nix nar ls --json $narFile / | jq -S) \
|
||||||
|
@ -46,7 +52,7 @@ diff -u \
|
||||||
<(echo '{"type":"regular","size":0}' | jq -S)
|
<(echo '{"type":"regular","size":0}' | jq -S)
|
||||||
|
|
||||||
# Test missing files.
|
# Test missing files.
|
||||||
expect 1 nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
|
expect 1 nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist'
|
||||||
expect 1 nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
|
expect 1 nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
|
||||||
|
|
||||||
# Test failure to dump.
|
# Test failure to dump.
|
||||||
|
|
Loading…
Reference in a new issue