aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-02-12 21:05:44 +0100
committerEelco Dolstra <edolstra@gmail.com>2019-02-12 21:07:48 +0100
commit272b58220d17bc862f646dbc2cb38eea126001c0 (patch)
treebad4b4a1d2e3b41b56d9c27073a57e53eb2146d5
parentba05f29838b3bafe28c3ea491be711229298cb1b (diff)
Enforce use of immutable flakes in pure mode
... plus a temporary hack to allow impure flakes at top-level for the default installation source.
-rw-r--r--src/libexpr/primops/fetchGit.cc6
-rw-r--r--src/libexpr/primops/fetchMercurial.cc6
-rw-r--r--src/libexpr/primops/flake.cc30
-rw-r--r--src/libexpr/primops/flakeref.cc14
-rw-r--r--src/libexpr/primops/flakeref.hh5
-rw-r--r--src/nix/installables.cc4
6 files changed, 46 insertions, 19 deletions
diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc
index 62e9dfc0e..bbf13c87b 100644
--- a/src/libexpr/primops/fetchGit.cc
+++ b/src/libexpr/primops/fetchGit.cc
@@ -22,9 +22,6 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
std::optional<std::string> ref, std::string rev,
const std::string & name)
{
- if (evalSettings.pureEval && rev == "")
- throw Error("in pure evaluation mode, 'fetchGit' requires a Git revision");
-
if (!ref && rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.git")) {
bool clean = true;
@@ -218,6 +215,9 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
// whitelist. Ah well.
state.checkURI(url);
+ if (evalSettings.pureEval && rev == "")
+ throw Error("in pure evaluation mode, 'fetchGit' requires a Git revision");
+
auto gitInfo = exportGit(state.store, url, ref, rev, name);
state.mkAttrs(v, 8);
diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc
index 66f49f374..cfe1bd871 100644
--- a/src/libexpr/primops/fetchMercurial.cc
+++ b/src/libexpr/primops/fetchMercurial.cc
@@ -27,9 +27,6 @@ std::regex commitHashRegex("^[0-9a-fA-F]{40}$");
HgInfo exportMercurial(ref<Store> store, const std::string & uri,
std::string rev, const std::string & name)
{
- if (evalSettings.pureEval && rev == "")
- throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
-
if (rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.hg")) {
bool clean = runProgram("hg", true, { "status", "-R", uri, "--modified", "--added", "--removed" }) == "";
@@ -203,6 +200,9 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
// whitelist. Ah well.
state.checkURI(url);
+ if (evalSettings.pureEval && rev == "")
+ throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
+
auto hgInfo = exportMercurial(state.store, url, rev, name);
state.mkAttrs(v, 8);
diff --git a/src/libexpr/primops/flake.cc b/src/libexpr/primops/flake.cc
index 4d027558d..1e70ccbd6 100644
--- a/src/libexpr/primops/flake.cc
+++ b/src/libexpr/primops/flake.cc
@@ -162,16 +162,17 @@ static Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
return flake;
}
-/* Given a set of flake references, recursively fetch them and their
+/* Given a flake reference, recursively fetch it and its
dependencies. */
-static std::map<FlakeId, Flake> resolveFlakes(EvalState & state, const std::vector<FlakeRef> & flakeRefs)
+static std::map<FlakeId, Flake> resolveFlake(EvalState & state,
+ const FlakeRef & topRef, bool impureTopRef)
{
std::map<FlakeId, Flake> done;
- std::queue<FlakeRef> todo;
- for (auto & i : flakeRefs) todo.push(i);
+ std::queue<std::tuple<FlakeRef, bool>> todo;
+ todo.push({topRef, impureTopRef});
while (!todo.empty()) {
- auto flakeRef = todo.front();
+ auto [flakeRef, impureRef] = todo.front();
todo.pop();
if (auto refData = std::get_if<FlakeRef::IsFlakeId>(&flakeRef.data)) {
@@ -179,12 +180,15 @@ static std::map<FlakeId, Flake> resolveFlakes(EvalState & state, const std::vect
flakeRef = lookupFlake(state, flakeRef);
}
+ if (evalSettings.pureEval && !flakeRef.isImmutable() && !impureRef)
+ throw Error("mutable flake '%s' is not allowed in pure mode; use --no-pure-eval to disable", flakeRef.to_string());
+
auto flake = getFlake(state, flakeRef);
if (done.count(flake.id)) continue;
for (auto & require : flake.requires)
- todo.push(require);
+ todo.push({require, false});
done.emplace(flake.id, flake);
}
@@ -194,9 +198,19 @@ static std::map<FlakeId, Flake> resolveFlakes(EvalState & state, const std::vect
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
- auto flakeUri = FlakeRef(state.forceStringNoCtx(*args[0], pos));
+ auto flakeUri = state.forceStringNoCtx(*args[0], pos);
+
+ // FIXME: temporary hack to make the default installation source
+ // work.
+ bool impure = false;
+ if (hasPrefix(flakeUri, "impure:")) {
+ flakeUri = std::string(flakeUri, 7);
+ impure = true;
+ }
+
+ auto flakeRef = FlakeRef(flakeUri);
- auto flakes = resolveFlakes(state, {flakeUri});
+ auto flakes = resolveFlake(state, flakeUri, impure);
auto vResult = state.allocValue();
diff --git a/src/libexpr/primops/flakeref.cc b/src/libexpr/primops/flakeref.cc
index 447b56822..639313f21 100644
--- a/src/libexpr/primops/flakeref.cc
+++ b/src/libexpr/primops/flakeref.cc
@@ -136,4 +136,18 @@ std::string FlakeRef::to_string() const
else abort();
}
+bool FlakeRef::isImmutable() const
+{
+ if (auto refData = std::get_if<FlakeRef::IsFlakeId>(&data))
+ return (bool) refData->rev;
+
+ else if (auto refData = std::get_if<FlakeRef::IsGitHub>(&data))
+ return (bool) refData->rev;
+
+ else if (auto refData = std::get_if<FlakeRef::IsGit>(&data))
+ return (bool) refData->rev;
+
+ else abort();
+}
+
}
diff --git a/src/libexpr/primops/flakeref.hh b/src/libexpr/primops/flakeref.hh
index 8559317e0..ad0cf8630 100644
--- a/src/libexpr/primops/flakeref.hh
+++ b/src/libexpr/primops/flakeref.hh
@@ -149,10 +149,7 @@ struct FlakeRef
/* Check whether this is an "immutable" flake reference, that is,
one that contains a commit hash or content hash. */
- bool isImmutable() const
- {
- abort(); // TODO
- }
+ bool isImmutable() const;
};
}
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index faad057a7..b4584f168 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -31,9 +31,11 @@ Value * SourceExprCommand::getSourceExpr(EvalState & state)
if (file != "")
state.evalFile(lookupFileArg(state, file), *vSourceExpr);
else {
+ // FIXME: remove "impure" hack, call some non-user-accessible
+ // variant of getFlake instead.
auto fun = state.parseExprFromString(
"builtins.mapAttrs (flakeName: flakeInfo:"
- " (getFlake flakeInfo.uri).${flakeName}.provides.packages or {})", "/");
+ " (getFlake (\"impure:\" + flakeInfo.uri)).${flakeName}.provides.packages or {})", "/");
auto vFun = state.allocValue();
state.eval(fun, *vFun);
auto vRegistry = state.makeFlakeRegistryValue();