From 06c1edf8899963d7799f12bd5e90cdd7f3efb02c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 1 Mar 2022 19:08:20 +0100 Subject: [PATCH] Checkpoint --- src/libexpr/eval-cache.cc | 11 ++++-- src/libexpr/eval.cc | 66 +++++++++++++++---------------- src/libexpr/eval.hh | 11 ++---- src/libexpr/flake/flake.cc | 12 +++--- src/libexpr/flake/flake.hh | 2 +- src/libexpr/nixexpr.hh | 8 +++- src/libexpr/parser.y | 13 +++--- src/libexpr/paths.cc | 29 +++----------- src/libexpr/primops.cc | 37 ++++++++++------- src/libexpr/primops/fetchTree.cc | 8 ++-- src/libexpr/value-to-json.cc | 3 +- src/libexpr/value-to-xml.cc | 2 +- src/libexpr/value.hh | 22 ++++++----- src/libfetchers/input-accessor.cc | 7 +++- src/libfetchers/input-accessor.hh | 16 ++++++-- src/nix/flake.cc | 4 +- src/nix/main.cc | 1 + src/nix/repl.cc | 2 +- 18 files changed, 134 insertions(+), 120 deletions(-) diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 54fa9b741..73b10ea2e 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -396,8 +396,11 @@ Value & AttrCursor::forceValue() if (v.type() == nString) cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), string_t{v.string.s, {}}}; - else if (v.type() == nPath) - cachedValue = {root->db->setString(getKey(), v.path), string_t{v.path, {}}}; + else if (v.type() == nPath) { + // FIXME: take accessor into account? + auto path = v.path().path; + cachedValue = {root->db->setString(getKey(), path), string_t{path, {}}}; + } else if (v.type() == nBool) cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean}; else if (v.type() == nAttrs) @@ -537,7 +540,7 @@ std::string AttrCursor::getString() if (v.type() != nString && v.type() != nPath) 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() @@ -568,7 +571,7 @@ string_t AttrCursor::getStringWithContext() if (v.type() == nString) return {v.string.s, v.getContext(*root->state.store)}; else if (v.type() == nPath) - return {v.path, {}}; + return {v.path().to_string(), {}}; else throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 93a4b99bb..88c411bd1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -119,7 +119,7 @@ void Value::print(std::ostream & str, std::set * seen) const str << "\""; break; case tPath: - str << path; // !!! escaping? + str << path().to_string(); // !!! escaping? break; case tNull: str << "null"; @@ -721,11 +721,6 @@ std::optional EvalState::getDoc(Value & v) evaluator. So here are some helper functions for throwing 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)) { 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 + auto pathKey = path.to_string(); FileEvalCache::iterator i; - if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) { + if ((i = fileEvalCache.find(pathKey)) != fileEvalCache.end()) { v = i->second; return; } - auto resolvedPath_ = resolveExprPath(path_); - auto resolvedPath = packPath(resolvedPath_); - if ((i = fileEvalCache.find(resolvedPath)) != fileEvalCache.end()) { + auto resolvedPath = resolveExprPath(path); + auto resolvedPathKey = resolvedPath.to_string(); + if ((i = fileEvalCache.find(resolvedPathKey)) != fileEvalCache.end()) { v = i->second; return; } @@ -1003,17 +996,17 @@ void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial printTalkative("evaluating file '%1%'", resolvedPath); Expr * e = nullptr; - auto j = fileParseCache.find(resolvedPath); + auto j = fileParseCache.find(resolvedPathKey); if (j != fileParseCache.end()) e = j->second; if (!e) - e = parseExprFromFile(resolvedPath_); + e = parseExprFromFile(resolvedPath); #if 0 e = parseExprFromFile(checkSourcePath(resolvedPath)); #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)); } else { if (s.empty()) s.reserve(es->size()); - /* skip canonization of first path, which would only be not - canonized in the first place if it's coming from a ./${foo} type - path */ + /* Skip canonization of first path, which would only be + non-canonical in the first place if it's coming from a + ./${foo} type path. */ auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first); sSize += part->size(); s.emplace_back(std::move(part)); @@ -1808,7 +1801,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) else if (firstType == nPath) { if (!context.empty()) 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 v.mkStringMove(c_str(), context); } @@ -2005,11 +1998,12 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & } if (v.type() == nPath) { - BackedStringView path(PathView(v.path)); + auto path = v.path().to_string(); if (canonicalizePath) - path = canonPath(*path); + // FIXME: unnecessary? + path = canonPath(path); if (copyToStore) - path = copyPathToStore(context, std::move(path).toOwned()); + path = copyPathToStore(context, 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) { + #if 0 if (nix::isDerivation(path)) 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); #endif auto source = sinkToSource([&](Sink & sink) { - path2.accessor->dumpPath(path2.path, sink); + path2.dumpPath(sink); }); // FIXME: readOnlyMode 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); 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(); if (path == "" || path[0] != '/') 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; 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: return true; diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 17fdb71dd..2de91ec9e 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -96,7 +96,7 @@ public: ref rootFS; ref corepkgsFS; - std::unordered_map> inputAccessors; + std::unordered_map> inputAccessors; /* Store used to materialise .drv files. */ const ref store; @@ -156,11 +156,9 @@ public: SearchPath getSearchPath() { return searchPath; } - Path packPath(const SourcePath & path); + SourcePath rootPath(Path path); - SourcePath unpackPath(const Path & path); - - SourcePath rootPath(const Path & path); + InputAccessor & registerAccessor(ref accessor); /* Allow access to a path. */ void allowPath(const Path & path); @@ -274,8 +272,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); + SourcePath coerceToPath(const Pos & pos, Value & v, PathSet & context); /* Like coerceToPath, but the result must be a store path. */ StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context); diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 95548104d..f7a6bdaac 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -201,7 +201,7 @@ static std::map parseFlakeInputs( static Flake readFlake( EvalState & state, const FlakeRef & lockedRef, - nix::ref accessor, + InputAccessor & accessor, const InputPath & lockRootPath) { auto flakeDir = canonPath("/" + lockedRef.subdir); @@ -213,14 +213,14 @@ static Flake readFlake( Value vInfo; 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 { // FIXME .originalRef = lockedRef, .resolvedRef = lockedRef, .lockedRef = lockedRef, - .accessor = accessor, + .accessor = ptr(&accessor), .flakePath = dirOf(flakePath.path), }; @@ -308,7 +308,7 @@ static Flake getFlake( // FIXME: resolve 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) @@ -324,7 +324,7 @@ Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup 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() ? LockFile(lockFilePath.readFile(), fmt("%s", lockFilePath)) : LockFile(); @@ -703,7 +703,7 @@ void callFlake(EvalState & state, emitTreeAttrs( state, - {lockedFlake.flake.accessor, lockedFlake.flake.flakePath}, + {*lockedFlake.flake.accessor, lockedFlake.flake.flakePath}, lockedFlake.flake.lockedRef.input, *vRootSrc, false, diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh index 04a0099f5..96616b40b 100644 --- a/src/libexpr/flake/flake.hh +++ b/src/libexpr/flake/flake.hh @@ -61,7 +61,7 @@ struct Flake FlakeRef originalRef; // the original flake specification (by the user) FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake FlakeRef lockedRef; // the specific local store result of invoking the fetcher - ref accessor; + ptr accessor; Path flakePath; bool forceDirty = false; // pretend that 'lockedRef' is dirty std::optional description; diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 4dbe31510..ebfeb1f74 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -121,9 +121,13 @@ struct ExprString : Expr struct ExprPath : Expr { - std::string s; + std::string s; // FIXME: remove 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 Value * maybeThunk(EvalState & state, Env & env); }; diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 3258327a0..ee08b1f3e 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -517,11 +517,11 @@ path_start /* add back in the trailing '/' to the first segment */ if ($1.p[$1.l-1] == '/' && $1.l > 1) path += "/"; - $$ = new ExprPath(path); + $$ = new ExprPath(*data->state.rootFS, path); } | HPATH { 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 auto path2 = path.path + "/default.nix"; - if (path.accessor->pathExists(path2)) + if (path.pathExists()) return {path.accessor, path2}; return path; @@ -715,11 +715,11 @@ Expr * EvalState::parseExprFromFile(const SourcePath & path) Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticEnv) { - auto packed = packPath(path); auto buffer = path.readFile(); // readFile hopefully have left some extra space for terminators 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/")) - return packPath(SourcePath {corepkgsFS, (std::string) path.substr(3)}); + abort(); + //return packPath(SourcePath {corepkgsFS, (std::string) path.substr(3)}); throw ThrownError({ .msg = hintfmt(evalSettings.pureEval diff --git a/src/libexpr/paths.cc b/src/libexpr/paths.cc index 16f747586..950c2b41b 100644 --- a/src/libexpr/paths.cc +++ b/src/libexpr/paths.cc @@ -3,34 +3,15 @@ namespace nix { -static constexpr std::string_view marker = "/__virtual/"; - -Path EvalState::packPath(const SourcePath & path) +SourcePath EvalState::rootPath(Path path) { - // FIXME: canonPath(path) ? - assert(hasPrefix(path.path, "/")); - inputAccessors.emplace(path.accessor->number, path.accessor); - return std::string(marker) + std::to_string(path.accessor->number) + path.path; + return {*rootFS, std::move(path)}; } -SourcePath EvalState::unpackPath(const Path & path) +InputAccessor & EvalState::registerAccessor(ref accessor) { - if (hasPrefix(path, marker)) { - auto s = path.substr(marker.size()); - 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}; + inputAccessors.emplace(&*accessor, accessor); + return *accessor; } } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index f50c2dca3..26a4a4dcd 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -104,7 +104,7 @@ static SourcePath realisePath(EvalState & state, const Pos & pos, Value & v, con auto path = [&]() { try { - return state.unpackPath(state.coerceToPath(pos, v, context)); + return state.coerceToPath(pos, v, context); } catch (Error & e) { e.addTrace(pos, "while realising the context of a path"); throw; @@ -557,7 +557,8 @@ struct CompareValues case nString: return strcmp(v1->string.s, v2->string.s) < 0; case nPath: - return strcmp(v1->path, v2->path) < 0; + // FIXME: handle accessor? + return strcmp(v1->_path.path, v2->_path.path) < 0; case nList: // Lexicographic comparison 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) { PathSet context; - Path path = state.coerceToPath(pos, *args[0], context); - v.mkString(canonPath(path), context); + auto path = state.coerceToPath(pos, *args[0], context); + v.mkString(canonPath(path.path), context); } static RegisterPrimOp primop_toPath({ @@ -1347,7 +1348,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V PathSet context; // 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 directly in the store. The latter condition is necessary so 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; auto path = state.coerceToString(pos, *args[0], context, false, false); auto dir = dirOf(*path); + abort(); + #if 0 if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context); + #endif } 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); + #if 0 // FIXME: checkSourcePath? v.mkPath(state.findFile(searchPath, path, pos)); + #endif + abort(); } 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 entries = path.accessor->readDirectory(path.path); + auto entries = path.readDirectory(); auto attrs = state.buildBindings(entries.size()); for (auto & [name, type] : entries) { @@ -1881,7 +1888,7 @@ static RegisterPrimOp primop_toFile({ static void addPath( EvalState & state, const Pos & pos, - const std::string & name, + std::string_view name, Path path, Value * filterFun, FileIngestionMethod method, @@ -1959,7 +1966,7 @@ static void addPath( static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v) { PathSet context; - Path path = state.coerceToPath(pos, *args[1], context); + auto path = state.coerceToPath(pos, *args[1], context); state.forceValue(*args[0], pos); if (args[0]->type() != nFunction) @@ -1970,7 +1977,8 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args .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({ @@ -2031,7 +2039,7 @@ static RegisterPrimOp primop_filterSource({ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceAttrs(*args[0], pos); - Path path; + std::optional path; std::string name; Value * filterFun = nullptr; 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) { auto & n(attr.name); 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) name = state.forceStringNoCtx(*attr.value, *attr.pos); else if (n == "filter") { @@ -2057,15 +2065,16 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value .errPos = *attr.pos }); } - if (path.empty()) + if (!path) throw EvalError({ .msg = hintfmt("'path' required"), .errPos = pos }); 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({ diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index b9eabea3e..cc06f6495 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -30,7 +30,7 @@ void emitTreeAttrs( attrs.alloc(state.sOutPath).mkString(storePath, {storePath}); #endif - attrs.alloc(state.sOutPath).mkPath(state.packPath(path)); + attrs.alloc(state.sOutPath).mkPath(path); // FIXME: support arbitrary input attributes. @@ -138,8 +138,8 @@ static void fetchTree( for (auto elem : attr.value->listItems()) { // FIXME: use realisePath PathSet context; - auto patchFile = state.unpackPath(state.coerceToPath(pos, *elem, context)); - patches.push_back(patchFile.accessor->readFile(patchFile.path)); + auto patchFile = state.coerceToPath(pos, *elem, context); + patches.push_back(patchFile.readFile()); } continue; @@ -201,7 +201,7 @@ static void fetchTree( emitTreeAttrs( state, - {accessor, "/"}, + {state.registerAccessor(accessor), "/"}, input2, v, params.emptyRevFallback, diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 517da4c01..ea5ee2a0d 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -32,7 +32,8 @@ void printValueAsJSON(EvalState & state, bool strict, break; case nPath: - out.write(state.copyPathToStore(context, v.path)); + // FIXME: handle accessors + out.write(state.copyPathToStore(context, v.path().path)); break; case nNull: diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index afeaf5694..20de52233 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -77,7 +77,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, break; case nPath: - doc.writeEmptyElement("path", singletonAttrs("value", v.path)); + doc.writeEmptyElement("path", singletonAttrs("value", v.path().to_string())); break; case nNull: diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 3d07c3198..9de0ece68 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -3,6 +3,7 @@ #include #include "symbol-table.hh" +#include "input-accessor.hh" #if HAVE_BOEHMGC #include @@ -170,7 +171,11 @@ public: const char * * context; // must be in sorted order } string; - const char * path; + struct { + InputAccessor * accessor; + const char * path; + } _path; + Bindings * attrs; struct { size_t size; @@ -255,14 +260,7 @@ public: mkString(((const std::string &) s).c_str()); } - inline void mkPath(const char * s) - { - clearValue(); - internalType = tPath; - path = s; - } - - void mkPath(std::string_view s); + void mkPath(const SourcePath & path); inline void mkNull() { @@ -404,6 +402,12 @@ public: auto begin = listElems(); return ConstListIterable { begin, begin + listSize() }; } + + SourcePath path() const + { + assert(internalType == tPath); + return SourcePath { .accessor = *_path.accessor, .path = _path.path }; + } }; diff --git a/src/libfetchers/input-accessor.cc b/src/libfetchers/input-accessor.cc index cf631be10..10a275857 100644 --- a/src/libfetchers/input-accessor.cc +++ b/src/libfetchers/input-accessor.cc @@ -216,9 +216,14 @@ ref makeFSInputAccessor( return make_ref(root, std::move(allowedPaths)); } +std::string SourcePath::to_string() const +{ + return path; // FIXME +} + std::ostream & operator << (std::ostream & str, const SourcePath & path) { - str << path.path; // FIXME + str << path.to_string(); return str; } diff --git a/src/libfetchers/input-accessor.hh b/src/libfetchers/input-accessor.hh index f14312026..129c1f345 100644 --- a/src/libfetchers/input-accessor.hh +++ b/src/libfetchers/input-accessor.hh @@ -72,16 +72,26 @@ ref makePatchingInputAccessor( struct SourcePath { - ref accessor; + InputAccessor & accessor; Path path; std::string_view baseName() const; std::string readFile() const - { return accessor->readFile(path); } + { return accessor.readFile(path); } 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); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 66e8295ad..f6ce12b4e 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -452,9 +452,7 @@ struct CmdFlakeCheck : FlakeCommand if (auto attr = v.attrs->get(state->symbols.create("path"))) { if (attr->name == state->symbols.create("path")) { PathSet context; - auto path = state->coerceToPath(*attr->pos, *attr->value, context); - if (!store->isInStore(path)) - throw Error("template '%s' has a bad 'path' attribute"); + state->coerceToStorePath(*attr->pos, *attr->value, context); // TODO: recursively check the flake in 'path'. } } else diff --git a/src/nix/main.cc b/src/nix/main.cc index 6198681e7..9db3e3494 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -178,6 +178,7 @@ static void showHelp(std::vector subcommand, MultiCommand & topleve #include "generate-manpage.nix.gen.hh" , "/"), *vGenerateManpage); + // FIXME: use MemoryAccessor auto vUtils = state.allocValue(); state.cacheFile( "/utils.nix", "/utils.nix", diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 5ad85691b..17bfe2dde 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -772,7 +772,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; case nPath: - str << ANSI_GREEN << v.path << ANSI_NORMAL; // !!! escaping? + str << ANSI_GREEN << v.path().path << ANSI_NORMAL; // !!! escaping? break; case nNull: