mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-30 09:36:15 +02:00
Checkpoint
This commit is contained in:
parent
2d572a250f
commit
c56e17b718
17 changed files with 428 additions and 79 deletions
|
@ -184,9 +184,11 @@ void SourceExprCommand::completeInstallable(std::string_view prefix)
|
|||
if (file) {
|
||||
evalSettings.pureEval = false;
|
||||
auto state = getEvalState();
|
||||
Expr *e = state->parseExprFromFile(
|
||||
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
||||
);
|
||||
Expr *e =
|
||||
state->parseExprFromFile(
|
||||
resolveExprPath(
|
||||
state->rootPath(
|
||||
lookupFileArg(*state, *file))));
|
||||
|
||||
Value root;
|
||||
state->eval(e, root);
|
||||
|
@ -700,8 +702,9 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
|
|||
if (file == "-") {
|
||||
auto e = state->parseStdin();
|
||||
state->eval(e, *vFile);
|
||||
} else if (file)
|
||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
||||
}
|
||||
else if (file)
|
||||
state->evalFile(state->rootPath(lookupFileArg(*state, *file)), *vFile);
|
||||
else {
|
||||
auto e = state->parseExprFromString(*expr, absPath("."));
|
||||
state->eval(e, *vFile);
|
||||
|
|
|
@ -450,6 +450,7 @@ EvalState::EvalState(
|
|||
, sPrefix(symbols.create("prefix"))
|
||||
, repair(NoRepair)
|
||||
, emptyBindings(0)
|
||||
, rootFS(makeFSInputAccessor(""))
|
||||
, store(store)
|
||||
, buildStore(buildStore ? buildStore : store)
|
||||
, regexCache(makeRegexCache())
|
||||
|
@ -527,6 +528,7 @@ void EvalState::allowAndSetStorePathString(const StorePath &storePath, Value & v
|
|||
v.mkString(path, PathSet({path}));
|
||||
}
|
||||
|
||||
#if 0
|
||||
Path EvalState::checkSourcePath(const Path & path_)
|
||||
{
|
||||
if (!allowedPaths) return path_;
|
||||
|
@ -572,6 +574,7 @@ Path EvalState::checkSourcePath(const Path & path_)
|
|||
|
||||
throw RestrictedPathError("access to canonical path '%1%' is forbidden in restricted mode", path);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void EvalState::checkURI(const std::string & uri)
|
||||
|
@ -593,12 +596,14 @@ void EvalState::checkURI(const std::string & uri)
|
|||
/* If the URI is a path, then check it against allowedPaths as
|
||||
well. */
|
||||
if (hasPrefix(uri, "/")) {
|
||||
checkSourcePath(uri);
|
||||
// FIXME: use rootPath
|
||||
//checkSourcePath(uri);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasPrefix(uri, "file://")) {
|
||||
checkSourcePath(std::string(uri, 7));
|
||||
// FIXME: use rootPath
|
||||
//checkSourcePath(std::string(uri, 7));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -970,17 +975,23 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
|
|||
}
|
||||
|
||||
|
||||
void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial)
|
||||
void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial)
|
||||
{
|
||||
#if 0
|
||||
auto path = checkSourcePath(path_);
|
||||
#endif
|
||||
|
||||
auto path = packPath(path_);
|
||||
|
||||
// FIXME: use SourcePath as cache key
|
||||
FileEvalCache::iterator i;
|
||||
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
|
||||
v = i->second;
|
||||
return;
|
||||
}
|
||||
|
||||
Path resolvedPath = resolveExprPath(path);
|
||||
auto resolvedPath_ = resolveExprPath(path_);
|
||||
auto resolvedPath = packPath(resolvedPath_);
|
||||
if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) {
|
||||
v = i->second;
|
||||
return;
|
||||
|
@ -994,7 +1005,10 @@ void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial)
|
|||
e = j->second;
|
||||
|
||||
if (!e)
|
||||
e = parseExprFromFile(resolvedPath_);
|
||||
#if 0
|
||||
e = parseExprFromFile(checkSourcePath(resolvedPath));
|
||||
#endif
|
||||
|
||||
cacheFile(path, resolvedPath, e, v, mustBeTrivial);
|
||||
}
|
||||
|
@ -2045,9 +2059,19 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
|
|||
if (i != srcToStore.end())
|
||||
dstPath = store->printStorePath(i->second);
|
||||
else {
|
||||
// FIXME: use SourcePath
|
||||
printError("COPY %s", path);
|
||||
auto path2 = unpackPath(path);
|
||||
#if 0
|
||||
auto p = settings.readOnlyMode
|
||||
? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first
|
||||
: store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair);
|
||||
? store->computeStorePathForPath(std::string(baseNameOf(path)), canonPath(path)).first
|
||||
: store->addToStore(std::string(baseNameOf(path)), canonPath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair);
|
||||
#endif
|
||||
auto source = sinkToSource([&](Sink & sink) {
|
||||
path2.accessor->dumpPath(path2.path, sink);
|
||||
});
|
||||
// FIXME: readOnlyMode
|
||||
auto p = store->addToStoreFromDump(*source, std::string(baseNameOf(path)), FileIngestionMethod::Recursive, htSHA256, repair);
|
||||
dstPath = store->printStorePath(p);
|
||||
allowPath(p);
|
||||
srcToStore.insert_or_assign(path, std::move(p));
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "symbol-table.hh"
|
||||
#include "config.hh"
|
||||
#include "experimental-features.hh"
|
||||
#include "input-accessor.hh"
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
@ -20,6 +21,7 @@ namespace nix {
|
|||
class Store;
|
||||
class EvalState;
|
||||
class StorePath;
|
||||
struct SourcePath;
|
||||
enum RepairFlag : bool;
|
||||
|
||||
|
||||
|
@ -95,6 +97,10 @@ public:
|
|||
|
||||
Bindings emptyBindings;
|
||||
|
||||
ref<InputAccessor> rootFS;
|
||||
|
||||
std::unordered_map<size_t, ref<InputAccessor>> inputAccessors;
|
||||
|
||||
/* Store used to materialise .drv files. */
|
||||
const ref<Store> store;
|
||||
|
||||
|
@ -153,6 +159,12 @@ public:
|
|||
|
||||
SearchPath getSearchPath() { return searchPath; }
|
||||
|
||||
Path packPath(const SourcePath & path);
|
||||
|
||||
SourcePath unpackPath(const Path & path);
|
||||
|
||||
SourcePath rootPath(const Path & path);
|
||||
|
||||
/* Allow access to a path. */
|
||||
void allowPath(const Path & path);
|
||||
|
||||
|
@ -163,10 +175,6 @@ public:
|
|||
/* Allow access to a store path and return it as a string. */
|
||||
void allowAndSetStorePathString(const StorePath & storePath, Value & v);
|
||||
|
||||
/* Check whether access to a path is allowed and throw an error if
|
||||
not. Otherwise return the canonicalised path. */
|
||||
Path checkSourcePath(const Path & path);
|
||||
|
||||
void checkURI(const std::string & uri);
|
||||
|
||||
/* When using a diverted store and 'path' is in the Nix store, map
|
||||
|
@ -179,8 +187,8 @@ public:
|
|||
Path toRealPath(const Path & path, const PathSet & context);
|
||||
|
||||
/* Parse a Nix expression from the specified file. */
|
||||
Expr * parseExprFromFile(const Path & path);
|
||||
Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv);
|
||||
Expr * parseExprFromFile(const SourcePath & path);
|
||||
Expr * parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv);
|
||||
|
||||
/* Parse a Nix expression from the specified string. */
|
||||
Expr * parseExprFromString(std::string s, const Path & basePath, StaticEnv & staticEnv);
|
||||
|
@ -191,7 +199,7 @@ public:
|
|||
/* Evaluate an expression read from the given file to normal
|
||||
form. Optionally enforce that the top-level expression is
|
||||
trivial (i.e. doesn't require arbitrary computation). */
|
||||
void evalFile(const Path & path, Value & v, bool mustBeTrivial = false);
|
||||
void evalFile(const SourcePath & path, Value & v, bool mustBeTrivial = false);
|
||||
|
||||
/* Like `cacheFile`, but with an already parsed expression. */
|
||||
void cacheFile(
|
||||
|
@ -269,6 +277,7 @@ public:
|
|||
/* Path coercion. Converts strings, paths and derivations to a
|
||||
path. The result is guaranteed to be a canonicalised, absolute
|
||||
path. Nothing is copied to the store. */
|
||||
// FIXME: return SourcePath
|
||||
Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
|
||||
|
||||
/* Like coerceToPath, but the result must be a store path. */
|
||||
|
@ -427,7 +436,7 @@ std::string showType(const Value & v);
|
|||
NixStringContextElem decodeContext(const Store & store, std::string_view s);
|
||||
|
||||
/* If `path' refers to a directory, then append "/default.nix". */
|
||||
Path resolveExprPath(Path path);
|
||||
SourcePath resolveExprPath(const SourcePath & path);
|
||||
|
||||
struct InvalidPathError : EvalError
|
||||
{
|
||||
|
|
|
@ -216,7 +216,8 @@ static Flake getFlake(
|
|||
throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir);
|
||||
|
||||
Value vInfo;
|
||||
state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack
|
||||
// FIXME: use accessor
|
||||
state.evalFile(state.rootPath(flakeFile), vInfo, true); // FIXME: symlink attack
|
||||
|
||||
expectType(state, nAttrs, vInfo, Pos(foFile, state.symbols.create(flakeFile), 0, 0));
|
||||
|
||||
|
|
|
@ -674,10 +674,9 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin,
|
|||
}
|
||||
|
||||
|
||||
Path resolveExprPath(Path path)
|
||||
SourcePath resolveExprPath(const SourcePath & path)
|
||||
{
|
||||
assert(path[0] == '/');
|
||||
|
||||
#if 0
|
||||
unsigned int followCount = 0, maxFollow = 1024;
|
||||
|
||||
/* If `path' is a symlink, follow it. This is so that relative
|
||||
|
@ -697,21 +696,30 @@ Path resolveExprPath(Path path)
|
|||
path = canonPath(path + "/default.nix");
|
||||
|
||||
return path;
|
||||
#endif
|
||||
|
||||
// FIXME
|
||||
auto path2 = path.path + "/default.nix";
|
||||
if (path.accessor->pathExists(path2))
|
||||
return {path.accessor, path2};
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
Expr * EvalState::parseExprFromFile(const Path & path)
|
||||
Expr * EvalState::parseExprFromFile(const SourcePath & path)
|
||||
{
|
||||
return parseExprFromFile(path, staticBaseEnv);
|
||||
}
|
||||
|
||||
|
||||
Expr * EvalState::parseExprFromFile(const Path & path, StaticEnv & staticEnv)
|
||||
Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv)
|
||||
{
|
||||
auto buffer = readFile(path);
|
||||
// readFile should have left some extra space for terminators
|
||||
auto packed = packPath(path);
|
||||
auto buffer = path.accessor->readFile(path.path);
|
||||
// readFile hopefully have left some extra space for terminators
|
||||
buffer.append("\0\0", 2);
|
||||
return parse(buffer.data(), buffer.size(), foFile, path, dirOf(path), staticEnv);
|
||||
return parse(buffer.data(), buffer.size(), foFile, packed, dirOf(packed), staticEnv);
|
||||
}
|
||||
|
||||
|
||||
|
|
39
src/libexpr/paths.cc
Normal file
39
src/libexpr/paths.cc
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "eval.hh"
|
||||
#include "util.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
static constexpr std::string_view marker = "/__virtual/";
|
||||
|
||||
Path EvalState::packPath(const SourcePath & path)
|
||||
{
|
||||
printError("PACK %s", path.path);
|
||||
assert(hasPrefix(path.path, "/"));
|
||||
inputAccessors.emplace(path.accessor->number, path.accessor);
|
||||
return std::string(marker) + std::to_string(path.accessor->number) + path.path;
|
||||
}
|
||||
|
||||
SourcePath EvalState::unpackPath(const Path & path)
|
||||
{
|
||||
if (hasPrefix(path, marker)) {
|
||||
auto s = path.substr(marker.size());
|
||||
auto slash = s.find('/');
|
||||
assert(slash != s.npos);
|
||||
auto n = std::stoi(s.substr(0, slash));
|
||||
printError("GOT %d", n);
|
||||
auto i = inputAccessors.find(n);
|
||||
assert(i != inputAccessors.end());
|
||||
return {i->second, s.substr(slash)};
|
||||
} else {
|
||||
printError("FIXME: %s", path);
|
||||
return rootPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
SourcePath EvalState::rootPath(const Path & path)
|
||||
{
|
||||
printError("ROOT %s", path);
|
||||
return {rootFS, path};
|
||||
}
|
||||
|
||||
}
|
|
@ -96,20 +96,23 @@ struct RealisePathFlags {
|
|||
bool checkForPureEval = true;
|
||||
};
|
||||
|
||||
static Path realisePath(EvalState & state, const Pos & pos, Value & v, const RealisePathFlags flags = {})
|
||||
static SourcePath realisePath(EvalState & state, const Pos & pos, Value & v, const RealisePathFlags flags = {})
|
||||
{
|
||||
PathSet context;
|
||||
|
||||
auto path = [&]()
|
||||
{
|
||||
try {
|
||||
return state.coerceToPath(pos, v, context);
|
||||
return state.unpackPath(state.coerceToPath(pos, v, context));
|
||||
} catch (Error & e) {
|
||||
e.addTrace(pos, "while realising the context of a path");
|
||||
throw;
|
||||
}
|
||||
}();
|
||||
|
||||
return path;
|
||||
|
||||
#if 0
|
||||
try {
|
||||
StringMap rewrites = state.realiseContext(context);
|
||||
|
||||
|
@ -122,6 +125,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea
|
|||
e.addTrace(pos, "while realising the context of path '%s'", path);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Add and attribute to the given attribute map from the output name to
|
||||
|
@ -161,6 +165,18 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
|||
{
|
||||
auto path = realisePath(state, pos, vPath);
|
||||
|
||||
#if 0
|
||||
// FIXME: use InputAccessor
|
||||
if (path == corepkgsPrefix + "fetchurl.nix") {
|
||||
state.eval(state.parseExprFromString(
|
||||
#include "fetchurl.nix.gen.hh"
|
||||
, "/"), v);
|
||||
}
|
||||
#endif
|
||||
|
||||
state.evalFile(path, v);
|
||||
|
||||
#if 0
|
||||
// FIXME
|
||||
auto isValidDerivationInStore = [&]() -> std::optional<StorePath> {
|
||||
if (!state.store->isStorePath(path))
|
||||
|
@ -200,6 +216,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
|||
state.forceAttrs(v, pos);
|
||||
}
|
||||
|
||||
// FIXME: use InputAccessor
|
||||
else if (path == corepkgsPrefix + "fetchurl.nix") {
|
||||
state.eval(state.parseExprFromString(
|
||||
#include "fetchurl.nix.gen.hh"
|
||||
|
@ -232,6 +249,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
|||
e->eval(state, *env, v);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info {
|
||||
|
@ -312,6 +330,9 @@ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
|
|||
/* Load a ValueInitializer from a DSO and return whatever it initializes */
|
||||
void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
throw UnimplementedError("importNative");
|
||||
|
||||
#if 0
|
||||
auto path = realisePath(state, pos, *args[0]);
|
||||
|
||||
std::string sym(state.forceStringNoCtx(*args[1], pos));
|
||||
|
@ -334,6 +355,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
|
|||
(func)(state, v);
|
||||
|
||||
/* We don't dlclose because v may be a primop referencing a function in the shared object file */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1343,7 +1365,8 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
|
|||
});
|
||||
|
||||
PathSet context;
|
||||
Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context));
|
||||
// FIXME: check rootPath
|
||||
Path path = state.coerceToPath(pos, *args[0], context);
|
||||
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
||||
directly in the store. The latter condition is necessary so
|
||||
e.g. nix-push does the right thing. */
|
||||
|
@ -1388,7 +1411,7 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args,
|
|||
auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false });
|
||||
|
||||
try {
|
||||
v.mkBool(pathExists(state.checkSourcePath(path)));
|
||||
v.mkBool(path.accessor->pathExists(path.path));
|
||||
} catch (SysError & e) {
|
||||
/* Don't give away info from errors while canonicalising
|
||||
‘path’ in restricted mode. */
|
||||
|
@ -1453,16 +1476,15 @@ static RegisterPrimOp primop_dirOf({
|
|||
static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
auto path = realisePath(state, pos, *args[0]);
|
||||
auto s = readFile(path);
|
||||
auto s = path.accessor->readFile(path.path);
|
||||
if (s.find((char) 0) != std::string::npos)
|
||||
throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path);
|
||||
StorePathSet refs;
|
||||
if (state.store->isInStore(path)) {
|
||||
try {
|
||||
refs = state.store->queryPathInfo(state.store->toStorePath(path).first)->references;
|
||||
} catch (Error &) { // FIXME: should be InvalidPathError
|
||||
}
|
||||
}
|
||||
auto refs =
|
||||
#if 0
|
||||
state.store->isInStore(path) ?
|
||||
state.store->queryPathInfo(state.store->toStorePath(path).first)->references :
|
||||
#endif
|
||||
StorePathSet{};
|
||||
auto context = state.store->printStorePathSet(refs);
|
||||
v.mkString(s, context);
|
||||
}
|
||||
|
@ -1480,6 +1502,7 @@ static RegisterPrimOp primop_readFile({
|
|||
which are desugared to 'findFile __nixPath "x"'. */
|
||||
static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
#if 0
|
||||
state.forceList(*args[0], pos);
|
||||
|
||||
SearchPath searchPath;
|
||||
|
@ -1500,26 +1523,18 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
pos
|
||||
);
|
||||
|
||||
PathSet context;
|
||||
auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
|
||||
|
||||
try {
|
||||
auto rewrites = state.realiseContext(context);
|
||||
path = rewriteStrings(path, rewrites);
|
||||
} catch (InvalidPathError & e) {
|
||||
throw EvalError({
|
||||
.msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path),
|
||||
.errPos = pos
|
||||
});
|
||||
}
|
||||
|
||||
auto path = realisePath(state, pos, *i->value, { .requireAbsolutePath = false });
|
||||
|
||||
searchPath.emplace_back(prefix, path);
|
||||
}
|
||||
|
||||
auto path = state.forceStringNoCtx(*args[1], pos);
|
||||
|
||||
v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos)));
|
||||
// FIXME: checkSourcePath?
|
||||
v.mkPath(state.findFile(searchPath, path, pos));
|
||||
#endif
|
||||
|
||||
throw UnimplementedError("findFile");
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
|
||||
|
@ -1541,7 +1556,8 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va
|
|||
|
||||
auto path = realisePath(state, pos, *args[1]);
|
||||
|
||||
v.mkString(hashFile(*ht, path).to_string(Base16, false));
|
||||
// FIXME: state.toRealPath(path, context)
|
||||
v.mkString(hashString(*ht, path.accessor->readFile(path.path)).to_string(Base16, false));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_hashFile({
|
||||
|
@ -1560,17 +1576,19 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
|
|||
{
|
||||
auto path = realisePath(state, pos, *args[0]);
|
||||
|
||||
DirEntries entries = readDirectory(path);
|
||||
|
||||
auto entries = path.accessor->readDirectory(path.path);
|
||||
auto attrs = state.buildBindings(entries.size());
|
||||
|
||||
for (auto & ent : entries) {
|
||||
if (ent.type == DT_UNKNOWN)
|
||||
ent.type = getFileType(path + "/" + ent.name);
|
||||
attrs.alloc(ent.name).mkString(
|
||||
ent.type == DT_REG ? "regular" :
|
||||
ent.type == DT_DIR ? "directory" :
|
||||
ent.type == DT_LNK ? "symlink" :
|
||||
for (auto & [name, type] : entries) {
|
||||
#if 0
|
||||
// FIXME?
|
||||
if (type == InputAccessor::Type::Misc)
|
||||
ent.type = getFileType(path + "/" + name);
|
||||
#endif
|
||||
attrs.alloc(name).mkString(
|
||||
type == InputAccessor::Type::tRegular ? "regular" :
|
||||
type == InputAccessor::Type::tDirectory ? "directory" :
|
||||
type == InputAccessor::Type::tSymlink ? "symlink" :
|
||||
"unknown");
|
||||
}
|
||||
|
||||
|
@ -1902,9 +1920,12 @@ static void addPath(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME
|
||||
#if 0
|
||||
path = evalSettings.pureEval && expectedHash
|
||||
? path
|
||||
: state.checkSourcePath(path);
|
||||
#endif
|
||||
|
||||
PathFilter filter = filterFun ? ([&](const Path & path) {
|
||||
auto st = lstat(path);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "path.hh"
|
||||
#include "attrs.hh"
|
||||
#include "url.hh"
|
||||
#include "input-accessor.hh"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -27,7 +28,6 @@ struct InputScheme;
|
|||
* "fromURL()" or "fromAttrs()" static functions which are provided
|
||||
* the url or attrset specified in the flake file.
|
||||
*/
|
||||
|
||||
struct Input
|
||||
{
|
||||
friend struct InputScheme;
|
||||
|
@ -98,7 +98,6 @@ public:
|
|||
std::optional<time_t> getLastModified() const;
|
||||
};
|
||||
|
||||
|
||||
/* The InputScheme represents a type of fetcher. Each fetcher
|
||||
* registers with nix at startup time. When processing an input for a
|
||||
* flake, each scheme is given an opportunity to "recognize" that
|
||||
|
@ -107,7 +106,6 @@ public:
|
|||
* recognized. The Input object contains the information the fetcher
|
||||
* needs to actually perform the "fetch()" when called.
|
||||
*/
|
||||
|
||||
struct InputScheme
|
||||
{
|
||||
virtual ~InputScheme()
|
||||
|
@ -133,6 +131,11 @@ struct InputScheme
|
|||
virtual void markChangedFile(const Input & input, std::string_view file, std::optional<std::string> commitMsg);
|
||||
|
||||
virtual std::pair<StorePath, Input> fetch(ref<Store> store, const Input & input) = 0;
|
||||
|
||||
virtual ref<InputAccessor> getAccessor()
|
||||
{
|
||||
throw UnimplementedError("getAccessor");
|
||||
}
|
||||
};
|
||||
|
||||
void registerInputScheme(std::shared_ptr<InputScheme> && fetcher);
|
||||
|
|
178
src/libfetchers/input-accessor.cc
Normal file
178
src/libfetchers/input-accessor.cc
Normal file
|
@ -0,0 +1,178 @@
|
|||
#include "input-accessor.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace nix {
|
||||
|
||||
static std::atomic<size_t> nextNumber{0};
|
||||
|
||||
InputAccessor::InputAccessor()
|
||||
: number(++nextNumber)
|
||||
{
|
||||
printError("CREATE %d", number);
|
||||
}
|
||||
|
||||
// FIXME: merge with archive.cc.
|
||||
const std::string narVersionMagic1 = "nix-archive-1";
|
||||
|
||||
static string caseHackSuffix = "~nix~case~hack~";
|
||||
|
||||
void InputAccessor::dumpPath(
|
||||
const Path & path,
|
||||
Sink & sink,
|
||||
PathFilter & filter)
|
||||
{
|
||||
auto dumpContents = [&](std::string_view path)
|
||||
{
|
||||
// FIXME: pipe
|
||||
auto s = readFile(path);
|
||||
sink << "contents" << s.size();
|
||||
sink(s);
|
||||
writePadding(s.size(), sink);
|
||||
};
|
||||
|
||||
std::function<void(const std::string & path)> dump;
|
||||
|
||||
dump = [&](const std::string & 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<string, string> unhacked;
|
||||
for (auto & i : readDirectory(path))
|
||||
if (/* archiveSettings.useCaseHack */ false) { // FIXME
|
||||
string name(i.first);
|
||||
size_t pos = i.first.find(caseHackSuffix);
|
||||
if (pos != string::npos) {
|
||||
debug(format("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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
struct FSInputAccessor : InputAccessor
|
||||
{
|
||||
Path root;
|
||||
|
||||
FSInputAccessor(const Path & root)
|
||||
: root(root)
|
||||
{ }
|
||||
|
||||
std::string readFile(std::string_view path) override
|
||||
{
|
||||
auto absPath = makeAbsPath(path);
|
||||
printError("READ %s", absPath);
|
||||
checkAllowed(absPath);
|
||||
return nix::readFile(absPath);
|
||||
}
|
||||
|
||||
bool pathExists(std::string_view path) override
|
||||
{
|
||||
auto absPath = makeAbsPath(path);
|
||||
printError("EXISTS %s", absPath);
|
||||
return isAllowed(absPath) && nix::pathExists(absPath);
|
||||
}
|
||||
|
||||
Stat lstat(std::string_view path) override
|
||||
{
|
||||
auto absPath = makeAbsPath(path);
|
||||
printError("LSTAT %s", absPath);
|
||||
checkAllowed(absPath);
|
||||
auto st = nix::lstat(absPath);
|
||||
return Stat {
|
||||
.type =
|
||||
S_ISREG(st.st_mode) ? tRegular :
|
||||
S_ISDIR(st.st_mode) ? tDirectory :
|
||||
S_ISLNK(st.st_mode) ? tSymlink :
|
||||
tMisc,
|
||||
.isExecutable = S_ISREG(st.st_mode) && st.st_mode & S_IXUSR
|
||||
};
|
||||
}
|
||||
|
||||
DirEntries readDirectory(std::string_view path) override
|
||||
{
|
||||
auto absPath = makeAbsPath(path);
|
||||
printError("READDIR %s", absPath);
|
||||
checkAllowed(absPath);
|
||||
abort();
|
||||
}
|
||||
|
||||
std::string readLink(std::string_view path) override
|
||||
{
|
||||
auto absPath = makeAbsPath(path);
|
||||
printError("READLINK %s", absPath);
|
||||
checkAllowed(absPath);
|
||||
return nix::readLink(absPath);
|
||||
}
|
||||
|
||||
Path makeAbsPath(std::string_view path)
|
||||
{
|
||||
assert(hasPrefix(path, "/"));
|
||||
return canonPath(root + std::string(path));
|
||||
}
|
||||
|
||||
void checkAllowed(std::string_view absPath)
|
||||
{
|
||||
if (!isAllowed(absPath))
|
||||
throw Error("access to path '%s' is not allowed", absPath);
|
||||
}
|
||||
|
||||
bool isAllowed(std::string_view absPath)
|
||||
{
|
||||
if (!isDirOrInDir(absPath, root))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ref<InputAccessor> makeFSInputAccessor(const Path & root)
|
||||
{
|
||||
return make_ref<FSInputAccessor>(root);
|
||||
}
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const SourcePath & path)
|
||||
{
|
||||
str << path.path; // FIXME
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
57
src/libfetchers/input-accessor.hh
Normal file
57
src/libfetchers/input-accessor.hh
Normal file
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include "ref.hh"
|
||||
#include "types.hh"
|
||||
#include "archive.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct InputAccessor
|
||||
{
|
||||
const size_t number;
|
||||
|
||||
InputAccessor();
|
||||
|
||||
virtual ~InputAccessor()
|
||||
{ }
|
||||
|
||||
virtual std::string readFile(std::string_view path) = 0;
|
||||
|
||||
virtual bool pathExists(std::string_view path) = 0;
|
||||
|
||||
enum Type { tRegular, tSymlink, tDirectory, tMisc };
|
||||
|
||||
struct Stat
|
||||
{
|
||||
Type type = tMisc;
|
||||
//uint64_t fileSize = 0; // regular files only
|
||||
bool isExecutable = false; // regular files only
|
||||
};
|
||||
|
||||
virtual Stat lstat(std::string_view path) = 0;
|
||||
|
||||
typedef std::optional<Type> DirEntry;
|
||||
|
||||
typedef std::map<std::string, DirEntry> DirEntries;
|
||||
|
||||
virtual DirEntries readDirectory(std::string_view path) = 0;
|
||||
|
||||
virtual std::string readLink(std::string_view path) = 0;
|
||||
|
||||
virtual void dumpPath(
|
||||
const Path & path,
|
||||
Sink & sink,
|
||||
PathFilter & filter = defaultPathFilter);
|
||||
};
|
||||
|
||||
ref<InputAccessor> makeFSInputAccessor(const Path & root);
|
||||
|
||||
struct SourcePath
|
||||
{
|
||||
ref<InputAccessor> accessor;
|
||||
Path path;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & str, const SourcePath & path);
|
||||
|
||||
}
|
|
@ -304,7 +304,11 @@ static void main_nix_build(int argc, char * * argv)
|
|||
else
|
||||
/* If we're in a #! script, interpret filenames
|
||||
relative to the script. */
|
||||
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state,
|
||||
exprs.push_back(
|
||||
state->parseExprFromFile(
|
||||
resolveExprPath(
|
||||
state->rootPath(
|
||||
lookupFileArg(*state,
|
||||
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
|
|||
throw SysError("getting information about '%1%'", path);
|
||||
|
||||
if (isNixExpr(path, st))
|
||||
state.evalFile(path, v);
|
||||
state.evalFile(state.rootPath(path), v);
|
||||
|
||||
/* The path is a directory. Put the Nix expressions in the
|
||||
directory in a set, with the file name of each expression as
|
||||
|
|
|
@ -22,7 +22,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
|||
Path manifestFile = userEnv + "/manifest.nix";
|
||||
if (pathExists(manifestFile)) {
|
||||
Value v;
|
||||
state.evalFile(manifestFile, v);
|
||||
state.evalFile(state.rootPath(manifestFile), v);
|
||||
Bindings & bindings(*state.allocBindings(0));
|
||||
getDerivations(state, v, "", bindings, elems, false);
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ static int main_nix_instantiate(int argc, char * * argv)
|
|||
for (auto & i : files) {
|
||||
Expr * e = fromArgs
|
||||
? state->parseExprFromString(i, absPath("."))
|
||||
: state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
|
||||
: state->parseExprFromFile(resolveExprPath(state->rootPath(lookupFileArg(*state, i))));
|
||||
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
|
||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||
}
|
||||
|
|
|
@ -192,9 +192,11 @@ static int main_nix_prefetch_url(int argc, char * * argv)
|
|||
throw UsageError("you must specify a URL");
|
||||
url = args[0];
|
||||
} else {
|
||||
Path path = resolveExprPath(lookupFileArg(*state, args.empty() ? "." : args[0]));
|
||||
Value vRoot;
|
||||
state->evalFile(path, vRoot);
|
||||
state->evalFile(
|
||||
resolveExprPath(
|
||||
state->rootPath(lookupFileArg(*state, args.empty() ? "." : args[0]))),
|
||||
vRoot);
|
||||
Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first);
|
||||
state->forceAttrs(v, noPos);
|
||||
|
||||
|
|
|
@ -624,7 +624,7 @@ void NixRepl::loadFile(const Path & path)
|
|||
loadedFiles.remove(path);
|
||||
loadedFiles.push_back(path);
|
||||
Value v, v2;
|
||||
state->evalFile(lookupFileArg(*state, path), v);
|
||||
state->evalFile(state->rootPath(lookupFileArg(*state, path)), v);
|
||||
state->autoCallFunction(*autoArgs, v, v2);
|
||||
addAttrsToScope(v2);
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@ libplugintest_ALLOW_UNDEFINED := 1
|
|||
|
||||
libplugintest_EXCLUDE_FROM_LIBRARY_LIST := 1
|
||||
|
||||
libplugintest_CXXFLAGS := -I src/libutil -I src/libexpr
|
||||
libplugintest_CXXFLAGS := -I src/libutil -I src/libexpr -I src/libfetchers
|
||||
|
|
Loading…
Reference in a new issue