Checkpoint

This commit is contained in:
Eelco Dolstra 2022-03-01 19:08:20 +01:00
parent 00b0fb27c1
commit 06c1edf889
18 changed files with 134 additions and 120 deletions

View file

@ -396,8 +396,11 @@ Value & AttrCursor::forceValue()
if (v.type() == nString) if (v.type() == nString)
cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context),
string_t{v.string.s, {}}}; string_t{v.string.s, {}}};
else if (v.type() == nPath) else if (v.type() == nPath) {
cachedValue = {root->db->setString(getKey(), v.path), string_t{v.path, {}}}; // FIXME: take accessor into account?
auto path = v.path().path;
cachedValue = {root->db->setString(getKey(), path), string_t{path, {}}};
}
else if (v.type() == nBool) else if (v.type() == nBool)
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean}; cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
else if (v.type() == nAttrs) else if (v.type() == nAttrs)
@ -537,7 +540,7 @@ std::string AttrCursor::getString()
if (v.type() != nString && v.type() != nPath) if (v.type() != nString && v.type() != nPath)
throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()));
return v.type() == nString ? v.string.s : v.path; return v.type() == nString ? v.string.s : v.path().to_string();
} }
string_t AttrCursor::getStringWithContext() string_t AttrCursor::getStringWithContext()
@ -568,7 +571,7 @@ string_t AttrCursor::getStringWithContext()
if (v.type() == nString) if (v.type() == nString)
return {v.string.s, v.getContext(*root->state.store)}; return {v.string.s, v.getContext(*root->state.store)};
else if (v.type() == nPath) else if (v.type() == nPath)
return {v.path, {}}; return {v.path().to_string(), {}};
else else
throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type()));
} }

View file

