Skip to content

Commit

Permalink
Backport SourcePath from the lazy-trees branch
Browse files Browse the repository at this point in the history
This introduces the SourcePath type from lazy-trees as an abstraction
for accessing files from inputs that may not be materialized in the
real filesystem (e.g. Git repositories). Currently, however, it's just
a wrapper around CanonPath, so it shouldn't change any behaviour. (On
lazy-trees, SourcePath is a <InputAccessor, CanonPath> tuple.)
  • Loading branch information
edolstra committed Apr 6, 2023
1 parent 5256ba6 commit 94812cc
Show file tree
Hide file tree
Showing 35 changed files with 568 additions and 264 deletions.
10 changes: 5 additions & 5 deletions src/libcmd/common-eval-args.cc
Expand Up @@ -153,27 +153,27 @@ 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(CanonPath::fromCwd())));
else
v->mkString(((std::string_view) i.second).substr(1));
res.insert(state.symbols.create(i.first), v);
}
return res.finish();
}

Path lookupFileArg(EvalState & state, std::string_view s)
SourcePath lookupFileArg(EvalState & state, std::string_view s)
{
if (EvalSettings::isPseudoUrl(s)) {
auto storePath = fetchers::downloadTarball(
state.store, EvalSettings::resolvePseudoUrl(s), "source", false).first.storePath;
return state.store->toRealPath(storePath);
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
}

else if (hasPrefix(s, "flake:")) {
experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(std::string(s.substr(6)), {}, true, false);
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
return state.store->toRealPath(storePath);
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
}

else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
Expand All @@ -182,7 +182,7 @@ Path lookupFileArg(EvalState & state, std::string_view s)
}

else
return absPath(std::string(s));
return state.rootPath(CanonPath::fromCwd(s));
}

}
3 changes: 2 additions & 1 deletion src/libcmd/common-eval-args.hh
Expand Up @@ -8,6 +8,7 @@ namespace nix {
class Store;
class EvalState;
class Bindings;
struct SourcePath;

struct MixEvalArgs : virtual Args
{
Expand All @@ -25,6 +26,6 @@ private:
std::map<std::string, std::string> autoArgs;
};

Path lookupFileArg(EvalState & state, std::string_view s);
SourcePath lookupFileArg(EvalState & state, std::string_view s);

}
7 changes: 5 additions & 2 deletions src/libcmd/editor-for.cc
Expand Up @@ -3,8 +3,11 @@

