aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2021-10-07 13:43:17 +0200
committerEelco Dolstra <edolstra@gmail.com>2021-10-07 13:43:17 +0200
commit4806f2f6b0fd2cae401b89fe19d8c528ffd88b5f (patch)
treed626b2c5ec4321f0ed68bed9ef9cd37b82ba2f50 /src/libexpr
parent66c4b20d8bdfb9434329439a7314942b25c7ba50 (diff)
Allow builtins.{path,filterSource} on paths with a context
We now build the context (so this has the side-effect of making builtins.{path,filterSource} work on derivations outputs, if IFD is enabled) and then check that the path has no references (which is what we really care about).
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/primops.cc62
1 files changed, 42 insertions, 20 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 77b27799f..67d670fb4 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1843,12 +1843,43 @@ static RegisterPrimOp primop_toFile({
.fun = prim_toFile,
});
-static void addPath(EvalState & state, const Pos & pos, const string & name, const Path & path_,
- Value * filterFun, FileIngestionMethod method, const std::optional<Hash> expectedHash, Value & v)
+static void addPath(
+ EvalState & state,
+ const Pos & pos,
+ const string & name,
+ const Path & path_,
+ Value * filterFun,
+ FileIngestionMethod method,
+ const std::optional<Hash> expectedHash,
+ Value & v,
+ const PathSet & context)
{
- const auto path = evalSettings.pureEval && expectedHash ?
- path_ :
- state.checkSourcePath(path_);
+ try {
+ // FIXME: handle CA derivation outputs (where path_ needs to
+ // be rewritten to the actual output).
+ state.realiseContext(context);
+ } catch (InvalidPathError & e) {
+ throw EvalError({
+ .msg = hintfmt("cannot add path '%s', since path '%s' is not valid", path_, e.path),
+ .errPos = pos
+ });
+ } catch (Error & e) {
+ e.addTrace(pos, "while adding path '%s'", path_);
+ throw;
+ }
+
+ const auto path = evalSettings.pureEval && expectedHash
+ ? path_
+ : state.checkSourcePath(path_);
+
+ if (state.store->isInStore(path)) {
+ auto storePath = state.store->toStorePath(path).first;
+ auto info = state.store->queryPathInfo(storePath);
+ if (!info->references.empty())
+ throw EvalError("store path '%s' is not allowed to have references",
+ state.store->printStorePath(storePath));
+ }
+
PathFilter filter = filterFun ? ([&](const Path & path) {
auto st = lstat(path);
@@ -1876,6 +1907,7 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
std::optional<StorePath> expectedStorePath;
if (expectedHash)
expectedStorePath = state.store->makeFixedOutputPath(method, *expectedHash, name);
+
Path dstPath;
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
dstPath = state.store->printStorePath(settings.readOnlyMode
@@ -1896,11 +1928,6 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
{
PathSet context;
Path path = state.coerceToPath(pos, *args[1], context);
- if (!context.empty())
- throw EvalError({
- .msg = hintfmt("string '%1%' cannot refer to other paths", path),
- .errPos = pos
- });
state.forceValue(*args[0], pos);
if (args[0]->type() != nFunction)
@@ -1911,7 +1938,7 @@ 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);
+ addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context);
}
static RegisterPrimOp primop_filterSource({
@@ -1977,18 +2004,13 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
Value * filterFun = nullptr;
auto method = FileIngestionMethod::Recursive;
std::optional<Hash> expectedHash;
+ PathSet context;
for (auto & attr : *args[0]->attrs) {
const string & n(attr.name);
- if (n == "path") {
- PathSet context;
+ if (n == "path")
path = state.coerceToPath(*attr.pos, *attr.value, context);
- if (!context.empty())
- throw EvalError({
- .msg = hintfmt("string '%1%' cannot refer to other paths", path),
- .errPos = *attr.pos
- });
- } else if (attr.name == state.sName)
+ else if (attr.name == state.sName)
name = state.forceStringNoCtx(*attr.value, *attr.pos);
else if (n == "filter") {
state.forceValue(*attr.value, pos);
@@ -2011,7 +2033,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
if (name.empty())
name = baseNameOf(path);
- addPath(state, pos, name, path, filterFun, method, expectedHash, v);
+ addPath(state, pos, name, path, filterFun, method, expectedHash, v, context);
}
static RegisterPrimOp primop_path({