@ -119,7 +119,7 @@ void Value::print(std::ostream & str, std::set<const void *> * seen) const
str << "\""; str << "\"";
break; break;
case tPath: case tPath:
str << path; // !!! escaping? str << path().to_string(); // !!! escaping?
break; break;
case tNull: case tNull:
str << "null"; str << "null";
@ -721,11 +721,6 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
evaluator. So here are some helper functions for throwing evaluator. So here are some helper functions for throwing
exceptions. */ exceptions. */
LocalNoInlineNoReturn(void throwEvalError(const char * s, const std::string & s2))
{
throw EvalError(s, s2);
}
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s, const std::string & s2)) LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s, const std::string & s2))
{ {
throw EvalError(ErrorInfo { throw EvalError(ErrorInfo {
@ -862,9 +857,12 @@ void Value::mkStringMove(const char * s, const PathSet & context)
} }
void Value::mkPath(std::string_view s) void Value::mkPath(const SourcePath & path)
{ {
mkPath(makeImmutableString(s)); clearValue();
internalType = tPath;
_path.accessor = &path.accessor;
_path.path = makeImmutableString(path.path);
} }
@ -978,24 +976,19 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
} }
void EvalState::evalFile(const SourcePath & 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 // FIXME: use SourcePath as cache key
auto pathKey = path.to_string();
FileEvalCache::iterator i; FileEvalCache::iterator i;
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) { if ((i = fileEvalCache.find(pathKey)) != fileEvalCache.end()) {
v = i->second; v = i->second;
return; return;
} }
auto resolvedPath_ = resolveExprPath(path_); auto resolvedPath = resolveExprPath(path);
auto resolvedPath = packPath(resolvedPath_); auto resolvedPathKey = resolvedPath.to_string();
if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) { if ((i = fileEvalCache.find(resolvedPathKey)) != fileEvalCache.end()) {
v = i->second; v = i->second;
return; return;
} }
@ -1003,17 +996,17 @@ void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial
printTalkative("evaluating file '%1%'", resolvedPath); printTalkative("evaluating file '%1%'", resolvedPath);
Expr * e = nullptr; Expr * e = nullptr;
auto j = fileParseCache.find(resolvedPath); auto j = fileParseCache.find(resolvedPathKey);
if (j != fileParseCache.end()) if (j != fileParseCache.end())
e = j->second; e = j->second;
if (!e) if (!e)
e = parseExprFromFile(resolvedPath_); e = parseExprFromFile(resolvedPath);
#if 0 #if 0
e = parseExprFromFile(checkSourcePath(resolvedPath)); e = parseExprFromFile(checkSourcePath(resolvedPath));
#endif #endif
cacheFile(path, resolvedPath, e, v, mustBeTrivial); cacheFile(pathKey, resolvedPathKey, e, v, mustBeTrivial);
} }
@ -1790,9 +1783,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp)); throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp));
} else { } else {
if (s.empty()) s.reserve(es->size()); if (s.empty()) s.reserve(es->size());
/* skip canonization of first path, which would only be not /* Skip canonization of first path, which would only be
canonized in the first place if it's coming from a ./${foo} type non-canonical in the first place if it's coming from a
path */ ./${foo} type path. */
auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first); auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first);
sSize += part->size(); sSize += part->size();
s.emplace_back(std::move(part)); s.emplace_back(std::move(part));
@ -1808,7 +1801,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
else if (firstType == nPath) { else if (firstType == nPath) {
if (!context.empty()) if (!context.empty())
throwEvalError(pos, "a string that refers to a store path cannot be appended to a path"); throwEvalError(pos, "a string that refers to a store path cannot be appended to a path");
v.mkPath(canonPath(str())); v.mkPath({.accessor = *values[0]._path.accessor, .path = canonPath(str())});
} else } else
v.mkStringMove(c_str(), context); v.mkStringMove(c_str(), context);
} }
@ -2005,11 +1998,12 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
} }
if (v.type() == nPath) { if (v.type() == nPath) {
BackedStringView path(PathView(v.path)); auto path = v.path().to_string();
if (canonicalizePath) if (canonicalizePath)
path = canonPath(*path); // FIXME: unnecessary?
path = canonPath(path);
if (copyToStore) if (copyToStore)
path = copyPathToStore(context, std::move(path).toOwned()); path = copyPathToStore(context, path);
return path; return path;
} }
@ -2054,6 +2048,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
std::string EvalState::copyPathToStore(PathSet & context, const Path & path) std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
{ {
#if 0
if (nix::isDerivation(path)) if (nix::isDerivation(path))
throwEvalError("file names are not allowed to end in '%1%'", drvExtension); throwEvalError("file names are not allowed to end in '%1%'", drvExtension);
@ -2070,7 +2065,7 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
: store->addToStore(path2.baseName(), canonPath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair); : store->addToStore(path2.baseName(), canonPath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair);
#endif #endif
auto source = sinkToSource([&](Sink & sink) { auto source = sinkToSource([&](Sink & sink) {
path2.accessor->dumpPath(path2.path, sink); path2.dumpPath(sink);
}); });
// FIXME: readOnlyMode // FIXME: readOnlyMode
auto p = store->addToStoreFromDump(*source, path2.baseName(), FileIngestionMethod::Recursive, htSHA256, repair); auto p = store->addToStoreFromDump(*source, path2.baseName(), FileIngestionMethod::Recursive, htSHA256, repair);
@ -2082,15 +2077,18 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
context.insert(dstPath); context.insert(dstPath);
return dstPath; return dstPath;
#endif
abort();
} }
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context) SourcePath EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
{ {
auto path = coerceToString(pos, v, context, false, false).toOwned(); auto path = coerceToString(pos, v, context, false, false).toOwned();
if (path == "" || path[0] != '/') if (path == "" || path[0] != '/')
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
return path; // FIXME
return rootPath(path);
} }
@ -2137,7 +2135,9 @@ bool EvalState::eqValues(Value & v1, Value & v2)
return strcmp(v1.string.s, v2.string.s) == 0; return strcmp(v1.string.s, v2.string.s) == 0;
case nPath: case nPath:
return strcmp(v1.path, v2.path) == 0; return
v1._path.accessor == v2._path.accessor
&& strcmp(v1._path.path, v2._path.path) == 0;
case nNull: case nNull:
return true; return true;

View file

