Checkpoint

This commit is contained in:
Eelco Dolstra 2021-12-06 11:14:52 +01:00
parent 2d572a250f
commit c56e17b718
17 changed files with 428 additions and 79 deletions

View file

@ -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);

View file

@ -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));

View file

@ -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
{

View file

@ -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));

View file

@ -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
View 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};
}
}

View file

@ -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);

View file

@ -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);

View 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;
}
}

View 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);
}

View file

@ -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)))));
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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