Fix findFile(), coerceToPath()

This commit is contained in:
Eelco Dolstra 2022-05-10 16:12:48 +02:00
parent e7f8aa8bdd
commit b4c6adfd35
13 changed files with 92 additions and 80 deletions

View file

@ -89,17 +89,18 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
return res.finish(); return res.finish();
} }
Path lookupFileArg(EvalState & state, std::string_view s) SourcePath lookupFileArg(EvalState & state, std::string_view s)
{ {
if (isUri(s)) { if (isUri(s)) {
return state.store->toRealPath( auto storePath = fetchers::downloadTarball(
fetchers::downloadTarball( state.store, resolveUri(s), "source", false).first.storePath;
state.store, resolveUri(s), "source", false).first.storePath); auto & accessor = state.registerAccessor(makeFSInputAccessor(state.store->toRealPath(storePath)));
return {accessor, "/"};
} else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { } else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
Path p(s.substr(1, s.size() - 2)); Path p(s.substr(1, s.size() - 2));
return state.findFile(p); return state.findFile(p);
} else } else
return absPath(std::string(s)); return state.rootPath(absPath(std::string(s)));
} }
} }

View file

@ -7,6 +7,7 @@ namespace nix {
class Store; class Store;
class EvalState; class EvalState;
class Bindings; class Bindings;
struct SourcePath;
struct MixEvalArgs : virtual Args struct MixEvalArgs : virtual Args
{ {
@ -22,6 +23,6 @@ private:
std::map<std::string, std::string> autoArgs; std::map<std::string, std::string> autoArgs;
}; };
Path lookupFileArg(EvalState & state, std::string_view s); SourcePath lookupFileArg(EvalState & state, std::string_view s);
} }

View file

@ -210,8 +210,7 @@ void SourceExprCommand::completeInstallable(std::string_view prefix)
Expr *e = Expr *e =
state->parseExprFromFile( state->parseExprFromFile(
resolveExprPath( resolveExprPath(
state->rootPath( lookupFileArg(*state, *file)));
lookupFileArg(*state, *file))));
Value root; Value root;
state->eval(e, root); state->eval(e, root);
@ -762,7 +761,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
state->eval(e, *vFile); state->eval(e, *vFile);
} }
else if (file) else if (file)
state->evalFile(state->rootPath(lookupFileArg(*state, *file)), *vFile); state->evalFile(lookupFileArg(*state, *file), *vFile);
else { else {
auto e = state->parseExprFromString(*expr, absPath(".")); auto e = state->parseExprFromString(*expr, absPath("."));
state->eval(e, *vFile); state->eval(e, *vFile);

View file

@ -485,22 +485,22 @@ EvalState::EvalState(
if (rootFS->hasAccessControl()) { if (rootFS->hasAccessControl()) {
for (auto & i : searchPath) { for (auto & i : searchPath) {
auto r = resolveSearchPathElem(i); if (auto path = resolveSearchPathElem(i)) {
if (!r.first) continue; // FIXME
#if 0
auto path = r.second; if (store->isInStore(*path)) {
try {
if (store->isInStore(r.second)) { StorePathSet closure;
try { store->computeFSClosure(store->toStorePath(*path).first, closure);
StorePathSet closure; for (auto & p : closure)
store->computeFSClosure(store->toStorePath(r.second).first, closure); allowPath(p);
for (auto & path : closure) } catch (InvalidPath &) {
allowPath(path); allowPath(*r);
} catch (InvalidPath &) { }
allowPath(r.second); } else
} allowPath(*r);
} else #endif
allowPath(r.second); }
} }
} }
@ -1812,10 +1812,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
state.throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp)); state.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 auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString);
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(); sSize += part->size();
s.emplace_back(std::move(part)); s.emplace_back(std::move(part));
} }
@ -2017,7 +2014,7 @@ std::optional<std::string> EvalState::tryAttrsToString(const PosIdx pos, Value &
} }
BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet & context, BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore, bool canonicalizePath) bool coerceMore, bool copyToStore)
{ {
forceValue(v, pos); forceValue(v, pos);
@ -2105,11 +2102,28 @@ StorePath EvalState::copyPathToStore(PathSet & context, const SourcePath & path)
SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context) SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context)
{ {
auto path = coerceToString(pos, v, context, false, false).toOwned(); forceValue(v, pos);
if (path == "" || path[0] != '/')
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path); if (v.type() == nString) {
// FIXME copyContext(v, context);
return rootPath(path); return {*rootFS, v.string.s};
}
if (v.type() == nPath)
return v.path();
#if 0
if (v.type() == nAttrs) {
auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
if (maybeString)
return std::move(*maybeString);
auto i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
}
#endif
throwTypeError(pos, "cannot coerce %1% to a path", v);
} }