@ -96,7 +96,7 @@ public:
ref<FSInputAccessor> rootFS; ref<FSInputAccessor> rootFS;
ref<MemoryInputAccessor> corepkgsFS; ref<MemoryInputAccessor> corepkgsFS;
std::unordered_map<size_t, ref<InputAccessor>> inputAccessors; std::unordered_map<InputAccessor *, ref<InputAccessor>> inputAccessors;
/* Store used to materialise .drv files. */ /* Store used to materialise .drv files. */
const ref<Store> store; const ref<Store> store;
@ -156,11 +156,9 @@ public:
SearchPath getSearchPath() { return searchPath; } SearchPath getSearchPath() { return searchPath; }
Path packPath(const SourcePath & path); SourcePath rootPath(Path path);
SourcePath unpackPath(const Path & path); InputAccessor & registerAccessor(ref<InputAccessor> accessor);
SourcePath rootPath(const Path & path);
/* Allow access to a path. */ /* Allow access to a path. */
void allowPath(const Path & path); void allowPath(const Path & path);
@ -274,8 +272,7 @@ public:
/* Path coercion. Converts strings, paths and derivations to a /* Path coercion. Converts strings, paths and derivations to a
path. The result is guaranteed to be a canonicalised, absolute path. The result is guaranteed to be a canonicalised, absolute
path. Nothing is copied to the store. */ path. Nothing is copied to the store. */
// FIXME: return SourcePath SourcePath coerceToPath(const Pos & pos, Value & v, PathSet & context);
Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
/* Like coerceToPath, but the result must be a store path. */ /* Like coerceToPath, but the result must be a store path. */
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context); StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);

View file

