aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/primops.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/primops.cc')
-rw-r--r--src/libexpr/primops.cc122
1 files changed, 62 insertions, 60 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 72faeada8..c77d45bd3 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -110,7 +110,7 @@ struct RealisePathFlags {
bool checkForPureEval = true;
};
-static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const RealisePathFlags flags = {})
+static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, const RealisePathFlags flags = {})
{
PathSet context;
@@ -119,7 +119,7 @@ static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const Re
try {
StringMap rewrites = state.realiseContext(context);
- auto realPath = state.toRealPath(rewriteStrings(path, rewrites), context);
+ auto realPath = state.rootPath(CanonPath(state.toRealPath(rewriteStrings(path.path.abs(), rewrites), context)));
return flags.checkForPureEval
? state.checkSourcePath(realPath)
@@ -166,13 +166,14 @@ static void mkOutputString(
static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * vScope, Value & v)
{
auto path = realisePath(state, pos, vPath);
+ auto path2 = path.path.abs();
// FIXME
auto isValidDerivationInStore = [&]() -> std::optional<StorePath> {
- if (!state.store->isStorePath(path))
+ if (!state.store->isStorePath(path2))
return std::nullopt;
- auto storePath = state.store->parseStorePath(path);
- if (!(state.store->isValidPath(storePath) && isDerivation(path)))
+ auto storePath = state.store->parseStorePath(path2);
+ if (!(state.store->isValidPath(storePath) && isDerivation(path2)))
return std::nullopt;
return storePath;
};
@@ -181,7 +182,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
auto storePath = *optStorePath;
Derivation drv = state.store->readDerivation(storePath);
auto attrs = state.buildBindings(3 + drv.outputs.size());
- attrs.alloc(state.sDrvPath).mkString(path, {"=" + path});
+ attrs.alloc(state.sDrvPath).mkString(path2, {"=" + path2});
attrs.alloc(state.sName).mkString(drv.env["name"]);
auto & outputsVal = attrs.alloc(state.sOutputs);
state.mkList(outputsVal, drv.outputs.size());
@@ -198,7 +199,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
state.vImportedDrvToDerivation = allocRootValue(state.allocValue());
state.eval(state.parseExprFromString(
#include "imported-drv-to-derivation.nix.gen.hh"
- , "/"), **state.vImportedDrvToDerivation);
+ , CanonPath::root), **state.vImportedDrvToDerivation);
}
state.forceFunction(**state.vImportedDrvToDerivation, pos, "while evaluating imported-drv-to-derivation.nix.gen.hh");
@@ -206,10 +207,10 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
state.forceAttrs(v, pos, "while calling imported-drv-to-derivation.nix.gen.hh");
}
- else if (path == corepkgsPrefix + "fetchurl.nix") {
+ else if (path2 == corepkgsPrefix + "fetchurl.nix") {
state.eval(state.parseExprFromString(
#include "fetchurl.nix.gen.hh"
- , "/"), v);
+ , CanonPath::root), v);
}
else {
@@ -330,7 +331,7 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu
std::string sym(state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.importNative"));
- void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
+ void *handle = dlopen(path.path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle)
state.debugThrowLastTrace(EvalError("could not open '%1%': %2%", path, dlerror()));
@@ -378,7 +379,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
auto output = runProgram(program, true, commandArgs);
Expr * parsed;
try {
- parsed = state.parseExprFromString(std::move(output), "/");
+ parsed = state.parseExprFromString(std::move(output), state.rootPath(CanonPath::root));
} catch (Error & e) {
e.addTrace(state.positions[pos], "while parsing the output from '%1%'", program);
throw;
@@ -585,7 +586,7 @@ struct CompareValues
case nString:
return strcmp(v1->string.s, v2->string.s) < 0;
case nPath:
- return strcmp(v1->path, v2->path) < 0;
+ return strcmp(v1->_path, v2->_path) < 0;
case nList:
// Lexicographic comparison
for (size_t i = 0;; i++) {
@@ -1428,8 +1429,8 @@ static RegisterPrimOp primop_placeholder({
static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
- Path path = state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.toPath");
- v.mkString(canonPath(path), context);
+ auto path = state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.toPath");
+ v.mkString(path.path.abs(), context);
}
static RegisterPrimOp primop_toPath({
@@ -1459,21 +1460,22 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
}));
PathSet context;
- Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.storePath"));
+ auto path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.storePath")).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. */
- if (!state.store->isStorePath(path)) path = canonPath(path, true);
- if (!state.store->isInStore(path))
+ if (!state.store->isStorePath(path.abs()))
+ path = CanonPath(canonPath(path.abs(), true));
+ if (!state.store->isInStore(path.abs()))
state.debugThrowLastTrace(EvalError({
.msg = hintfmt("path '%1%' is not in the Nix store", path),
.errPos = state.positions[pos]
}));
- auto path2 = state.store->toStorePath(path).first;
+ auto path2 = state.store->toStorePath(path.abs()).first;
if (!settings.readOnlyMode)
state.store->ensurePath(path2);
context.insert(state.store->printStorePath(path2));
- v.mkString(path, context);
+ v.mkString(path.abs(), context);
}
static RegisterPrimOp primop_storePath({
@@ -1504,7 +1506,7 @@ static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args,
auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false });
try {
- v.mkBool(pathExists(state.checkSourcePath(path)));
+ v.mkBool(state.checkSourcePath(path).pathExists());
} catch (SysError & e) {
/* Don't give away info from errors while canonicalising
‘path’ in restricted mode. */
@@ -1551,11 +1553,17 @@ static RegisterPrimOp primop_baseNameOf({
static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
- auto path = state.coerceToString(pos, *args[0], context,
- "while evaluating the first argument passed to builtins.dirOf",
+ state.forceValue(*args[0], pos);
+ if (args[0]->type() == nPath) {
+ auto path = args[0]->path();
+ v.mkPath(path.path.isRoot() ? path : path.parent());
+ } else {
+ auto path = state.coerceToString(pos, *args[0], context,
+ "while evaluating the first argument passed to 'builtins.dirOf'",
false, false);
- auto dir = dirOf(*path);
- if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context);
+ auto dir = dirOf(*path);
+ v.mkString(dir, context);
+ }
}
static RegisterPrimOp primop_dirOf({
@@ -1573,13 +1581,13 @@ static RegisterPrimOp primop_dirOf({
static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
- auto s = readFile(path);
+ auto s = path.readFile();
if (s.find((char) 0) != std::string::npos)
state.debugThrowLastTrace(Error("the contents of the file '%1%' cannot be represented as a Nix string", path));
StorePathSet refs;
- if (state.store->isInStore(path)) {
+ if (state.store->isInStore(path.path.abs())) {
try {
- refs = state.store->queryPathInfo(state.store->toStorePath(path).first)->references;
+ refs = state.store->queryPathInfo(state.store->toStorePath(path.path.abs()).first)->references;
} catch (Error &) { // FIXME: should be InvalidPathError
}
// Re-scan references to filter down to just the ones that actually occur in the file.
@@ -1660,7 +1668,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, V
auto path = realisePath(state, pos, *args[1]);
- v.mkString(hashFile(*ht, path).to_string(Base16, false));
+ v.mkString(hashString(*ht, path.readFile()).to_string(Base16, false));
}
static RegisterPrimOp primop_hashFile({
@@ -1674,26 +1682,20 @@ static RegisterPrimOp primop_hashFile({
.fun = prim_hashFile,
});
-
-/* Stringize a directory entry enum. Used by `readFileType' and `readDir'. */
-static const char * dirEntTypeToString(unsigned char dtType)
+static std::string_view fileTypeToString(InputAccessor::Type type)
{
- /* Enum DT_(DIR|LNK|REG|UNKNOWN) */
- switch(dtType) {
- case DT_REG: return "regular"; break;
- case DT_DIR: return "directory"; break;
- case DT_LNK: return "symlink"; break;
- default: return "unknown"; break;
- }
- return "unknown"; /* Unreachable */
+ return
+ type == InputAccessor::Type::tRegular ? "regular" :
+ type == InputAccessor::Type::tDirectory ? "directory" :
+ type == InputAccessor::Type::tSymlink ? "symlink" :
+ "unknown";
}
-
static void prim_readFileType(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
auto path = realisePath(state, pos, *args[0]);
/* Retrieve the directory entry type and stringize it. */
- v.mkString(dirEntTypeToString(getFileType(path)));
+ v.mkString(fileTypeToString(path.lstat().type));
}
static RegisterPrimOp primop_readFileType({
@@ -1714,8 +1716,7 @@ static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Va
// Retrieve directory entries for all nodes in a directory.
// This is similar to `getFileType` but is optimized to reduce system calls
// on many systems.
- DirEntries entries = readDirectory(path);
-
+ auto entries = path.readDirectory();
auto attrs = state.buildBindings(entries.size());
// If we hit unknown directory entry types we may need to fallback to
@@ -1724,22 +1725,21 @@ static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Va
// `builtins.readFileType` application.
Value * readFileType = nullptr;
- for (auto & ent : entries) {
- auto & attr = attrs.alloc(ent.name);
- if (ent.type == DT_UNKNOWN) {
+ for (auto & [name, type] : entries) {
+ auto & attr = attrs.alloc(name);
+ if (!type) {
// Some filesystems or operating systems may not be able to return
// detailed node info quickly in this case we produce a thunk to
// query the file type lazily.
auto epath = state.allocValue();
- Path path2 = path + "/" + ent.name;
- epath->mkString(path2);
+ epath->mkPath(path + name);
if (!readFileType)
readFileType = &state.getBuiltin("readFileType");
attr.mkApp(readFileType, epath);
} else {
// This branch of the conditional is much more likely.
// Here we just stringize the directory entry type.
- attr.mkString(dirEntTypeToString(ent.type));
+ attr.mkString(fileTypeToString(*type));
}
}
@@ -2045,7 +2045,7 @@ static RegisterPrimOp primop_toFile({
static void addPath(
EvalState & state,
const PosIdx pos,
- const std::string & name,
+ std::string_view name,
Path path,
Value * filterFun,
FileIngestionMethod method,
@@ -2073,7 +2073,7 @@ static void addPath(
path = evalSettings.pureEval && expectedHash
? path
- : state.checkSourcePath(path);
+ : state.checkSourcePath(CanonPath(path)).path.abs();
PathFilter filter = filterFun ? ([&](const Path & path) {
auto st = lstat(path);
@@ -2120,9 +2120,10 @@ static void addPath(
static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
PathSet context;
- Path path = state.coerceToPath(pos, *args[1], context, "while evaluating the second argument (the path to filter) passed to builtins.filterSource");
+ auto path = state.coerceToPath(pos, *args[1], context,
+ "while evaluating the second argument (the path to filter) passed to builtins.filterSource");
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.filterSource");
- addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context);
+ addPath(state, pos, path.baseName(), path.path.abs(), args[0], FileIngestionMethod::Recursive, std::nullopt, v, context);
}
static RegisterPrimOp primop_filterSource({
@@ -2182,18 +2183,19 @@ static RegisterPrimOp primop_filterSource({
static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
- state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.path");
- Path path;
+ std::optional<SourcePath> path;
std::string name;
Value * filterFun = nullptr;
auto method = FileIngestionMethod::Recursive;
std::optional<Hash> expectedHash;
PathSet context;
+ state.forceAttrs(*args[0], pos, "while evaluating the argument passed to 'builtins.path'");
+
for (auto & attr : *args[0]->attrs) {
auto n = state.symbols[attr.name];
if (n == "path")
- path = state.coerceToPath(attr.pos, *attr.value, context, "while evaluating the `path` attribute passed to builtins.path");
+ path.emplace(state.coerceToPath(attr.pos, *attr.value, context, "while evaluating the 'path' attribute passed to 'builtins.path'"));
else if (attr.name == state.sName)
name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.path");
else if (n == "filter")
@@ -2208,15 +2210,15 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value
.errPos = state.positions[attr.pos]
}));
}
- if (path.empty())
+ if (!path)
state.debugThrowLastTrace(EvalError({
.msg = hintfmt("missing required 'path' attribute in the first argument to builtins.path"),
.errPos = state.positions[pos]
}));
if (name.empty())
- name = baseNameOf(path);
+ name = path->baseName();
- addPath(state, pos, name, path, filterFun, method, expectedHash, v, context);
+ addPath(state, pos, name, path->path.abs(), filterFun, method, expectedHash, v, context);
}
static RegisterPrimOp primop_path({
@@ -4151,7 +4153,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), derivationNixPath, "/", staticBaseEnv), *vDerivation);
+ eval(parse(code, sizeof(code), derivationNixPath, {CanonPath::root}, staticBaseEnv), *vDerivation);
}