View file

@ -50,14 +50,15 @@ struct Env
void copyContext(const Value & v, PathSet & context); void copyContext(const Value & v, PathSet & context);
std::ostream & printValue(const EvalState & state, std::ostream & str, const Value & v); // FIXME: maybe change this to an std::variant<SourcePath, URL>.
std::string printValue(const EvalState & state, const Value & v);
typedef std::pair<std::string, std::string> SearchPathElem; typedef std::pair<std::string, std::string> SearchPathElem;
typedef std::list<SearchPathElem> SearchPath; typedef std::list<SearchPathElem> SearchPath;
std::ostream & printValue(const EvalState & state, std::ostream & str, const Value & v);
std::string printValue(const EvalState & state, const Value & v);
/* Initialise the Boehm GC, if applicable. */ /* Initialise the Boehm GC, if applicable. */
void initGC(); void initGC();
@ -130,7 +131,7 @@ private:
SearchPath searchPath; SearchPath searchPath;
std::map<std::string, std::pair<bool, std::string>> searchPathResolved; std::map<std::string, std::optional<SourcePath>> searchPathResolved;
/* Cache used by checkSourcePath(). */ /* Cache used by checkSourcePath(). */
std::unordered_map<Path, Path> resolvedPaths; std::unordered_map<Path, Path> resolvedPaths;
@ -209,11 +210,11 @@ public:
void resetFileCache(); void resetFileCache();
/* Look up a file in the search path. */ /* Look up a file in the search path. */
Path findFile(const std::string_view path); SourcePath findFile(const std::string_view path);
Path findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos); SourcePath findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
/* If the specified search path element is a URI, download it. */ /* If the specified search path element is a URI, download it. */
std::pair<bool, std::string> resolveSearchPathElem(const SearchPathElem & elem); std::optional<SourcePath> resolveSearchPathElem(const SearchPathElem & elem);
/* Evaluate an expression to normal form, storing the result in /* Evaluate an expression to normal form, storing the result in
value `v'. */ value `v'. */
@ -303,8 +304,7 @@ public:
booleans and lists to a string. If `copyToStore' is set, booleans and lists to a string. If `copyToStore' is set,
referenced paths are copied to the Nix store as a side effect. */ referenced paths are copied to the Nix store as a side effect. */
BackedStringView coerceToString(const PosIdx pos, Value & v, PathSet & context, BackedStringView coerceToString(const PosIdx pos, Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true, bool coerceMore = false, bool copyToStore = true);
bool canonicalizePath = true);
StorePath copyPathToStore(PathSet & context, const SourcePath & path); StorePath copyPathToStore(PathSet & context, const SourcePath & path);

View file

@ -268,7 +268,7 @@ static Flake readFlake(
PathSet emptyContext = {}; PathSet emptyContext = {};
flake.config.settings.emplace( flake.config.settings.emplace(
state.symbols[setting.name], state.symbols[setting.name],
state.coerceToString(setting.pos, *setting.value, emptyContext, false, true, true) .toOwned()); state.coerceToString(setting.pos, *setting.value, emptyContext, false, true).toOwned());
} }
else if (setting.value->type() == nInt) else if (setting.value->type() == nInt)
flake.config.settings.emplace( flake.config.settings.emplace(

View file

@ -759,13 +759,13 @@ void EvalState::addToSearchPath(const std::string & s)
} }
Path EvalState::findFile(const std::string_view path) SourcePath EvalState::findFile(const std::string_view path)
{ {
return findFile(searchPath, path); return findFile(searchPath, path);
} }
Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos) SourcePath EvalState::findFile(SearchPath & searchPath, const std::string_view path, const PosIdx pos)
{ {
for (auto & i : searchPath) { for (auto & i : searchPath) {
std::string suffix; std::string suffix;
@ -778,15 +778,14 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c
continue; continue;
suffix = path.size() == s ? "" : concatStrings("/", path.substr(s)); suffix = path.size() == s ? "" : concatStrings("/", path.substr(s));
} }
auto r = resolveSearchPathElem(i); if (auto path = resolveSearchPathElem(i)) {
if (!r.first) continue; auto res = path->append("/" + suffix);
Path res = r.second + suffix; if (res.pathExists()) return res;
if (pathExists(res)) return canonPath(res); }
} }
if (hasPrefix(path, "nix/")) if (hasPrefix(path, "nix/"))
abort(); return {*corepkgsFS, (std::string) path.substr(3)};
//return packPath(SourcePath {corepkgsFS, (std::string) path.substr(3)});
throw ThrownError({ throw ThrownError({
.msg = hintfmt(evalSettings.pureEval .msg = hintfmt(evalSettings.pureEval
@ -798,38 +797,39 @@ Path EvalState::findFile(SearchPath & searchPath, const std::string_view path, c
} }
std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathElem & elem) std::optional<SourcePath> EvalState::resolveSearchPathElem(const SearchPathElem & elem)
{ {
auto i = searchPathResolved.find(elem.second); auto i = searchPathResolved.find(elem.second);
if (i != searchPathResolved.end()) return i->second; if (i != searchPathResolved.end()) return i->second;
std::pair<bool, std::string> res; std::optional<SourcePath> res;
if (isUri(elem.second)) { if (isUri(elem.second)) {
try { try {
res = { true, store->toRealPath(fetchers::downloadTarball( auto storePath = fetchers::downloadTarball(
store, resolveUri(elem.second), "source", false).first.storePath) }; store, resolveUri(elem.second), "source", false).first.storePath;
auto & accessor = registerAccessor(makeFSInputAccessor(store->toRealPath(storePath)));
res.emplace(SourcePath {accessor, "/"});
} catch (FileTransferError & e) { } catch (FileTransferError & e) {
logWarning({ logWarning({
.msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", elem.second) .msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", elem.second)
}); });
res = { false, "" };
} }
} else { } else {
auto path = absPath(elem.second); auto path = rootPath(absPath(elem.second));
if (pathExists(path)) if (path.pathExists())
res = { true, path }; res.emplace(path);
else { else {
logWarning({ logWarning({
.msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", elem.second) .msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", elem.second)
}); });
res = { false, "" };
} }
} }
debug(format("resolved search path element '%s' to '%s'") % elem.second % res.second); if (res)
debug("resolved search path element '%s' to '%s'", elem.second, *res);
searchPathResolved[elem.second] = res; searchPathResolved.emplace(elem.second, res);
return res; return res;
} }

View file

@ -113,6 +113,7 @@ static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, co
}(); }();
try { try {
#if 0
if (!context.empty()) { if (!context.empty()) {
auto rewrites = state.realiseContext(context); auto rewrites = state.realiseContext(context);
// FIXME: check that path.accessor == rootFS? // FIXME: check that path.accessor == rootFS?
@ -120,6 +121,7 @@ static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, co
// FIXME: return store accessor // FIXME: return store accessor
return state.rootPath(realPath); return state.rootPath(realPath);
} else } else
#endif
return path; return path;
} catch (Error & e) { } catch (Error & e) {
e.addTrace(state.positions[pos], "while realising the context of path '%s'", path); e.addTrace(state.positions[pos], "while realising the context of path '%s'", path);
@ -1545,12 +1547,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V
auto path = state.forceStringNoCtx(*args[1], pos); auto path = state.forceStringNoCtx(*args[1], pos);
#if 0
// FIXME: checkSourcePath?
v.mkPath(state.findFile(searchPath, path, pos)); v.mkPath(state.findFile(searchPath, path, pos));
#endif
throw ThrownError("findFile('%s'): not implemented", path);
} }
static RegisterPrimOp primop_findFile(RegisterPrimOp::Info { static RegisterPrimOp primop_findFile(RegisterPrimOp::Info {

View file

@ -307,9 +307,8 @@ static void main_nix_build(int argc, char * * argv)
exprs.push_back( exprs.push_back(
state->parseExprFromFile( state->parseExprFromFile(
resolveExprPath( resolveExprPath(
state->rootPath( lookupFileArg(*state,
lookupFileArg(*state, inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i))));
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
} }
} }

View file

@ -1475,7 +1475,9 @@ static int main_nix_env(int argc, char * * argv)
globals.state->repair = repair; globals.state->repair = repair;
if (file != "") if (file != "")
globals.instSource.nixExprPath = lookupFileArg(*globals.state, file); // FIXME: check that the accessor returned by
// lookupFileArg() is the root FS.
globals.instSource.nixExprPath = lookupFileArg(*globals.state, file).path;
globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state); globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state);

View file

@ -167,9 +167,8 @@ static int main_nix_instantiate(int argc, char * * argv)
if (findFile) { if (findFile) {
for (auto & i : files) { for (auto & i : files) {
Path p = state->findFile(i); auto p = state->findFile(i);
if (p == "") throw Error("unable to find '%1%'", i); std::cout << p.readFile() << std::endl;
std::cout << p << std::endl;
} }
return 0; return 0;
} }
@ -184,7 +183,7 @@ static int main_nix_instantiate(int argc, char * * argv)
for (auto & i : files) { for (auto & i : files) {
Expr * e = fromArgs Expr * e = fromArgs
? state->parseExprFromString(i, absPath(".")) ? state->parseExprFromString(i, absPath("."))
: state->parseExprFromFile(resolveExprPath(state->rootPath(lookupFileArg(*state, i)))); : state->parseExprFromFile(resolveExprPath(lookupFileArg(*state, i)));
processExpr(*state, attrPaths, parseOnly, strict, autoArgs, processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
evalOnly, outputKind, xmlOutputSourceLocation, e); evalOnly, outputKind, xmlOutputSourceLocation, e);
} }

View file

@ -195,7 +195,7 @@ static int main_nix_prefetch_url(int argc, char * * argv)
Value vRoot; Value vRoot;
state->evalFile( state->evalFile(
resolveExprPath( resolveExprPath(
state->rootPath(lookupFileArg(*state, args.empty() ? "." : args[0]))), lookupFileArg(*state, args.empty() ? "." : args[0])),
vRoot); vRoot);
Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first); Value & v(*findAlongAttrPath(*state, attrPath, autoArgs, vRoot).first);
state->forceAttrs(v, noPos); state->forceAttrs(v, noPos);

View file

@ -636,7 +636,7 @@ void NixRepl::loadFile(const Path & path)
loadedFiles.remove(path); loadedFiles.remove(path);
loadedFiles.push_back(path); loadedFiles.push_back(path);
Value v, v2; Value v, v2;
state->evalFile(state->rootPath(lookupFileArg(*state, path)), v); state->evalFile(lookupFileArg(*state, path), v);
state->autoCallFunction(*autoArgs, v, v2); state->autoCallFunction(*autoArgs, v, v2);
addAttrsToScope(v2); addAttrsToScope(v2);
} }