@ -201,7 +201,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
static Flake readFlake( static Flake readFlake(
EvalState & state, EvalState & state,
const FlakeRef & lockedRef, const FlakeRef & lockedRef,
nix::ref<InputAccessor> accessor, InputAccessor & accessor,
const InputPath & lockRootPath) const InputPath & lockRootPath)
{ {
auto flakeDir = canonPath("/" + lockedRef.subdir); auto flakeDir = canonPath("/" + lockedRef.subdir);
@ -213,14 +213,14 @@ static Flake readFlake(
Value vInfo; Value vInfo;
state.evalFile(flakePath, vInfo, true); state.evalFile(flakePath, vInfo, true);
expectType(state, nAttrs, vInfo, Pos(foFile, state.symbols.create(state.packPath(flakePath)), 0, 0)); expectType(state, nAttrs, vInfo, Pos(foFile, state.symbols.create(flakePath.to_string()), 0, 0));
Flake flake { Flake flake {
// FIXME // FIXME
.originalRef = lockedRef, .originalRef = lockedRef,
.resolvedRef = lockedRef, .resolvedRef = lockedRef,
.lockedRef = lockedRef, .lockedRef = lockedRef,
.accessor = accessor, .accessor = ptr(&accessor),
.flakePath = dirOf(flakePath.path), .flakePath = dirOf(flakePath.path),
}; };
@ -308,7 +308,7 @@ static Flake getFlake(
// FIXME: resolve // FIXME: resolve
auto [accessor, input] = originalRef.input.lazyFetch(state.store); auto [accessor, input] = originalRef.input.lazyFetch(state.store);
return readFlake(state, originalRef, accessor, lockRootPath); return readFlake(state, originalRef, state.registerAccessor(accessor), lockRootPath);
} }
Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup, FlakeCache & flakeCache) Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup, FlakeCache & flakeCache)
@ -324,7 +324,7 @@ Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup
static LockFile readLockFile(const Flake & flake) static LockFile readLockFile(const Flake & flake)
{ {
SourcePath lockFilePath{flake.accessor, canonPath(flake.flakePath + "/flake.lock")}; SourcePath lockFilePath{*flake.accessor, canonPath(flake.flakePath + "/flake.lock")};
return lockFilePath.pathExists() return lockFilePath.pathExists()
? LockFile(lockFilePath.readFile(), fmt("%s", lockFilePath)) ? LockFile(lockFilePath.readFile(), fmt("%s", lockFilePath))
: LockFile(); : LockFile();
@ -703,7 +703,7 @@ void callFlake(EvalState & state,
emitTreeAttrs( emitTreeAttrs(
state, state,
{lockedFlake.flake.accessor, lockedFlake.flake.flakePath}, {*lockedFlake.flake.accessor, lockedFlake.flake.flakePath},
lockedFlake.flake.lockedRef.input, lockedFlake.flake.lockedRef.input,
*vRootSrc, *vRootSrc,
false, false,

View file

@ -61,7 +61,7 @@ struct Flake
FlakeRef originalRef; // the original flake specification (by the user) FlakeRef originalRef; // the original flake specification (by the user)
FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake
FlakeRef lockedRef; // the specific local store result of invoking the fetcher FlakeRef lockedRef; // the specific local store result of invoking the fetcher
ref<InputAccessor> accessor; ptr<InputAccessor> accessor;
Path flakePath; Path flakePath;
bool forceDirty = false; // pretend that 'lockedRef' is dirty bool forceDirty = false; // pretend that 'lockedRef' is dirty
std::optional<std::string> description; std::optional<std::string> description;

View file

@ -121,9 +121,13 @@ struct ExprString : Expr
struct ExprPath : Expr struct ExprPath : Expr
{ {
std::string s; std::string s; // FIXME: remove
Value v; Value v;
ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); }; ExprPath(InputAccessor & accessor, std::string s)
: s(std::move(s))
{
v.mkPath({accessor, this->s});
}
COMMON_METHODS COMMON_METHODS
Value * maybeThunk(EvalState & state, Env & env); Value * maybeThunk(EvalState & state, Env & env);
}; };

View file

@ -517,11 +517,11 @@ path_start
/* add back in the trailing '/' to the first segment */ /* add back in the trailing '/' to the first segment */
if ($1.p[$1.l-1] == '/' && $1.l > 1) if ($1.p[$1.l-1] == '/' && $1.l > 1)
path += "/"; path += "/";
$$ = new ExprPath(path); $$ = new ExprPath(*data->state.rootFS, path);
} }
| HPATH { | HPATH {
Path path(getHome() + std::string($1.p + 1, $1.l - 1)); Path path(getHome() + std::string($1.p + 1, $1.l - 1));
$$ = new ExprPath(path); $$ = new ExprPath(*data->state.rootFS, path);
} }
; ;
@ -700,7 +700,7 @@ SourcePath resolveExprPath(const SourcePath & path)
// FIXME // FIXME
auto path2 = path.path + "/default.nix"; auto path2 = path.path + "/default.nix";
if (path.accessor->pathExists(path2)) if (path.pathExists())
return {path.accessor, path2}; return {path.accessor, path2};
return path; return path;
@ -715,11 +715,11 @@ Expr * EvalState::parseExprFromFile(const SourcePath & path)
Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv) Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv)
{ {
auto packed = packPath(path);
auto buffer = path.readFile(); auto buffer = path.readFile();
// readFile hopefully have left some extra space for terminators // readFile hopefully have left some extra space for terminators
buffer.append("\0\0", 2); buffer.append("\0\0", 2);
return parse(buffer.data(), buffer.size(), foFile, packed, dirOf(packed), staticEnv); // FIXME: pass SourcePaths
return parse(buffer.data(), buffer.size(), foFile, path.path, dirOf(path.path), staticEnv);
} }
@ -788,7 +788,8 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c
} }
if (hasPrefix(path, "nix/")) if (hasPrefix(path, "nix/"))
return packPath(SourcePath {corepkgsFS, (std::string) path.substr(3)}); abort();
//return packPath(SourcePath {corepkgsFS, (std::string) path.substr(3)});
throw ThrownError({ throw ThrownError({
.msg = hintfmt(evalSettings.pureEval .msg = hintfmt(evalSettings.pureEval

View file

@ -3,34 +3,15 @@
namespace nix { namespace nix {
static constexpr std::string_view marker = "/__virtual/"; SourcePath EvalState::rootPath(Path path)
Path EvalState::packPath(const SourcePath & path)
{ {
// FIXME: canonPath(path) ? return {*rootFS, std::move(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) InputAccessor & EvalState::registerAccessor(ref<InputAccessor> accessor)
{ {
if (hasPrefix(path, marker)) { inputAccessors.emplace(&*accessor, accessor);
auto s = path.substr(marker.size()); return *accessor;
auto slash = s.find('/');
auto n = std::stoi(s.substr(0, slash));
auto i = inputAccessors.find(n);
assert(i != inputAccessors.end());
return {i->second, slash != std::string::npos ? s.substr(slash) : "/"};
} else {
printError("FIXME: %s", path);
return rootPath(path);
}
}
SourcePath EvalState::rootPath(const Path & path)
{
return {rootFS, path};
} }
} }

View file

@ -104,7 +104,7 @@ static SourcePath realisePath(EvalState & state, const Pos & pos, Value & v, con
auto path = [&]() auto path = [&]()
{ {
try { try {
return state.unpackPath(state.coerceToPath(pos, v, context)); return state.coerceToPath(pos, v, context);
} catch (Error & e) { } catch (Error & e) {
e.addTrace(pos, "while realising the context of a path"); e.addTrace(pos, "while realising the context of a path");
throw; throw;
@ -557,7 +557,8 @@ struct CompareValues
case nString: case nString:
return strcmp(v1->string.s, v2->string.s) < 0; return strcmp(v1->string.s, v2->string.s) < 0;
case nPath: case nPath:
return strcmp(v1->path, v2->path) < 0; // FIXME: handle accessor?
return strcmp(v1->_path.path, v2->_path.path) < 0;
case nList: case nList:
// Lexicographic comparison // Lexicographic comparison
for (size_t i = 0;; i++) { for (size_t i = 0;; i++) {
@ -1315,8 +1316,8 @@ static RegisterPrimOp primop_placeholder({
static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
Path path = state.coerceToPath(pos, *args[0], context); auto path = state.coerceToPath(pos, *args[0], context);
v.mkString(canonPath(path), context); v.mkString(canonPath(path.path), context);
} }
static RegisterPrimOp primop_toPath({ static RegisterPrimOp primop_toPath({
@ -1347,7 +1348,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
PathSet context; PathSet context;
// FIXME: check rootPath // FIXME: check rootPath
Path path = state.coerceToPath(pos, *args[0], context); auto path = state.coerceToPath(pos, *args[0], context).path;
/* Resolve symlinks in path, unless path itself is a symlink /* Resolve symlinks in path, unless path itself is a symlink
directly in the store. The latter condition is necessary so directly in the store. The latter condition is necessary so
e.g. nix-push does the right thing. */ e.g. nix-push does the right thing. */
@ -1439,7 +1440,10 @@ static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value
PathSet context; PathSet context;
auto path = state.coerceToString(pos, *args[0], context, false, false); auto path = state.coerceToString(pos, *args[0], context, false, false);
auto dir = dirOf(*path); auto dir = dirOf(*path);
abort();
#if 0
if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context); if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context);
#endif
} }
static RegisterPrimOp primop_dirOf({ static RegisterPrimOp primop_dirOf({
@ -1520,8 +1524,11 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
auto path = state.forceStringNoCtx(*args[1], pos); auto path = state.forceStringNoCtx(*args[1], pos);
#if 0
// FIXME: checkSourcePath? // FIXME: checkSourcePath?
v.mkPath(state.findFile(searchPath, path, pos)); v.mkPath(state.findFile(searchPath, path, pos));
#endif
abort();
} }
static RegisterPrimOp primop_findFile(RegisterPrimOp::Info { static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {
@ -1563,7 +1570,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
{ {
auto path = realisePath(state, pos, *args[0]); auto path = realisePath(state, pos, *args[0]);
auto entries = path.accessor->readDirectory(path.path); auto entries = path.readDirectory();
auto attrs = state.buildBindings(entries.size()); auto attrs = state.buildBindings(entries.size());
for (auto & [name, type] : entries) { for (auto & [name, type] : entries) {
@ -1881,7 +1888,7 @@ static RegisterPrimOp primop_toFile({
static void addPath( static void addPath(
EvalState & state, EvalState & state,
const Pos & pos, const Pos & pos,
const std::string & name, std::string_view name,
Path path, Path path,
Value * filterFun, Value * filterFun,
FileIngestionMethod method, FileIngestionMethod method,
@ -1959,7 +1966,7 @@ static void addPath(
static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
PathSet context; PathSet context;
Path path = state.coerceToPath(pos, *args[1], context); auto path = state.coerceToPath(pos, *args[1], context);
state.forceValue(*args[0], pos); state.forceValue(*args[0], pos);
if (args[0]->type() != nFunction) if (args[0]->type() != nFunction)
@ -1970,7 +1977,8 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
.errPos = pos .errPos = pos
}); });
addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context); // FIXME: use SourcePath
addPath(state, pos, path.baseName(), path.path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context);
} }
static RegisterPrimOp primop_filterSource({ static RegisterPrimOp primop_filterSource({
@ -2031,7 +2039,7 @@ static RegisterPrimOp primop_filterSource({
static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
Path path; std::optional<SourcePath> path;
std::string name; std::string name;
Value * filterFun = nullptr; Value * filterFun = nullptr;
auto method = FileIngestionMethod::Recursive; auto method = FileIngestionMethod::Recursive;
@ -2041,7 +2049,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
for (auto & attr : *args[0]->attrs) { for (auto & attr : *args[0]->attrs) {
auto & n(attr.name); auto & n(attr.name);
if (n == "path") if (n == "path")
path = state.coerceToPath(*attr.pos, *attr.value, context); path.emplace(state.coerceToPath(*attr.pos, *attr.value, context));
else if (attr.name == state.sName) else if (attr.name == state.sName)
name = state.forceStringNoCtx(*attr.value, *attr.pos); name = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (n == "filter") { else if (n == "filter") {
@ -2057,15 +2065,16 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
.errPos = *attr.pos .errPos = *attr.pos
}); });
} }
if (path.empty()) if (!path)
throw EvalError({ throw EvalError({
.msg = hintfmt("'path' required"), .msg = hintfmt("'path' required"),
.errPos = pos .errPos = pos
}); });
if (name.empty()) if (name.empty())
name = baseNameOf(path); name = path->baseName();
addPath(state, pos, name, path, filterFun, method, expectedHash, v, context); // FIXME: use SourcePath
addPath(state, pos, name, path->path, filterFun, method, expectedHash, v, context);
} }
static RegisterPrimOp primop_path({ static RegisterPrimOp primop_path({

View file

@ -30,7 +30,7 @@ void emitTreeAttrs(
attrs.alloc(state.sOutPath).mkString(storePath, {storePath}); attrs.alloc(state.sOutPath).mkString(storePath, {storePath});
#endif #endif
attrs.alloc(state.sOutPath).mkPath(state.packPath(path)); attrs.alloc(state.sOutPath).mkPath(path);
// FIXME: support arbitrary input attributes. // FIXME: support arbitrary input attributes.
@ -138,8 +138,8 @@ static void fetchTree(
for (auto elem : attr.value->listItems()) { for (auto elem : attr.value->listItems()) {
// FIXME: use realisePath // FIXME: use realisePath
PathSet context; PathSet context;
auto patchFile = state.unpackPath(state.coerceToPath(pos, *elem, context)); auto patchFile = state.coerceToPath(pos, *elem, context);
patches.push_back(patchFile.accessor->readFile(patchFile.path)); patches.push_back(patchFile.readFile());
} }
continue; continue;
@ -201,7 +201,7 @@ static void fetchTree(
emitTreeAttrs( emitTreeAttrs(
state, state,
{accessor, "/"}, {state.registerAccessor(accessor), "/"},
input2, input2,
v, v,
params.emptyRevFallback, params.emptyRevFallback,

View file

@ -32,7 +32,8 @@ void printValueAsJSON(EvalState & state, bool strict,
break; break;
case nPath: case nPath:
out.write(state.copyPathToStore(context, v.path)); // FIXME: handle accessors
out.write(state.copyPathToStore(context, v.path().path));
break; break;
case nNull: case nNull:

View file

@ -77,7 +77,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
break; break;
case nPath: case nPath:
doc.writeEmptyElement("path", singletonAttrs("value", v.path)); doc.writeEmptyElement("path", singletonAttrs("value", v.path().to_string()));
break; break;
case nNull: case nNull:

View file

@ -3,6 +3,7 @@
#include <cassert> #include <cassert>
#include "symbol-table.hh" #include "symbol-table.hh"
#include "input-accessor.hh"
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
#include <gc/gc_allocator.h> #include <gc/gc_allocator.h>
@ -170,7 +171,11 @@ public:
const char * * context; // must be in sorted order const char * * context; // must be in sorted order
} string; } string;
struct {
InputAccessor * accessor;
const char * path; const char * path;
} _path;
Bindings * attrs; Bindings * attrs;
struct { struct {
size_t size; size_t size;
@ -255,14 +260,7 @@ public:
mkString(((const std::string &) s).c_str()); mkString(((const std::string &) s).c_str());
} }
inline void mkPath(const char * s) void mkPath(const SourcePath & path);
{
clearValue();
internalType = tPath;
path = s;
}
void mkPath(std::string_view s);
inline void mkNull() inline void mkNull()
{ {
@ -404,6 +402,12 @@ public:
auto begin = listElems(); auto begin = listElems();
return ConstListIterable { begin, begin + listSize() }; return ConstListIterable { begin, begin + listSize() };
} }
SourcePath path() const
{
assert(internalType == tPath);
return SourcePath { .accessor = *_path.accessor, .path = _path.path };
}
}; };

View file

@ -216,9 +216,14 @@ ref<FSInputAccessor> makeFSInputAccessor(
return make_ref<FSInputAccessorImpl>(root, std::move(allowedPaths)); return make_ref<FSInputAccessorImpl>(root, std::move(allowedPaths));
} }
std::string SourcePath::to_string() const
{
return path; // FIXME
}
std::ostream & operator << (std::ostream & str, const SourcePath & path) std::ostream & operator << (std::ostream & str, const SourcePath & path)
{ {
str << path.path; // FIXME str << path.to_string();
return str; return str;
} }

View file

@ -72,16 +72,26 @@ ref<InputAccessor> makePatchingInputAccessor(
struct SourcePath struct SourcePath
{ {
ref<InputAccessor> accessor; InputAccessor & accessor;
Path path; Path path;
std::string_view baseName() const; std::string_view baseName() const;
std::string readFile() const std::string readFile() const
{ return accessor->readFile(path); } { return accessor.readFile(path); }
bool pathExists() const bool pathExists() const
{ return accessor->pathExists(path); } { return accessor.pathExists(path); }
InputAccessor::DirEntries readDirectory() const
{ return accessor.readDirectory(path); }
void dumpPath(
Sink & sink,
PathFilter & filter = defaultPathFilter) const
{ return accessor.dumpPath(path, sink, filter); }
std::string to_string() const;
}; };
std::ostream & operator << (std::ostream & str, const SourcePath & path); std::ostream & operator << (std::ostream & str, const SourcePath & path);

View file

@ -452,9 +452,7 @@ struct CmdFlakeCheck : FlakeCommand
if (auto attr = v.attrs->get(state->symbols.create("path"))) { if (auto attr = v.attrs->get(state->symbols.create("path"))) {
if (attr->name == state->symbols.create("path")) { if (attr->name == state->symbols.create("path")) {
PathSet context; PathSet context;
auto path = state->coerceToPath(*attr->pos, *attr->value, context); state->coerceToStorePath(*attr->pos, *attr->value, context);
if (!store->isInStore(path))
throw Error("template '%s' has a bad 'path' attribute");
// TODO: recursively check the flake in 'path'. // TODO: recursively check the flake in 'path'.
} }
} else } else

View file

@ -178,6 +178,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
#include "generate-manpage.nix.gen.hh" #include "generate-manpage.nix.gen.hh"
, "/"), *vGenerateManpage); , "/"), *vGenerateManpage);
// FIXME: use MemoryAccessor
auto vUtils = state.allocValue(); auto vUtils = state.allocValue();
state.cacheFile( state.cacheFile(
"/utils.nix", "/utils.nix", "/utils.nix", "/utils.nix",

View file

@ -772,7 +772,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
break; break;
case nPath: case nPath:
str << ANSI_GREEN << v.path << ANSI_NORMAL; // !!! escaping? str << ANSI_GREEN << v.path().path << ANSI_NORMAL; // !!! escaping?
break; break;
case nNull: case nNull: