From 1ee5dd6d96b837b0590c17973f7164bb026cffce Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 12 May 2022 18:25:36 +0200 Subject: [PATCH] Fix relative path handling in the parser --- src/libcmd/common-eval-args.cc | 2 +- src/libcmd/installables.cc | 2 +- src/libexpr/eval.hh | 13 +++++++--- src/libexpr/flake/flake.cc | 2 +- src/libexpr/nixexpr.hh | 6 ++--- src/libexpr/parser.y | 34 +++++++++++++------------- src/libexpr/primops.cc | 6 ++--- src/libfetchers/input-accessor.cc | 21 ++++++++++++---- src/libfetchers/input-accessor.hh | 7 +++++- src/nix-build/nix-build.cc | 6 +++-- src/nix-env/nix-env.cc | 2 +- src/nix-env/user-env.cc | 2 +- src/nix-instantiate/nix-instantiate.cc | 2 +- src/nix/eval.cc | 2 +- src/nix/main.cc | 2 +- src/nix/prefetch.cc | 5 +++- src/nix/repl.cc | 2 +- src/nix/upgrade-nix.cc | 2 +- 18 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 40435f710..6651b0da1 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -81,7 +81,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state) for (auto & i : autoArgs) { auto v = state.allocValue(); if (i.second[0] == 'E') - state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), absPath("."))); + state.mkThunk_(*v, state.parseExprFromString(i.second.substr(1), state.rootPath(absPath(".")))); else v->mkString(((std::string_view) i.second).substr(1)); res.insert(state.symbols.create(i.first), v); diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index acd3fbfee..b7494c222 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -766,7 +766,7 @@ std::vector> SourceExprCommand::parseInstallables( else if (file) state->evalFile(lookupFileArg(*state, *file), *vFile); else { - auto e = state->parseExprFromString(*expr, absPath(".")); + auto e = state->parseExprFromString(*expr, state->rootPath(absPath("."))); state->eval(e, *vFile); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 6d7a9cb12..7d4d870f7 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -190,8 +190,8 @@ public: 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); - Expr * parseExprFromString(std::string s, const Path & basePath); + Expr * parseExprFromString(std::string s, const SourcePath & basePath, StaticEnv & staticEnv); + Expr * parseExprFromString(std::string s, const SourcePath & basePath); Expr * parseStdin(); @@ -356,8 +356,13 @@ private: friend struct ExprAttrs; friend struct ExprLet; - Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path, - const PathView basePath, StaticEnv & staticEnv); + Expr * parse( + char * text, + size_t length, + FileOrigin origin, + const PathView path, + const SourcePath & basePath, + StaticEnv & staticEnv); public: diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index d1a4c0402..424e6ac26 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -723,7 +723,7 @@ void callFlake(EvalState & state, state.vCallFlake = allocRootValue(state.allocValue()); state.eval(state.parseExprFromString( #include "call-flake.nix.gen.hh" - , "/"), **state.vCallFlake); + , state.rootPath("/")), **state.vCallFlake); } state.callFunction(**state.vCallFlake, *vLocks, *vTmp1, noPos); diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index f9d75bf40..953e97419 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -185,10 +185,10 @@ struct ExprPath : Expr { std::string s; // FIXME: remove Value v; - ExprPath(InputAccessor & accessor, std::string s) - : s(std::move(s)) + ExprPath(SourcePath && path) + : s(path.path) { - v.mkPath({accessor, this->s}); + v.mkPath(std::move(path)); } COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 6ede0d27a..4c10d137d 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -31,14 +31,9 @@ namespace nix { EvalState & state; SymbolTable & symbols; Expr * result; - Path basePath; + SourcePath basePath; PosTable::Origin origin; std::optional error; - ParseData(EvalState & state, PosTable::Origin origin) - : state(state) - , symbols(state.symbols) - , origin(std::move(origin)) - { }; }; struct ParserFormals { @@ -513,15 +508,15 @@ string_parts_interpolated path_start : PATH { - Path path(absPath({$1.p, $1.l}, data->basePath)); + SourcePath path { data->basePath.accessor, absPath({$1.p, $1.l}, data->basePath.path) }; /* add back in the trailing '/' to the first segment */ if ($1.p[$1.l-1] == '/' && $1.l > 1) - path += "/"; - $$ = new ExprPath(*data->state.rootFS, path); + path.path += "/"; + $$ = new ExprPath(std::move(path)); } | HPATH { Path path(getHome() + std::string($1.p + 1, $1.l - 1)); - $$ = new ExprPath(*data->state.rootFS, path); + $$ = new ExprPath(data->state.rootPath(path)); } ; @@ -643,12 +638,13 @@ namespace nix { Expr * EvalState::parse(char * text, size_t length, FileOrigin origin, - const PathView path, const PathView basePath, StaticEnv & staticEnv) + const PathView path, const SourcePath & basePath, StaticEnv & staticEnv) { yyscan_t scanner; std::string file; switch (origin) { case foFile: + // FIXME: change this to a SourcePath. file = path; break; case foStdin: @@ -658,8 +654,12 @@ Expr * EvalState::parse(char * text, size_t length, FileOrigin origin, default: assert(false); } - ParseData data(*this, {file, origin}); - data.basePath = basePath; + ParseData data { + .state = *this, + .symbols = symbols, + .basePath = basePath, + .origin = {file, origin}, + }; yylex_init(&scanner); yy_scan_buffer(text, length, scanner); @@ -716,18 +716,18 @@ Expr * EvalState::parseExprFromFile(const SourcePath & path, StaticEnv & staticE // readFile hopefully have left some extra space for terminators buffer.append("\0\0", 2); // FIXME: pass SourcePaths - return parse(buffer.data(), buffer.size(), foFile, path.path, dirOf(path.path), staticEnv); + return parse(buffer.data(), buffer.size(), foFile, path.path, path.parent(), staticEnv); } -Expr * EvalState::parseExprFromString(std::string s, const Path & basePath, StaticEnv & staticEnv) +Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath, StaticEnv & staticEnv) { s.append("\0\0", 2); return parse(s.data(), s.size(), foString, "", basePath, staticEnv); } -Expr * EvalState::parseExprFromString(std::string s, const Path & basePath) +Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath) { return parseExprFromString(std::move(s), basePath, staticBaseEnv); } @@ -739,7 +739,7 @@ Expr * EvalState::parseStdin() auto buffer = drainFD(0); // drainFD should have left some extra space for terminators buffer.append("\0\0", 2); - return parse(buffer.data(), buffer.size(), foStdin, "", absPath("."), staticBaseEnv); + return parse(buffer.data(), buffer.size(), foStdin, "", rootPath(absPath(".")), staticBaseEnv); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 6a45278e6..eb973b2ec 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -375,7 +375,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) Expr * parsed; try { auto base = state.positions[pos]; - parsed = state.parseExprFromString(std::move(output), base.file); + parsed = state.parseExprFromString(std::move(output), state.rootPath(base.file)); } catch (Error & e) { e.addTrace(state.positions[pos], "While parsing the output from '%1%'", program); throw; @@ -1464,7 +1464,7 @@ static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Valu state.forceValue(*args[0], pos); if (args[0]->type() == nPath) { auto path = args[0]->path(); - v.mkPath({path.accessor, dirOf(path.path)}); + v.mkPath(path.parent()); } else { auto path = state.coerceToString(pos, *args[0], context, false, false); auto dir = dirOf(*path); @@ -3967,7 +3967,7 @@ void EvalState::createBaseEnv() // the parser needs two NUL bytes as terminators; one of them // is implied by being a C string. "\0"; - eval(parse(code, sizeof(code), foFile, derivationNixPath, "/", staticBaseEnv), *vDerivation); + eval(parse(code, sizeof(code), foFile, derivationNixPath, rootPath("/"), staticBaseEnv), *vDerivation); } diff --git a/src/libfetchers/input-accessor.cc b/src/libfetchers/input-accessor.cc index 025114515..71eebcdbf 100644 --- a/src/libfetchers/input-accessor.cc +++ b/src/libfetchers/input-accessor.cc @@ -87,6 +87,11 @@ void InputAccessor::dumpPath( dump(path); } +std::string InputAccessor::showPath(PathView path) +{ + return "/virtual/" + std::to_string(number) + path; +} + struct FSInputAccessorImpl : FSInputAccessor { Path root; @@ -210,6 +215,11 @@ struct FSInputAccessorImpl : FSInputAccessor { return (bool) allowedPaths; } + + std::string showPath(PathView path) override + { + return root + path; + } }; ref makeFSInputAccessor( @@ -219,11 +229,6 @@ 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.to_string(); @@ -286,4 +291,10 @@ std::string_view SourcePath::baseName() const return path == "" || path == "/" ? "source" : baseNameOf(path); } +SourcePath SourcePath::parent() const +{ + // FIXME: + return {accessor, dirOf(path)}; +} + } diff --git a/src/libfetchers/input-accessor.hh b/src/libfetchers/input-accessor.hh index ffa06ecd8..d7fc3f11d 100644 --- a/src/libfetchers/input-accessor.hh +++ b/src/libfetchers/input-accessor.hh @@ -52,6 +52,8 @@ struct InputAccessor { return number < x.number; } + + virtual std::string showPath(PathView path); }; struct FSInputAccessor : InputAccessor @@ -87,6 +89,8 @@ struct SourcePath std::string_view baseName() const; + SourcePath parent() const; + std::string readFile() const { return accessor.readFile(path); } @@ -104,7 +108,8 @@ struct SourcePath PathFilter & filter = defaultPathFilter) const { return accessor.dumpPath(path, sink, filter); } - std::string to_string() const; + std::string to_string() const + { return accessor.showPath(path); } SourcePath append(std::string_view s) const; diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 384a2bc76..bfe53bb5e 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -292,7 +292,7 @@ static void main_nix_build(int argc, char * * argv) else for (auto i : left) { if (fromArgs) - exprs.push_back(state->parseExprFromString(std::move(i), absPath("."))); + exprs.push_back(state->parseExprFromString(std::move(i), state->rootPath(absPath(".")))); else { auto absolute = i; try { @@ -362,7 +362,9 @@ static void main_nix_build(int argc, char * * argv) if (!shell) { try { - auto expr = state->parseExprFromString("(import {}).bashInteractive", absPath(".")); + auto expr = state->parseExprFromString( + "(import {}).bashInteractive", + state->rootPath(absPath("."))); Value v; state->eval(expr, v); diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 05f0ae20a..21464440d 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -410,7 +410,7 @@ static void queryInstSources(EvalState & state, loadSourceExpr(state, instSource.nixExprPath, vArg); for (auto & i : args) { - Expr * eFun = state.parseExprFromString(i, absPath(".")); + Expr * eFun = state.parseExprFromString(i, state.rootPath(absPath("."))); Value vFun, vTmp; state.eval(eFun, vFun); vTmp.mkApp(&vFun, &vArg); diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 0b65f1d11..d202c82d4 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -114,7 +114,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, Value envBuilder; state.eval(state.parseExprFromString( #include "buildenv.nix.gen.hh" - , "/"), envBuilder); + , state.rootPath("/")), envBuilder); /* Construct a Nix expression that calls the user environment builder with the manifest as argument. */ diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 614201bbb..261760a32 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -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->parseExprFromString(i, state->rootPath(absPath("."))) : state->parseExprFromFile(resolveExprPath(lookupFileArg(*state, i))); processExpr(*state, attrPaths, parseOnly, strict, autoArgs, evalOnly, outputKind, xmlOutputSourceLocation, e); diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 967dc8519..7f3be0127 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -65,7 +65,7 @@ struct CmdEval : MixJSON, InstallableCommand if (apply) { auto vApply = state->allocValue(); - state->eval(state->parseExprFromString(*apply, absPath(".")), *vApply); + state->eval(state->parseExprFromString(*apply, state->rootPath(absPath("."))), *vApply); auto vRes = state->allocValue(); state->callFunction(*vApply, *v, *vRes, noPos); v = vRes; diff --git a/src/nix/main.cc b/src/nix/main.cc index fe78fe6af..22bc79156 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -176,7 +176,7 @@ static void showHelp(std::vector subcommand, MultiCommand & topleve auto vGenerateManpage = state.allocValue(); state.eval(state.parseExprFromString( #include "generate-manpage.nix.gen.hh" - , "/"), *vGenerateManpage); + , state.rootPath("/")), *vGenerateManpage); state.corepkgsFS->addFile( "/utils.nix", diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc index 73d0cc23e..e983d237d 100644 --- a/src/nix/prefetch.cc +++ b/src/nix/prefetch.cc @@ -27,7 +27,10 @@ std::string resolveMirrorUrl(EvalState & state, const std::string & url) Value vMirrors; // FIXME: use nixpkgs flake - state.eval(state.parseExprFromString("import ", "."), vMirrors); + state.eval(state.parseExprFromString( + "import ", + state.rootPath(absPath("/"))), + vMirrors); state.forceAttrs(vMirrors, noPos); auto mirrorList = vMirrors.attrs->find(state.symbols.create(mirrorName)); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 9dcc9b251..c2b8449ef 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -726,7 +726,7 @@ void NixRepl::addVarToScope(const Symbol name, Value & v) Expr * NixRepl::parseString(std::string s) { - Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv); + Expr * e = state->parseExprFromString(std::move(s), state->rootPath(curDir), staticEnv); return e; } diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc index 17a5a77ee..e90034699 100644 --- a/src/nix/upgrade-nix.cc +++ b/src/nix/upgrade-nix.cc @@ -140,7 +140,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand auto state = std::make_unique(Strings(), store); auto v = state->allocValue(); - state->eval(state->parseExprFromString(res.data, "/no-such-path"), *v); + state->eval(state->parseExprFromString(res.data, state->rootPath("/no-such-path")), *v); Bindings & bindings(*state->allocBindings(0)); auto v2 = findAlongAttrPath(*state, settings.thisSystem, bindings, *v).first;