forked from lix-project/lix
Enforce use of immutable flakes in pure mode
... plus a temporary hack to allow impure flakes at top-level for the default installation source.
This commit is contained in:
parent
ba05f29838
commit
272b58220d
|
@ -22,9 +22,6 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
|
||||||
std::optional<std::string> ref, std::string rev,
|
std::optional<std::string> ref, std::string rev,
|
||||||
const std::string & name)
|
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")) {
|
if (!ref && rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.git")) {
|
||||||
|
|
||||||
bool clean = true;
|
bool clean = true;
|
||||||
|
@ -218,6 +215,9 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
// whitelist. Ah well.
|
// whitelist. Ah well.
|
||||||
state.checkURI(url);
|
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);
|
auto gitInfo = exportGit(state.store, url, ref, rev, name);
|
||||||
|
|
||||||
state.mkAttrs(v, 8);
|
state.mkAttrs(v, 8);
|
||||||
|
|
|
@ -27,9 +27,6 @@ std::regex commitHashRegex("^[0-9a-fA-F]{40}$");
|
||||||
HgInfo exportMercurial(ref<Store> store, const std::string & uri,
|
HgInfo exportMercurial(ref<Store> store, const std::string & uri,
|
||||||
std::string rev, const std::string & name)
|
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")) {
|
if (rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.hg")) {
|
||||||
|
|
||||||
bool clean = runProgram("hg", true, { "status", "-R", uri, "--modified", "--added", "--removed" }) == "";
|
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.
|
// whitelist. Ah well.
|
||||||
state.checkURI(url);
|
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);
|
auto hgInfo = exportMercurial(state.store, url, rev, name);
|
||||||
|
|
||||||
state.mkAttrs(v, 8);
|
state.mkAttrs(v, 8);
|
||||||
|
|
|
@ -162,16 +162,17 @@ static Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
|
||||||
return flake;
|
return flake;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given a set of flake references, recursively fetch them and their
|
/* Given a flake reference, recursively fetch it and its
|
||||||
dependencies. */
|
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::map<FlakeId, Flake> done;
|
||||||
std::queue<FlakeRef> todo;
|
std::queue<std::tuple<FlakeRef, bool>> todo;
|
||||||
for (auto & i : flakeRefs) todo.push(i);
|
todo.push({topRef, impureTopRef});
|
||||||
|
|
||||||
while (!todo.empty()) {
|
while (!todo.empty()) {
|
||||||
auto flakeRef = todo.front();
|
auto [flakeRef, impureRef] = todo.front();
|
||||||
todo.pop();
|
todo.pop();
|
||||||
|
|
||||||
if (auto refData = std::get_if<FlakeRef::IsFlakeId>(&flakeRef.data)) {
|
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);
|
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);
|
auto flake = getFlake(state, flakeRef);
|
||||||
|
|
||||||
if (done.count(flake.id)) continue;
|
if (done.count(flake.id)) continue;
|
||||||
|
|
||||||
for (auto & require : flake.requires)
|
for (auto & require : flake.requires)
|
||||||
todo.push(require);
|
todo.push({require, false});
|
||||||
|
|
||||||
done.emplace(flake.id, flake);
|
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)
|
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);
|
||||||
|
|
||||||
auto flakes = resolveFlakes(state, {flakeUri});
|
// 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 = resolveFlake(state, flakeUri, impure);
|
||||||
|
|
||||||
auto vResult = state.allocValue();
|
auto vResult = state.allocValue();
|
||||||
|
|
||||||
|
|
|
@ -136,4 +136,18 @@ std::string FlakeRef::to_string() const
|
||||||
else abort();
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,10 +149,7 @@ struct FlakeRef
|
||||||
|
|
||||||
/* Check whether this is an "immutable" flake reference, that is,
|
/* Check whether this is an "immutable" flake reference, that is,
|
||||||
one that contains a commit hash or content hash. */
|
one that contains a commit hash or content hash. */
|
||||||
bool isImmutable() const
|
bool isImmutable() const;
|
||||||
{
|
|
||||||
abort(); // TODO
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,11 @@ Value * SourceExprCommand::getSourceExpr(EvalState & state)
|
||||||
if (file != "")
|
if (file != "")
|
||||||
state.evalFile(lookupFileArg(state, file), *vSourceExpr);
|
state.evalFile(lookupFileArg(state, file), *vSourceExpr);
|
||||||
else {
|
else {
|
||||||
|
// FIXME: remove "impure" hack, call some non-user-accessible
|
||||||
|
// variant of getFlake instead.
|
||||||
auto fun = state.parseExprFromString(
|
auto fun = state.parseExprFromString(
|
||||||
"builtins.mapAttrs (flakeName: flakeInfo:"
|
"builtins.mapAttrs (flakeName: flakeInfo:"
|
||||||
" (getFlake flakeInfo.uri).${flakeName}.provides.packages or {})", "/");
|
" (getFlake (\"impure:\" + flakeInfo.uri)).${flakeName}.provides.packages or {})", "/");
|
||||||
auto vFun = state.allocValue();
|
auto vFun = state.allocValue();
|
||||||
state.eval(fun, *vFun);
|
state.eval(fun, *vFun);
|
||||||
auto vRegistry = state.makeFlakeRegistryValue();
|
auto vRegistry = state.makeFlakeRegistryValue();
|
||||||
|
|
Loading…
Reference in a new issue