forked from lix-project/lix
Merge pull request #9634 from 9999years/combine-abstract-pos-and-pos
Combine `AbstractPos`, `PosAdapter`, and `Pos`
This commit is contained in:
commit
113499d16f
|
@ -1,5 +1,6 @@
|
|||
#include "editor-for.hh"
|
||||
#include "environment-variables.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "input-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "installable-value.hh"
|
||||
#include "eval-cache.hh"
|
||||
#include "fetch-to-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -44,7 +45,7 @@ ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
|
|||
std::optional<DerivedPathWithInfo> InstallableValue::trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx)
|
||||
{
|
||||
if (v.type() == nPath) {
|
||||
auto storePath = v.path().fetchToStore(*state->store);
|
||||
auto storePath = fetchToStore(*state->store, v.path());
|
||||
return {{
|
||||
.path = DerivedPath::Opaque {
|
||||
.path = std::move(storePath),
|
||||
|
|
|
@ -221,7 +221,7 @@ static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positi
|
|||
// prefer direct pos, but if noPos then try the expr.
|
||||
auto pos = dt.pos
|
||||
? dt.pos
|
||||
: static_cast<std::shared_ptr<AbstractPos>>(positions[dt.expr.getPos() ? dt.expr.getPos() : noPos]);
|
||||
: positions[dt.expr.getPos() ? dt.expr.getPos() : noPos];
|
||||
|
||||
if (pos) {
|
||||
out << pos;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "signals.hh"
|
||||
#include "gc-small-vector.hh"
|
||||
#include "url.hh"
|
||||
#include "fetch-to-store.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
@ -870,7 +871,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
|
|||
? std::make_unique<DebugTraceStacker>(
|
||||
*this,
|
||||
DebugTrace {
|
||||
.pos = error->info().errPos ? error->info().errPos : static_cast<std::shared_ptr<AbstractPos>>(positions[expr.getPos()]),
|
||||
.pos = error->info().errPos ? error->info().errPos : positions[expr.getPos()],
|
||||
.expr = expr,
|
||||
.env = env,
|
||||
.hint = error->info().msg,
|
||||
|
@ -909,7 +910,7 @@ static std::unique_ptr<DebugTraceStacker> makeDebugTraceStacker(
|
|||
EvalState & state,
|
||||
Expr & expr,
|
||||
Env & env,
|
||||
std::shared_ptr<AbstractPos> && pos,
|
||||
std::shared_ptr<Pos> && pos,
|
||||
const char * s,
|
||||
const std::string & s2)
|
||||
{
|
||||
|
@ -1187,7 +1188,7 @@ void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
|
|||
*this,
|
||||
*e,
|
||||
this->baseEnv,
|
||||
e->getPos() ? static_cast<std::shared_ptr<AbstractPos>>(positions[e->getPos()]) : nullptr,
|
||||
e->getPos() ? std::make_shared<Pos>(positions[e->getPos()]) : nullptr,
|
||||
"while evaluating the file '%1%':", resolvedPath.to_string())
|
||||
: nullptr;
|
||||
|
||||
|
@ -2368,7 +2369,7 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
|
|||
auto dstPath = i != srcToStore.end()
|
||||
? i->second
|
||||
: [&]() {
|
||||
auto dstPath = path.fetchToStore(*store, path.baseName(), FileIngestionMethod::Recursive, nullptr, repair);
|
||||
auto dstPath = fetchToStore(*store, path, path.baseName(), FileIngestionMethod::Recursive, nullptr, repair);
|
||||
allowPath(dstPath);
|
||||
srcToStore.insert_or_assign(path, dstPath);
|
||||
printMsg(lvlChatty, "copied source '%1%' -> '%2%'", path, store->printStorePath(dstPath));
|
||||
|
|
|
@ -142,7 +142,7 @@ struct RegexCache;
|
|||
std::shared_ptr<RegexCache> makeRegexCache();
|
||||
|
||||
struct DebugTrace {
|
||||
std::shared_ptr<AbstractPos> pos;
|
||||
std::shared_ptr<Pos> pos;
|
||||
const Expr & expr;
|
||||
const Env & env;
|
||||
hintformat hint;
|
||||
|
|
|
@ -11,58 +11,6 @@ namespace nix {
|
|||
|
||||
ExprBlackHole eBlackHole;
|
||||
|
||||
struct PosAdapter : AbstractPos
|
||||
{
|
||||
Pos::Origin origin;
|
||||
|
||||
PosAdapter(Pos::Origin origin)
|
||||
: origin(std::move(origin))
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<std::string> getSource() const override
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
[](const Pos::none_tag &) -> std::optional<std::string> {
|
||||
return std::nullopt;
|
||||
},
|
||||
[](const Pos::Stdin & s) -> std::optional<std::string> {
|
||||
// Get rid of the null terminators added by the parser.
|
||||
return std::string(s.source->c_str());
|
||||
},
|
||||
[](const Pos::String & s) -> std::optional<std::string> {
|
||||
// Get rid of the null terminators added by the parser.
|
||||
return std::string(s.source->c_str());
|
||||
},
|
||||
[](const SourcePath & path) -> std::optional<std::string> {
|
||||
try {
|
||||
return path.readFile();
|
||||
} catch (Error &) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}, origin);
|
||||
}
|
||||
|
||||
void print(std::ostream & out) const override
|
||||
{
|
||||
std::visit(overloaded {
|
||||
[&](const Pos::none_tag &) { out << "«none»"; },
|
||||
[&](const Pos::Stdin &) { out << "«stdin»"; },
|
||||
[&](const Pos::String & s) { out << "«string»"; },
|
||||
[&](const SourcePath & path) { out << path; }
|
||||
}, origin);
|
||||
}
|
||||
};
|
||||
|
||||
Pos::operator std::shared_ptr<AbstractPos>() const
|
||||
{
|
||||
auto pos = std::make_shared<PosAdapter>(origin);
|
||||
pos->line = line;
|
||||
pos->column = column;
|
||||
return pos;
|
||||
}
|
||||
|
||||
// FIXME: remove, because *symbols* are abstract and do not have a single
|
||||
// textual representation; see printIdentifier()
|
||||
std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
|
||||
|
@ -268,17 +216,6 @@ void ExprPos::show(const SymbolTable & symbols, std::ostream & str) const
|
|||
}
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const Pos & pos)
|
||||
{
|
||||
if (auto pos2 = (std::shared_ptr<AbstractPos>) pos) {
|
||||
str << *pos2;
|
||||
} else
|
||||
str << "undefined position";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath)
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "symbol-table.hh"
|
||||
#include "error.hh"
|
||||
#include "chunked-vector.hh"
|
||||
#include "position.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -28,27 +29,6 @@ public:
|
|||
using EvalError::EvalError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Position objects.
|
||||
*/
|
||||
struct Pos
|
||||
{
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
|
||||
struct none_tag { };
|
||||
struct Stdin { ref<std::string> source; };
|
||||
struct String { ref<std::string> source; };
|
||||
|
||||
typedef std::variant<none_tag, Stdin, String, SourcePath> Origin;
|
||||
|
||||
Origin origin;
|
||||
|
||||
explicit operator bool() const { return line > 0; }
|
||||
|
||||
operator std::shared_ptr<AbstractPos>() const;
|
||||
};
|
||||
|
||||
class PosIdx {
|
||||
friend class PosTable;
|
||||
|
||||
|
@ -81,7 +61,7 @@ public:
|
|||
mutable uint32_t idx = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
// Used for searching in PosTable::[].
|
||||
explicit Origin(uint32_t idx): idx(idx), origin{Pos::none_tag()} {}
|
||||
explicit Origin(uint32_t idx): idx(idx), origin{std::monostate()} {}
|
||||
|
||||
public:
|
||||
const Pos::Origin origin;
|
||||
|
@ -132,8 +112,6 @@ public:
|
|||
|
||||
inline PosIdx noPos = {};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const Pos & pos);
|
||||
|
||||
|
||||
struct Env;
|
||||
struct Value;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "value-to-xml.hh"
|
||||
#include "primops.hh"
|
||||
#include "fs-input-accessor.hh"
|
||||
#include "fetch-to-store.hh"
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
@ -2240,7 +2241,7 @@ static void addPath(
|
|||
});
|
||||
|
||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||
auto dstPath = path.fetchToStore(*state.store, name, method, filter.get(), state.repair);
|
||||
auto dstPath = fetchToStore(*state.store, path, name, method, filter.get(), state.repair);
|
||||
if (expectedHash && expectedStorePath != dstPath)
|
||||
state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path));
|
||||
state.allowAndSetStorePathString(dstPath, v);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "symbol-table.hh"
|
||||
#include "value/context.hh"
|
||||
#include "input-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
#include <gc/gc_allocator.h>
|
||||
|
|
68
src/libfetchers/fetch-to-store.cc
Normal file
68
src/libfetchers/fetch-to-store.cc
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "fetch-to-store.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "cache.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
StorePath fetchToStore(
|
||||
Store & store,
|
||||
const SourcePath & path,
|
||||
std::string_view name,
|
||||
ContentAddressMethod method,
|
||||
PathFilter * filter,
|
||||
RepairFlag repair)
|
||||
{
|
||||
// FIXME: add an optimisation for the case where the accessor is
|
||||
// an FSInputAccessor pointing to a store path.
|
||||
|
||||
std::optional<fetchers::Attrs> cacheKey;
|
||||
|
||||
if (!filter && path.accessor->fingerprint) {
|
||||
cacheKey = fetchers::Attrs{
|
||||
{"_what", "fetchToStore"},
|
||||
{"store", store.storeDir},
|
||||
{"name", std::string(name)},
|
||||
{"fingerprint", *path.accessor->fingerprint},
|
||||
{
|
||||
"method",
|
||||
std::visit(overloaded {
|
||||
[](const TextIngestionMethod &) {
|
||||
return "text";
|
||||
},
|
||||
[](const FileIngestionMethod & fim) {
|
||||
switch (fim) {
|
||||
case FileIngestionMethod::Flat: return "flat";
|
||||
case FileIngestionMethod::Recursive: return "nar";
|
||||
default: assert(false);
|
||||
}
|
||||
},
|
||||
}, method.raw),
|
||||
},
|
||||
{"path", path.path.abs()}
|
||||
};
|
||||
if (auto res = fetchers::getCache()->lookup(store, *cacheKey)) {
|
||||
debug("store path cache hit for '%s'", path);
|
||||
return res->second;
|
||||
}
|
||||
} else
|
||||
debug("source path '%s' is uncacheable", path);
|
||||
|
||||
Activity act(*logger, lvlChatty, actUnknown, fmt("copying '%s' to the store", path));
|
||||
|
||||
auto filter2 = filter ? *filter : defaultPathFilter;
|
||||
|
||||
auto storePath =
|
||||
settings.readOnlyMode
|
||||
? store.computeStorePath(
|
||||
name, *path.accessor, path.path, method, HashAlgorithm::SHA256, {}, filter2).first
|
||||
: store.addToStore(
|
||||
name, *path.accessor, path.path, method, HashAlgorithm::SHA256, {}, filter2, repair);
|
||||
|
||||
if (cacheKey)
|
||||
fetchers::getCache()->add(store, *cacheKey, {}, storePath, true);
|
||||
|
||||
return storePath;
|
||||
}
|
||||
|
||||
|
||||
}
|
22
src/libfetchers/fetch-to-store.hh
Normal file
22
src/libfetchers/fetch-to-store.hh
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "source-path.hh"
|
||||
#include "store-api.hh"
|
||||
#include "file-system.hh"
|
||||
#include "repair-flag.hh"
|
||||
#include "file-content-address.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* Copy the `path` to the Nix store.
|
||||
*/
|
||||
StorePath fetchToStore(
|
||||
Store & store,
|
||||
const SourcePath & path,
|
||||
std::string_view name = "source",
|
||||
ContentAddressMethod method = FileIngestionMethod::Recursive,
|
||||
PathFilter * filter = nullptr,
|
||||
RepairFlag repair = NoRepair);
|
||||
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
#include "fetchers.hh"
|
||||
#include "store-api.hh"
|
||||
#include "input-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
#include "fetch-to-store.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
@ -374,7 +376,7 @@ void InputScheme::clone(const Input & input, const Path & destDir) const
|
|||
std::pair<StorePath, Input> InputScheme::fetch(ref<Store> store, const Input & input)
|
||||
{
|
||||
auto [accessor, input2] = getAccessor(store, input);
|
||||
auto storePath = SourcePath(accessor).fetchToStore(*store, input2.getName());
|
||||
auto storePath = fetchToStore(*store, SourcePath(accessor), input2.getName());
|
||||
return {storePath, input2};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "input-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "input-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
#include "input-accessor.hh"
|
||||
#include "store-api.hh"
|
||||
#include "cache.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
StorePath InputAccessor::fetchToStore(
|
||||
Store & store,
|
||||
const CanonPath & path,
|
||||
std::string_view name,
|
||||
ContentAddressMethod method,
|
||||
PathFilter * filter,
|
||||
RepairFlag repair)
|
||||
{
|
||||
// FIXME: add an optimisation for the case where the accessor is
|
||||
// an FSInputAccessor pointing to a store path.
|
||||
|
||||
std::optional<fetchers::Attrs> cacheKey;
|
||||
|
||||
if (!filter && fingerprint) {
|
||||
cacheKey = fetchers::Attrs{
|
||||
{"_what", "fetchToStore"},
|
||||
{"store", store.storeDir},
|
||||
{"name", std::string(name)},
|
||||
{"fingerprint", *fingerprint},
|
||||
{
|
||||
"method",
|
||||
std::visit(overloaded {
|
||||
[](const TextIngestionMethod &) {
|
||||
return "text";
|
||||
},
|
||||
[](const FileIngestionMethod & fim) {
|
||||
switch (fim) {
|
||||
case FileIngestionMethod::Flat: return "flat";
|
||||
case FileIngestionMethod::Recursive: return "nar";
|
||||
default: assert(false);
|
||||
}
|
||||
},
|
||||
}, method.raw),
|
||||
},
|
||||
{"path", path.abs()}
|
||||
};
|
||||
if (auto res = fetchers::getCache()->lookup(store, *cacheKey)) {
|
||||
debug("store path cache hit for '%s'", showPath(path));
|
||||
return res->second;
|
||||
}
|
||||
} else
|
||||
debug("source path '%s' is uncacheable", showPath(path));
|
||||
|
||||
Activity act(*logger, lvlChatty, actUnknown, fmt("copying '%s' to the store", showPath(path)));
|
||||
|
||||
auto filter2 = filter ? *filter : defaultPathFilter;
|
||||
|
||||
auto storePath =
|
||||
settings.readOnlyMode
|
||||
? store.computeStorePath(
|
||||
name, *this, path, method, HashAlgorithm::SHA256, {}, filter2).first
|
||||
: store.addToStore(
|
||||
name, *this, path, method, HashAlgorithm::SHA256, {}, filter2, repair);
|
||||
|
||||
if (cacheKey)
|
||||
fetchers::getCache()->add(store, *cacheKey, {}, storePath, true);
|
||||
|
||||
return storePath;
|
||||
}
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const SourcePath & path)
|
||||
{
|
||||
str << path.to_string();
|
||||
return str;
|
||||
}
|
||||
|
||||
StorePath SourcePath::fetchToStore(
|
||||
Store & store,
|
||||
std::string_view name,
|
||||
ContentAddressMethod method,
|
||||
PathFilter * filter,
|
||||
RepairFlag repair) const
|
||||
{
|
||||
return accessor->fetchToStore(store, path, name, method, filter, repair);
|
||||
}
|
||||
|
||||
std::string_view SourcePath::baseName() const
|
||||
{
|
||||
return path.baseName().value_or("source");
|
||||
}
|
||||
|
||||
SourcePath SourcePath::parent() const
|
||||
{
|
||||
auto p = path.parent();
|
||||
assert(p);
|
||||
return {accessor, std::move(*p)};
|
||||
}
|
||||
|
||||
SourcePath SourcePath::resolveSymlinks() const
|
||||
{
|
||||
auto res = SourcePath(accessor);
|
||||
|
||||
int linksAllowed = 1024;
|
||||
|
||||
std::list<std::string> todo;
|
||||
for (auto & c : path)
|
||||
todo.push_back(std::string(c));
|
||||
|
||||
while (!todo.empty()) {
|
||||
auto c = *todo.begin();
|
||||
todo.pop_front();
|
||||
if (c == "" || c == ".")
|
||||
;
|
||||
else if (c == "..")
|
||||
res.path.pop();
|
||||
else {
|
||||
res.path.push(c);
|
||||
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||
if (!linksAllowed--)
|
||||
throw Error("infinite symlink recursion in path '%s'", path);
|
||||
auto target = res.readLink();
|
||||
res.path.pop();
|
||||
if (hasPrefix(target, "/"))
|
||||
res.path = CanonPath::root;
|
||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "source-accessor.hh"
|
||||
#include "ref.hh"
|
||||
#include "types.hh"
|
||||
#include "file-system.hh"
|
||||
#include "repair-flag.hh"
|
||||
#include "content-address.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
MakeError(RestrictedPathError, Error);
|
||||
|
||||
struct SourcePath;
|
||||
class StorePath;
|
||||
class Store;
|
||||
|
||||
struct InputAccessor : virtual SourceAccessor, std::enable_shared_from_this<InputAccessor>
|
||||
{
|
||||
std::optional<std::string> fingerprint;
|
||||
|
||||
/**
|
||||
* Return the maximum last-modified time of the files in this
|
||||
* tree, if available.
|
||||
*/
|
||||
virtual std::optional<time_t> getLastModified()
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
StorePath fetchToStore(
|
||||
Store & store,
|
||||
const CanonPath & path,
|
||||
std::string_view name = "source",
|
||||
ContentAddressMethod method = FileIngestionMethod::Recursive,
|
||||
PathFilter * filter = nullptr,
|
||||
RepairFlag repair = NoRepair);
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstraction for accessing source files during
|
||||
* evaluation. Currently, it's just a wrapper around `CanonPath` that
|
||||
* accesses files in the regular filesystem, but in the future it will
|
||||
* support fetching files in other ways.
|
||||
*/
|
||||
struct SourcePath
|
||||
{
|
||||
ref<InputAccessor> accessor;
|
||||
CanonPath path;
|
||||
|
||||
SourcePath(ref<InputAccessor> accessor, CanonPath path = CanonPath::root)
|
||||
: accessor(std::move(accessor))
|
||||
, path(std::move(path))
|
||||
{ }
|
||||
|
||||
std::string_view baseName() const;
|
||||
|
||||
/**
|
||||
* Construct the parent of this `SourcePath`. Aborts if `this`
|
||||
* denotes the root.
|
||||
*/
|
||||
SourcePath parent() const;
|
||||
|
||||
/**
|
||||
* If this `SourcePath` denotes a regular file (not a symlink),
|
||||
* return its contents; otherwise throw an error.
|
||||
*/
|
||||
std::string readFile() const
|
||||
{ return accessor->readFile(path); }
|
||||
|
||||
/**
|
||||
* Return whether this `SourcePath` denotes a file (of any type)
|
||||
* that exists
|
||||
*/
|
||||
bool pathExists() const
|
||||
{ return accessor->pathExists(path); }
|
||||
|
||||
/**
|
||||
* Return stats about this `SourcePath`, or throw an exception if
|
||||
* it doesn't exist.
|
||||
*/
|
||||
InputAccessor::Stat lstat() const
|
||||
{ return accessor->lstat(path); }
|
||||
|
||||
/**
|
||||
* Return stats about this `SourcePath`, or std::nullopt if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
std::optional<InputAccessor::Stat> maybeLstat() const
|
||||
{ return accessor->maybeLstat(path); }
|
||||
|
||||
/**
|
||||
* If this `SourcePath` denotes a directory (not a symlink),
|
||||
* return its directory entries; otherwise throw an error.
|
||||
*/
|
||||
InputAccessor::DirEntries readDirectory() const
|
||||
{ return accessor->readDirectory(path); }
|
||||
|
||||
/**
|
||||
* If this `SourcePath` denotes a symlink, return its target;
|
||||
* otherwise throw an error.
|
||||
*/
|
||||
std::string readLink() const
|
||||
{ return accessor->readLink(path); }
|
||||
|
||||
/**
|
||||
* Dump this `SourcePath` to `sink` as a NAR archive.
|
||||
*/
|
||||
void dumpPath(
|
||||
Sink & sink,
|
||||
PathFilter & filter = defaultPathFilter) const
|
||||
{ return accessor->dumpPath(path, sink, filter); }
|
||||
|
||||
/**
|
||||
* Copy this `SourcePath` to the Nix store.
|
||||
*/
|
||||
StorePath fetchToStore(
|
||||
Store & store,
|
||||
std::string_view name = "source",
|
||||
ContentAddressMethod method = FileIngestionMethod::Recursive,
|
||||
PathFilter * filter = nullptr,
|
||||
RepairFlag repair = NoRepair) const;
|
||||
|
||||
/**
|
||||
* Return the location of this path in the "real" filesystem, if
|
||||
* it has a physical location.
|
||||
*/
|
||||
std::optional<CanonPath> getPhysicalPath() const
|
||||
{ return accessor->getPhysicalPath(path); }
|
||||
|
||||
std::string to_string() const
|
||||
{ return accessor->showPath(path); }
|
||||
|
||||
/**
|
||||
* Append a `CanonPath` to this path.
|
||||
*/
|
||||
SourcePath operator + (const CanonPath & x) const
|
||||
{ return {accessor, path + x}; }
|
||||
|
||||
/**
|
||||
* Append a single component `c` to this path. `c` must not
|
||||
* contain a slash. A slash is implicitly added between this path
|
||||
* and `c`.
|
||||
*/
|
||||
SourcePath operator + (std::string_view c) const
|
||||
{ return {accessor, path + c}; }
|
||||
|
||||
bool operator == (const SourcePath & x) const
|
||||
{
|
||||
return std::tie(accessor, path) == std::tie(x.accessor, x.path);
|
||||
}
|
||||
|
||||
bool operator != (const SourcePath & x) const
|
||||
{
|
||||
return std::tie(accessor, path) != std::tie(x.accessor, x.path);
|
||||
}
|
||||
|
||||
bool operator < (const SourcePath & x) const
|
||||
{
|
||||
return std::tie(accessor, path) < std::tie(x.accessor, x.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve any symlinks in this `SourcePath` (including its
|
||||
* parents). The result is a `SourcePath` in which no element is a
|
||||
* symlink.
|
||||
*/
|
||||
SourcePath resolveSymlinks() const;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const SourcePath & path);
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include "memory-input-accessor.hh"
|
||||
#include "memory-source-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "input-accessor.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "path-info.hh"
|
||||
#include "repair-flag.hh"
|
||||
#include "store-dir-config.hh"
|
||||
#include "source-path.hh"
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <atomic>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "environment-variables.hh"
|
||||
#include "signals.hh"
|
||||
#include "terminal.hh"
|
||||
#include "position.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
@ -10,7 +11,7 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
void BaseError::addTrace(std::shared_ptr<AbstractPos> && e, hintformat hint, bool frame)
|
||||
void BaseError::addTrace(std::shared_ptr<Pos> && e, hintformat hint, bool frame)
|
||||
{
|
||||
err.traces.push_front(Trace { .pos = std::move(e), .hint = hint, .frame = frame });
|
||||
}
|
||||
|
@ -41,15 +42,6 @@ std::ostream & operator <<(std::ostream & os, const hintformat & hf)
|
|||
return os << hf.str();
|
||||
}
|
||||
|
||||
std::ostream & operator <<(std::ostream & str, const AbstractPos & pos)
|
||||
{
|
||||
pos.print(str);
|
||||
str << ":" << pos.line;
|
||||
if (pos.column > 0)
|
||||
str << ":" << pos.column;
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* An arbitrarily defined value comparison for the purpose of using traces in the key of a sorted container.
|
||||
*/
|
||||
|
@ -76,49 +68,10 @@ inline bool operator> (const Trace& lhs, const Trace& rhs) { return rhs < lhs; }
|
|||
inline bool operator<=(const Trace& lhs, const Trace& rhs) { return !(lhs > rhs); }
|
||||
inline bool operator>=(const Trace& lhs, const Trace& rhs) { return !(lhs < rhs); }
|
||||
|
||||
std::optional<LinesOfCode> AbstractPos::getCodeLines() const
|
||||
{
|
||||
if (line == 0)
|
||||
return std::nullopt;
|
||||
|
||||
if (auto source = getSource()) {
|
||||
|
||||
std::istringstream iss(*source);
|
||||
// count the newlines.
|
||||
int count = 0;
|
||||
std::string curLine;
|
||||
int pl = line - 1;
|
||||
|
||||
LinesOfCode loc;
|
||||
|
||||
do {
|
||||
std::getline(iss, curLine);
|
||||
++count;
|
||||
if (count < pl)
|
||||
;
|
||||
else if (count == pl) {
|
||||
loc.prevLineOfCode = curLine;
|
||||
} else if (count == pl + 1) {
|
||||
loc.errLineOfCode = curLine;
|
||||
} else if (count == pl + 2) {
|
||||
loc.nextLineOfCode = curLine;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!iss.good())
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// print lines of code to the ostream, indicating the error column.
|
||||
void printCodeLines(std::ostream & out,
|
||||
const std::string & prefix,
|
||||
const AbstractPos & errPos,
|
||||
const Pos & errPos,
|
||||
const LinesOfCode & loc)
|
||||
{
|
||||
// previous line of code.
|
||||
|
@ -196,7 +149,7 @@ static bool printUnknownLocations = getEnv("_NIX_EVAL_SHOW_UNKNOWN_LOCATIONS").h
|
|||
*
|
||||
* @return true if a position was printed.
|
||||
*/
|
||||
static bool printPosMaybe(std::ostream & oss, std::string_view indent, const std::shared_ptr<AbstractPos> & pos) {
|
||||
static bool printPosMaybe(std::ostream & oss, std::string_view indent, const std::shared_ptr<Pos> & pos) {
|
||||
bool hasPos = pos && *pos;
|
||||
if (hasPos) {
|
||||
oss << indent << ANSI_BLUE << "at " ANSI_WARNING << *pos << ANSI_NORMAL << ":";
|
||||
|
|
|
@ -63,45 +63,15 @@ struct LinesOfCode {
|
|||
std::optional<std::string> nextLineOfCode;
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstract type that represents a location in a source file.
|
||||
*/
|
||||
struct AbstractPos
|
||||
{
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
|
||||
/**
|
||||
* An AbstractPos may be a "null object", representing an unknown position.
|
||||
*
|
||||
* Return true if this position is known.
|
||||
*/
|
||||
inline operator bool() const { return line != 0; };
|
||||
|
||||
/**
|
||||
* Return the contents of the source file.
|
||||
*/
|
||||
virtual std::optional<std::string> getSource() const
|
||||
{ return std::nullopt; };
|
||||
|
||||
virtual void print(std::ostream & out) const = 0;
|
||||
|
||||
std::optional<LinesOfCode> getCodeLines() const;
|
||||
|
||||
virtual ~AbstractPos() = default;
|
||||
|
||||
inline auto operator<=>(const AbstractPos& rhs) const = default;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const AbstractPos & pos);
|
||||
struct Pos;
|
||||
|
||||
void printCodeLines(std::ostream & out,
|
||||
const std::string & prefix,
|
||||
const AbstractPos & errPos,
|
||||
const Pos & errPos,
|
||||
const LinesOfCode & loc);
|
||||
|
||||
struct Trace {
|
||||
std::shared_ptr<AbstractPos> pos;
|
||||
std::shared_ptr<Pos> pos;
|
||||
hintformat hint;
|
||||
bool frame;
|
||||
};
|
||||
|
@ -114,7 +84,7 @@ inline bool operator>=(const Trace& lhs, const Trace& rhs);
|
|||
struct ErrorInfo {
|
||||
Verbosity level;
|
||||
hintformat msg;
|
||||
std::shared_ptr<AbstractPos> errPos;
|
||||
std::shared_ptr<Pos> errPos;
|
||||
std::list<Trace> traces;
|
||||
|
||||
Suggestions suggestions;
|
||||
|
@ -185,12 +155,12 @@ public:
|
|||
}
|
||||
|
||||
template<typename... Args>
|
||||
void addTrace(std::shared_ptr<AbstractPos> && e, std::string_view fs, const Args & ... args)
|
||||
void addTrace(std::shared_ptr<Pos> && e, std::string_view fs, const Args & ... args)
|
||||
{
|
||||
addTrace(std::move(e), hintfmt(std::string(fs), args...));
|
||||
}
|
||||
|
||||
void addTrace(std::shared_ptr<AbstractPos> && e, hintformat hint, bool frame = false);
|
||||
void addTrace(std::shared_ptr<Pos> && e, hintformat hint, bool frame = false);
|
||||
|
||||
bool hasTrace() const { return !err.traces.empty(); }
|
||||
|
||||
|
|
27
src/libutil/input-accessor.hh
Normal file
27
src/libutil/input-accessor.hh
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "source-accessor.hh"
|
||||
#include "ref.hh"
|
||||
#include "repair-flag.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
MakeError(RestrictedPathError, Error);
|
||||
|
||||
struct InputAccessor : virtual SourceAccessor, std::enable_shared_from_this<InputAccessor>
|
||||
{
|
||||
std::optional<std::string> fingerprint;
|
||||
|
||||
/**
|
||||
* Return the maximum last-modified time of the files in this
|
||||
* tree, if available.
|
||||
*/
|
||||
virtual std::optional<time_t> getLastModified()
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
#include "terminal.hh"
|
||||
#include "util.hh"
|
||||
#include "config.hh"
|
||||
#include "source-path.hh"
|
||||
#include "position.hh"
|
||||
|
||||
#include <atomic>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
@ -136,13 +138,13 @@ Activity::Activity(Logger & logger, Verbosity lvl, ActivityType type,
|
|||
logger.startActivity(id, lvl, type, s, fields, parent);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json & json, std::shared_ptr<AbstractPos> pos)
|
||||
void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
|
||||
{
|
||||
if (pos) {
|
||||
json["line"] = pos->line;
|
||||
json["column"] = pos->column;
|
||||
std::ostringstream str;
|
||||
pos->print(str);
|
||||
pos->print(str, true);
|
||||
json["file"] = str.str();
|
||||
} else {
|
||||
json["line"] = nullptr;
|
||||
|
|
112
src/libutil/position.cc
Normal file
112
src/libutil/position.cc
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "position.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
Pos::Pos(const Pos * other)
|
||||
{
|
||||
if (!other) {
|
||||
return;
|
||||
}
|
||||
line = other->line;
|
||||
column = other->column;
|
||||
origin = std::move(other->origin);
|
||||
}
|
||||
|
||||
Pos::operator std::shared_ptr<Pos>() const
|
||||
{
|
||||
return std::make_shared<Pos>(&*this);
|
||||
}
|
||||
|
||||
bool Pos::operator<(const Pos &rhs) const
|
||||
{
|
||||
return std::forward_as_tuple(line, column, origin)
|
||||
< std::forward_as_tuple(rhs.line, rhs.column, rhs.origin);
|
||||
}
|
||||
|
||||
std::optional<LinesOfCode> Pos::getCodeLines() const
|
||||
{
|
||||
if (line == 0)
|
||||
return std::nullopt;
|
||||
|
||||
if (auto source = getSource()) {
|
||||
|
||||
std::istringstream iss(*source);
|
||||
// count the newlines.
|
||||
int count = 0;
|
||||
std::string curLine;
|
||||
int pl = line - 1;
|
||||
|
||||
LinesOfCode loc;
|
||||
|
||||
do {
|
||||
std::getline(iss, curLine);
|
||||
++count;
|
||||
if (count < pl)
|
||||
;
|
||||
else if (count == pl) {
|
||||
loc.prevLineOfCode = curLine;
|
||||
} else if (count == pl + 1) {
|
||||
loc.errLineOfCode = curLine;
|
||||
} else if (count == pl + 2) {
|
||||
loc.nextLineOfCode = curLine;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!iss.good())
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
std::optional<std::string> Pos::getSource() const
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
[](const std::monostate &) -> std::optional<std::string> {
|
||||
return std::nullopt;
|
||||
},
|
||||
[](const Pos::Stdin & s) -> std::optional<std::string> {
|
||||
// Get rid of the null terminators added by the parser.
|
||||
return std::string(s.source->c_str());
|
||||
},
|
||||
[](const Pos::String & s) -> std::optional<std::string> {
|
||||
// Get rid of the null terminators added by the parser.
|
||||
return std::string(s.source->c_str());
|
||||
},
|
||||
[](const SourcePath & path) -> std::optional<std::string> {
|
||||
try {
|
||||
return path.readFile();
|
||||
} catch (Error &) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}, origin);
|
||||
}
|
||||
|
||||
void Pos::print(std::ostream & out, bool showOrigin) const
|
||||
{
|
||||
if (showOrigin) {
|
||||
std::visit(overloaded {
|
||||
[&](const std::monostate &) { out << "«none»"; },
|
||||
[&](const Pos::Stdin &) { out << "«stdin»"; },
|
||||
[&](const Pos::String & s) { out << "«string»"; },
|
||||
[&](const SourcePath & path) { out << path; }
|
||||
}, origin);
|
||||
out << ":";
|
||||
}
|
||||
out << line;
|
||||
if (column > 0)
|
||||
out << ":" << column;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & str, const Pos & pos)
|
||||
{
|
||||
pos.print(str, true);
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
74
src/libutil/position.hh
Normal file
74
src/libutil/position.hh
Normal file
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Pos and AbstractPos
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* A position and an origin for that position (like a source file).
|
||||
*/
|
||||
struct Pos
|
||||
{
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
|
||||
struct Stdin {
|
||||
ref<std::string> source;
|
||||
bool operator==(const Stdin & rhs) const
|
||||
{ return *source == *rhs.source; }
|
||||
bool operator!=(const Stdin & rhs) const
|
||||
{ return *source != *rhs.source; }
|
||||
bool operator<(const Stdin & rhs) const
|
||||
{ return *source < *rhs.source; }
|
||||
};
|
||||
struct String {
|
||||
ref<std::string> source;
|
||||
bool operator==(const String & rhs) const
|
||||
{ return *source == *rhs.source; }
|
||||
bool operator!=(const String & rhs) const
|
||||
{ return *source != *rhs.source; }
|
||||
bool operator<(const String & rhs) const
|
||||
{ return *source < *rhs.source; }
|
||||
};
|
||||
|
||||
typedef std::variant<std::monostate, Stdin, String, SourcePath> Origin;
|
||||
|
||||
Origin origin = std::monostate();
|
||||
|
||||
Pos() { }
|
||||
Pos(uint32_t line, uint32_t column, Origin origin)
|
||||
: line(line), column(column), origin(origin) { }
|
||||
Pos(Pos & other) = default;
|
||||
Pos(const Pos & other) = default;
|
||||
Pos(Pos && other) = default;
|
||||
Pos(const Pos * other);
|
||||
|
||||
explicit operator bool() const { return line > 0; }
|
||||
|
||||
operator std::shared_ptr<Pos>() const;
|
||||
|
||||
/**
|
||||
* Return the contents of the source file.
|
||||
*/
|
||||
std::optional<std::string> getSource() const;
|
||||
|
||||
void print(std::ostream & out, bool showOrigin) const;
|
||||
|
||||
std::optional<LinesOfCode> getCodeLines() const;
|
||||
|
||||
bool operator==(const Pos & rhs) const = default;
|
||||
bool operator!=(const Pos & rhs) const = default;
|
||||
bool operator<(const Pos & rhs) const;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & str, const Pos & pos);
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <compare>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
|
105
src/libutil/source-path.cc
Normal file
105
src/libutil/source-path.cc
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include "source-path.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
std::string_view SourcePath::baseName() const
|
||||
{ return path.baseName().value_or("source"); }
|
||||
|
||||
SourcePath SourcePath::parent() const
|
||||
{
|
||||
auto p = path.parent();
|
||||
assert(p);
|
||||
return {accessor, std::move(*p)};
|
||||
}
|
||||
|
||||
std::string SourcePath::readFile() const
|
||||
{ return accessor->readFile(path); }
|
||||
|
||||
bool SourcePath::pathExists() const
|
||||
{ return accessor->pathExists(path); }
|
||||
|
||||
InputAccessor::Stat SourcePath::lstat() const
|
||||
{ return accessor->lstat(path); }
|
||||
|
||||
std::optional<InputAccessor::Stat> SourcePath::maybeLstat() const
|
||||
{ return accessor->maybeLstat(path); }
|
||||
|
||||
InputAccessor::DirEntries SourcePath::readDirectory() const
|
||||
{ return accessor->readDirectory(path); }
|
||||
|
||||
std::string SourcePath::readLink() const
|
||||
{ return accessor->readLink(path); }
|
||||
|
||||
void SourcePath::dumpPath(
|
||||
Sink & sink,
|
||||
PathFilter & filter) const
|
||||
{ return accessor->dumpPath(path, sink, filter); }
|
||||
|
||||
std::optional<CanonPath> SourcePath::getPhysicalPath() const
|
||||
{ return accessor->getPhysicalPath(path); }
|
||||
|
||||
std::string SourcePath::to_string() const
|
||||
{ return accessor->showPath(path); }
|
||||
|
||||
SourcePath SourcePath::operator+(const CanonPath & x) const
|
||||
{ return {accessor, path + x}; }
|
||||
|
||||
SourcePath SourcePath::operator+(std::string_view c) const
|
||||
{ return {accessor, path + c}; }
|
||||
|
||||
bool SourcePath::operator==(const SourcePath & x) const
|
||||
{
|
||||
return std::tie(*accessor, path) == std::tie(*x.accessor, x.path);
|
||||
}
|
||||
|
||||
bool SourcePath::operator!=(const SourcePath & x) const
|
||||
{
|
||||
return std::tie(*accessor, path) != std::tie(*x.accessor, x.path);
|
||||
}
|
||||
|
||||
bool SourcePath::operator<(const SourcePath & x) const
|
||||
{
|
||||
return std::tie(*accessor, path) < std::tie(*x.accessor, x.path);
|
||||
}
|
||||
|
||||
SourcePath SourcePath::resolveSymlinks() const
|
||||
{
|
||||
auto res = SourcePath(accessor);
|
||||
|
||||
int linksAllowed = 1024;
|
||||
|
||||
std::list<std::string> todo;
|
||||
for (auto & c : path)
|
||||
todo.push_back(std::string(c));
|
||||
|
||||
while (!todo.empty()) {
|
||||
auto c = *todo.begin();
|
||||
todo.pop_front();
|
||||
if (c == "" || c == ".")
|
||||
;
|
||||
else if (c == "..")
|
||||
res.path.pop();
|
||||
else {
|
||||
res.path.push(c);
|
||||
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||
if (!linksAllowed--)
|
||||
throw Error("infinite symlink recursion in path '%s'", path);
|
||||
auto target = res.readLink();
|
||||
res.path.pop();
|
||||
if (hasPrefix(target, "/"))
|
||||
res.path = CanonPath::root;
|
||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & str, const SourcePath & path)
|
||||
{
|
||||
str << path.to_string();
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
114
src/libutil/source-path.hh
Normal file
114
src/libutil/source-path.hh
Normal file
|
@ -0,0 +1,114 @@
|
|||
#pragma once
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief SourcePath
|
||||
*/
|
||||
|
||||
#include "ref.hh"
|
||||
#include "canon-path.hh"
|
||||
#include "input-accessor.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* An abstraction for accessing source files during
|
||||
* evaluation. Currently, it's just a wrapper around `CanonPath` that
|
||||
* accesses files in the regular filesystem, but in the future it will
|
||||
* support fetching files in other ways.
|
||||
*/
|
||||
struct SourcePath
|
||||
{
|
||||
ref<InputAccessor> accessor;
|
||||
CanonPath path;
|
||||
|
||||
SourcePath(ref<InputAccessor> accessor, CanonPath path = CanonPath::root)
|
||||
: accessor(std::move(accessor))
|
||||
, path(std::move(path))
|
||||
{ }
|
||||
|
||||
std::string_view baseName() const;
|
||||
|
||||
/**
|
||||
* Construct the parent of this `SourcePath`. Aborts if `this`
|
||||
* denotes the root.
|
||||
*/
|
||||
SourcePath parent() const;
|
||||
|
||||
/**
|
||||
* If this `SourcePath` denotes a regular file (not a symlink),
|
||||
* return its contents; otherwise throw an error.
|
||||
*/
|
||||
std::string readFile() const;
|
||||
|
||||
/**
|
||||
* Return whether this `SourcePath` denotes a file (of any type)
|
||||
* that exists
|
||||
*/
|
||||
bool pathExists() const;
|
||||
|
||||
/**
|
||||
* Return stats about this `SourcePath`, or throw an exception if
|
||||
* it doesn't exist.
|
||||
*/
|
||||
InputAccessor::Stat lstat() const;
|
||||
|
||||
/**
|
||||
* Return stats about this `SourcePath`, or std::nullopt if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
std::optional<InputAccessor::Stat> maybeLstat() const;
|
||||
|
||||
/**
|
||||
* If this `SourcePath` denotes a directory (not a symlink),
|
||||
* return its directory entries; otherwise throw an error.
|
||||
*/
|
||||
InputAccessor::DirEntries readDirectory() const;
|
||||
|
||||
/**
|
||||
* If this `SourcePath` denotes a symlink, return its target;
|
||||
* otherwise throw an error.
|
||||
*/
|
||||
std::string readLink() const;
|
||||
|
||||
/**
|
||||
* Dump this `SourcePath` to `sink` as a NAR archive.
|
||||
*/
|
||||
void dumpPath(
|
||||
Sink & sink,
|
||||
PathFilter & filter = defaultPathFilter) const;
|
||||
|
||||
/**
|
||||
* Return the location of this path in the "real" filesystem, if
|
||||
* it has a physical location.
|
||||
*/
|
||||
std::optional<CanonPath> getPhysicalPath() const;
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
/**
|
||||
* Append a `CanonPath` to this path.
|
||||
*/
|
||||
SourcePath operator + (const CanonPath & x) const;
|
||||
|
||||
/**
|
||||
* Append a single component `c` to this path. `c` must not
|
||||
* contain a slash. A slash is implicitly added between this path
|
||||
* and `c`.
|
||||
*/
|
||||
SourcePath operator+(std::string_view c) const;
|
||||
bool operator==(const SourcePath & x) const;
|
||||
bool operator!=(const SourcePath & x) const;
|
||||
bool operator<(const SourcePath & x) const;
|
||||
|
||||
/**
|
||||
* Resolve any symlinks in this `SourcePath` (including its
|
||||
* parents). The result is a `SourcePath` in which no element is a
|
||||
* symlink.
|
||||
*/
|
||||
SourcePath resolveSymlinks() const;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const SourcePath & path);
|
||||
|
||||
}
|
Loading…
Reference in a new issue