namespace nix {

Strings editorFor(const Path & file, uint32_t line)
Strings editorFor(const SourcePath & file, uint32_t line)
{
auto path = file.getPhysicalPath();
if (!path)
throw Error("cannot open '%s' in an editor because it has no physical path", file);
auto editor = getEnv("EDITOR").value_or("cat");
auto args = tokenizeString<Strings>(editor);
if (line > 0 && (
Expand All @@ -13,7 +16,7 @@ Strings editorFor(const Path & file, uint32_t line)
editor.find("vim") != std::string::npos ||
editor.find("kak") != std::string::npos))
args.push_back(fmt("+%d", line));
args.push_back(file);
args.push_back(path->abs());
return args;
}

Expand Down
3 changes: 2 additions & 1 deletion src/libcmd/editor-for.hh
Expand Up @@ -2,11 +2,12 @@
///@file

#include "types.hh"
#include "input-accessor.hh"

namespace nix {

/* Helper function to generate args that invoke $EDITOR on
filename:lineno. */
Strings editorFor(const Path & file, uint32_t line);
Strings editorFor(const SourcePath & file, uint32_t line);

}
3 changes: 1 addition & 2 deletions src/libcmd/installable-flake.cc
Expand Up @@ -96,8 +96,7 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
auto v = attr->forceValue();

if (v.type() == nPath) {
PathSet context;
auto storePath = state->copyPathToStore(context, Path(v.path));
auto storePath = v.path().fetchToStore(state->store);
return {{
.path = DerivedPath::Opaque {
.path = std::move(storePath),
Expand Down
2 changes: 1 addition & 1 deletion src/libcmd/installables.cc
Expand Up @@ -427,7 +427,7 @@ Installables 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(CanonPath::fromCwd()));
state->eval(e, *vFile);
}

Expand Down
12 changes: 4 additions & 8 deletions src/libcmd/repl.cc
Expand Up @@ -54,8 +54,6 @@ struct NixRepl
, gc
#endif
{
std::string curDir;

size_t debugTraceIndex;

Strings loadedFiles;
Expand Down Expand Up @@ -113,7 +111,6 @@ NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalStat
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
, historyFile(getDataDir() + "/nix/repl-history")
{
curDir = absPath(".");
}


Expand Down Expand Up @@ -590,15 +587,15 @@ bool NixRepl::processLine(std::string line)
Value v;
evalString(arg, v);

const auto [path, line] = [&] () -> std::pair<Path, uint32_t> {
const auto [path, line] = [&] () -> std::pair<SourcePath, uint32_t> {
if (v.type() == nPath || v.type() == nString) {
PathSet context;
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
return {path, 0};
} else if (v.isLambda()) {
auto pos = state->positions[v.lambda.fun->pos];
if (auto path = std::get_if<Path>(&pos.origin))
return {*path, pos.line};
return {SourcePath(CanonPath(*path)), pos.line};
else
throw Error("'%s' cannot be shown in an editor", pos);
} else {
Expand Down Expand Up @@ -872,8 +869,7 @@ void NixRepl::addVarToScope(const Symbol name, Value & v)

Expr * NixRepl::parseString(std::string s)
{
Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv);
return e;
return state->parseExprFromString(std::move(s), state->rootPath(CanonPath::fromCwd()), staticEnv);
}


Expand Down Expand Up @@ -930,7 +926,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().to_string() << ANSI_NORMAL; // !!! escaping?
break;

case nNull:
Expand Down
26 changes: 15 additions & 11 deletions src/libexpr/attr-path.cc
Expand Up @@ -106,7 +106,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::strin
}


std::pair<std::string, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what)
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what)
{
Value * v2;
try {
Expand All @@ -118,21 +118,25 @@ std::pair<std::string, uint32_t> findPackageFilename(EvalState & state, Value &

// FIXME: is it possible to extract the Pos object instead of doing this
// toString + parsing?
auto pos = state.forceString(*v2, noPos, "while evaluating the 'meta.position' attribute of a derivation");
PathSet context;
auto path = state.coerceToPath(noPos, *v2, context, "while evaluating the 'meta.position' attribute of a derivation");

auto colon = pos.rfind(':');
if (colon == std::string::npos)
throw ParseError("cannot parse meta.position attribute '%s'", pos);
auto fn = path.path.abs();

auto fail = [fn]() {
throw ParseError("cannot parse 'meta.position' attribute '%s'", fn);
};

std::string filename(pos, 0, colon);
unsigned int lineno;
try {
lineno = std::stoi(std::string(pos, colon + 1, std::string::npos));
auto colon = fn.rfind(':');
if (colon == std::string::npos) fail();
std::string filename(fn, 0, colon);
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
return {CanonPath(fn.substr(0, colon)), lineno};
} catch (std::invalid_argument & e) {
throw ParseError("cannot parse line number '%s'", pos);
fail();
abort();
}

return { std::move(filename), lineno };
}


Expand Down
2 changes: 1 addition & 1 deletion src/libexpr/attr-path.hh
Expand Up @@ -18,7 +18,7 @@ std::pair<Value *, PosIdx> findAlongAttrPath(
Value & vIn);

/* Heuristic to find the filename and lineno or a nix value. */
std::pair<std::string, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what);
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what);

std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s);

Expand Down
10 changes: 6 additions & 4 deletions src/libexpr/eval-cache.cc
Expand Up @@ -442,8 +442,10 @@ 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) {
auto path = v.path().path;
cachedValue = {root->db->setString(getKey(), path.abs()), string_t{path.abs(), {}}};
}
else if (v.type() == nBool)
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
else if (v.type() == nInt)
Expand Down Expand Up @@ -580,7 +582,7 @@ std::string AttrCursor::getString()
if (v.type() != nString && v.type() != nPath)
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();

return v.type() == nString ? v.string.s : v.path;
return v.type() == nString ? v.string.s : v.path().to_string();
}

string_t AttrCursor::getStringWithContext()
Expand Down Expand Up @@ -622,7 +624,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
root->state.error("'%s' is not a string but %s", getAttrPathStr()).debugThrow<TypeError>();
}
Expand Down

0 comments on commit 94812cc

Please sign in to comment.