aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval.cc17
-rw-r--r--src/libexpr/eval.hh6
-rw-r--r--src/libexpr/flake/flake.cc4
-rw-r--r--src/libexpr/lexer.l6
-rw-r--r--src/libexpr/primops.cc39
-rw-r--r--src/libexpr/primops.hh4
-rw-r--r--src/libexpr/primops/fetchTree.cc64
7 files changed, 85 insertions, 55 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index bc41a2cd9..800839a8d 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -465,6 +465,23 @@ EvalState::~EvalState()
}
+void EvalState::requireExperimentalFeatureOnEvaluation(
+ const std::string & feature,
+ const std::string_view fName,
+ const Pos & pos)
+{
+ if (!settings.isExperimentalFeatureEnabled(feature)) {
+ throw EvalError({
+ .msg = hintfmt(
+ "Cannot call '%2%' because experimental Nix feature '%1%' is disabled. You can enable it via '--extra-experimental-features %1%'.",
+ feature,
+ fName
+ ),
+ .errPos = pos
+ });
+ }
+}
+
Path EvalState::checkSourcePath(const Path & path_)
{
if (!allowedPaths) return path_;
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index b29feb134..9df6150c6 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -140,6 +140,12 @@ public:
std::shared_ptr<Store> buildStore = nullptr);
~EvalState();
+ void requireExperimentalFeatureOnEvaluation(
+ const std::string & feature,
+ const std::string_view fName,
+ const Pos & pos
+ );
+
void addToSearchPath(const string & s);
SearchPath getSearchPath() { return searchPath; }
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 492b47115..1a1fa6938 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -688,6 +688,8 @@ void callFlake(EvalState & state,
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
+ state.requireExperimentalFeatureOnEvaluation("flakes", "builtins.getFlake", pos);
+
auto flakeRefS = state.forceStringNoCtx(*args[0], pos);
auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
if (evalSettings.pureEval && !flakeRef.input.isImmutable())
@@ -703,7 +705,7 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
v);
}
-static RegisterPrimOp r2("__getFlake", 1, prim_getFlake, "flakes");
+static RegisterPrimOp r2("__getFlake", 1, prim_getFlake);
}
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 8ad6a1957..51593eccd 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -28,6 +28,8 @@ using namespace nix;
namespace nix {
+// backup to recover from yyless(0)
+YYLTYPE prev_yylloc;
static void initLoc(YYLTYPE * loc)
{
@@ -38,6 +40,8 @@ static void initLoc(YYLTYPE * loc)
static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
{
+ prev_yylloc = *loc;
+
loc->first_line = loc->last_line;
loc->first_column = loc->last_column;
@@ -210,6 +214,7 @@ or { return OR_KW; }
{HPATH_START}\$\{ {
PUSH_STATE(PATH_START);
yyless(0);
+ *yylloc = prev_yylloc;
}
<PATH_START>{PATH_SEG} {
@@ -265,6 +270,7 @@ or { return OR_KW; }
context (it may be ')', ';', or something of that sort) */
POP_STATE();
yyless(0);
+ *yylloc = prev_yylloc;
return PATH_END;
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 15d56bd6d..bd8ea18fb 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -52,7 +52,8 @@ void EvalState::realiseContext(const PathSet & context)
if (drvs.empty()) return;
if (!evalSettings.enableImportFromDerivation)
- throw EvalError("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false",
+ throw Error(
+ "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled",
store->printStorePath(drvs.begin()->drvPath));
/* For performance, prefetch all substitute info. */
@@ -124,7 +125,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
});
} catch (Error & e) {
e.addTrace(pos, "while importing '%s'", path);
- throw e;
+ throw;
}
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
@@ -578,7 +579,7 @@ static Bindings::iterator getAttr(
// Adding another trace for the function name to make it clear
// which call received wrong arguments.
e.addTrace(pos, hintfmt("while invoking '%s'", funcName));
- throw e;
+ throw;
}
}
@@ -1173,7 +1174,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
// hash per output.
auto hashModulo = hashDerivationModulo(*state.store, Derivation(drv), true);
std::visit(overloaded {
- [&](Hash h) {
+ [&](Hash & h) {
for (auto & i : outputs) {
auto outPath = state.store->makeOutputPath(i, h, drvName);
drv.env[i] = state.store->printStorePath(outPath);
@@ -1185,11 +1186,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
});
}
},
- [&](CaOutputHashes) {
+ [&](CaOutputHashes &) {
// Shouldn't happen as the toplevel derivation is not CA.
assert(false);
},
- [&](DeferredHash _) {
+ [&](DeferredHash &) {
for (auto & i : outputs) {
drv.outputs.insert_or_assign(i,
DerivationOutput {
@@ -1716,7 +1717,7 @@ static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Va
parseJSON(state, s, v);
} catch (JSONParseError &e) {
e.addTrace(pos, "while decoding a JSON string");
- throw e;
+ throw;
}
}
@@ -1890,6 +1891,9 @@ static void addPath(EvalState & state, const Pos & pos, const string & name, con
dstPath = state.store->printStorePath(*expectedStorePath);
mkString(v, dstPath, {dstPath});
+
+ if (state.allowedPaths)
+ state.allowedPaths->insert(v.string.s);
}
@@ -2914,7 +2918,7 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V
state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos)));
} catch (TypeError &e) {
e.addTrace(pos, hintfmt("while invoking '%s'", "concatMap"));
- throw e;
+ throw;
}
len += lists[n].listSize();
}
@@ -3618,15 +3622,13 @@ static RegisterPrimOp primop_splitVersion({
RegisterPrimOp::PrimOps * RegisterPrimOp::primOps;
-RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun,
- std::optional<std::string> requiredFeature)
+RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun)
{
if (!primOps) primOps = new PrimOps;
primOps->push_back({
.name = name,
.args = {},
.arity = arity,
- .requiredFeature = std::move(requiredFeature),
.fun = fun
});
}
@@ -3700,14 +3702,13 @@ void EvalState::createBaseEnv()
if (RegisterPrimOp::primOps)
for (auto & primOp : *RegisterPrimOp::primOps)
- if (!primOp.requiredFeature || settings.isExperimentalFeatureEnabled(*primOp.requiredFeature))
- addPrimOp({
- .fun = primOp.fun,
- .arity = std::max(primOp.args.size(), primOp.arity),
- .name = symbols.create(primOp.name),
- .args = std::move(primOp.args),
- .doc = primOp.doc,
- });
+ addPrimOp({
+ .fun = primOp.fun,
+ .arity = std::max(primOp.args.size(), primOp.arity),
+ .name = symbols.create(primOp.name),
+ .args = std::move(primOp.args),
+ .doc = primOp.doc,
+ });
/* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */
diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh
index 9d42d6539..5b16e075f 100644
--- a/src/libexpr/primops.hh
+++ b/src/libexpr/primops.hh
@@ -15,7 +15,6 @@ struct RegisterPrimOp
std::vector<std::string> args;
size_t arity = 0;
const char * doc;
- std::optional<std::string> requiredFeature;
PrimOpFun fun;
};
@@ -28,8 +27,7 @@ struct RegisterPrimOp
RegisterPrimOp(
std::string name,
size_t arity,
- PrimOpFun fun,
- std::optional<std::string> requiredFeature = {});
+ PrimOpFun fun);
RegisterPrimOp(Info && info);
};
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index d004b701b..1a69fe4e4 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -36,7 +36,7 @@ void emitTreeAttrs(
if (input.getType() == "git")
mkBool(*state.allocAttr(v, state.symbols.create("submodules")),
- fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(true));
+ fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false));
if (!forceDirty) {
@@ -66,7 +66,7 @@ void emitTreeAttrs(
v.attrs->sort();
}
-std::string fixURI(std::string uri, EvalState &state, const std::string & defaultScheme = "file")
+std::string fixURI(std::string uri, EvalState & state, const std::string & defaultScheme = "file")
{
state.checkURI(uri);
return uri.find("://") != std::string::npos ? uri : defaultScheme + "://" + uri;
@@ -81,23 +81,17 @@ std::string fixURIForGit(std::string uri, EvalState & state)
return fixURI(uri, state);
}
-void addURI(EvalState &state, fetchers::Attrs &attrs, Symbol name, std::string v)
-{
- string n(name);
- attrs.emplace(name, n == "url" ? fixURI(v, state) : v);
-}
-
struct FetchTreeParams {
bool emptyRevFallback = false;
bool allowNameArgument = false;
};
static void fetchTree(
- EvalState &state,
- const Pos &pos,
- Value **args,
- Value &v,
- const std::optional<std::string> type,
+ EvalState & state,
+ const Pos & pos,
+ Value * * args,
+ Value & v,
+ std::optional<std::string> type,
const FetchTreeParams & params = FetchTreeParams{}
) {
fetchers::Input input;
@@ -110,17 +104,33 @@ static void fetchTree(
fetchers::Attrs attrs;
+ if (auto aType = args[0]->attrs->get(state.sType)) {
+ if (type)
+ throw Error({
+ .msg = hintfmt("unexpected attribute 'type'"),
+ .errPos = pos
+ });
+ type = state.forceStringNoCtx(*aType->value, *aType->pos);
+ } else if (!type)
+ throw Error({
+ .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"),
+ .errPos = pos
+ });
+
+ attrs.emplace("type", type.value());
+
for (auto & attr : *args[0]->attrs) {
+ if (attr.name == state.sType) continue;
state.forceValue(*attr.value);
- if (attr.value->type() == nPath || attr.value->type() == nString)
- addURI(
- state,
- attrs,
- attr.name,
- state.coerceToString(*attr.pos, *attr.value, context, false, false)
- );
- else if (attr.value->type() == nString)
- addURI(state, attrs, attr.name, attr.value->string.s);
+ if (attr.value->type() == nPath || attr.value->type() == nString) {
+ auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false);
+ attrs.emplace(attr.name,
+ attr.name == "url"
+ ? type == "git"
+ ? fixURIForGit(s, state)
+ : fixURI(s, state)
+ : s);
+ }
else if (attr.value->type() == nBool)
attrs.emplace(attr.name, Explicit<bool>{attr.value->boolean});
else if (attr.value->type() == nInt)
@@ -130,15 +140,6 @@ static void fetchTree(
attr.name, showType(*attr.value));
}
- if (type)
- attrs.emplace("type", type.value());
-
- if (!attrs.count("type"))
- throw Error({
- .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"),
- .errPos = pos
- });
-
if (!params.allowNameArgument)
if (auto nameIter = attrs.find("name"); nameIter != attrs.end())
throw Error({
@@ -146,7 +147,6 @@ static void fetchTree(
.errPos = pos
});
-
input = fetchers::Input::fromAttrs(std::move(attrs));
} else {
auto url = state.coerceToString(pos, *args[0], context, false, false);