mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-24 23:06:16 +02:00
c6a89c1a16
While preparing PRs like #9753, I've had to change error messages in dozens of code paths. It would be nice if instead of EvalError("expected 'boolean' but found '%1%'", showType(v)) we could write TypeError(v, "boolean") or similar. Then, changing the error message could be a mechanical refactor with the compiler pointing out places the constructor needs to be changed, rather than the error-prone process of grepping through the codebase. Structured errors would also help prevent the "same" error from having multiple slightly different messages, and could be a first step towards error codes / an error index. This PR reworks the exception infrastructure in `libexpr` to support exception types with different constructor signatures than `BaseError`. Actually refactoring the exceptions to use structured data will come in a future PR (this one is big enough already, as it has to touch every exception in `libexpr`). The core design is in `eval-error.hh`. Generally, errors like this: state.error("'%s' is not a string", getAttrPathStr()) .debugThrow<TypeError>() are transformed like this: state.error<TypeError>("'%s' is not a string", getAttrPathStr()) .debugThrow() The type annotation has moved from `ErrorBuilder::debugThrow` to `EvalState::error`.
92 lines
3.5 KiB
C++
92 lines
3.5 KiB
C++
#include "primops.hh"
|
|
#include "eval-inline.hh"
|
|
#include "eval-settings.hh"
|
|
#include "store-api.hh"
|
|
#include "fetchers.hh"
|
|
#include "url.hh"
|
|
#include "url-parts.hh"
|
|
|
|
namespace nix {
|
|
|
|
static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
|
{
|
|
std::string url;
|
|
std::optional<Hash> rev;
|
|
std::optional<std::string> ref;
|
|
std::string_view name = "source";
|
|
NixStringContext context;
|
|
|
|
state.forceValue(*args[0], pos);
|
|
|
|
if (args[0]->type() == nAttrs) {
|
|
|
|
for (auto & attr : *args[0]->attrs) {
|
|
std::string_view n(state.symbols[attr.name]);
|
|
if (n == "url")
|
|
url = state.coerceToString(attr.pos, *attr.value, context,
|
|
"while evaluating the `url` attribute passed to builtins.fetchMercurial",
|
|
false, false).toOwned();
|
|
else if (n == "rev") {
|
|
// Ugly: unlike fetchGit, here the "rev" attribute can
|
|
// be both a revision or a branch/tag name.
|
|
auto value = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `rev` attribute passed to builtins.fetchMercurial");
|
|
if (std::regex_match(value.begin(), value.end(), revRegex))
|
|
rev = Hash::parseAny(value, HashAlgorithm::SHA1);
|
|
else
|
|
ref = value;
|
|
}
|
|
else if (n == "name")
|
|
name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the `name` attribute passed to builtins.fetchMercurial");
|
|
else
|
|
state.error<EvalError>("unsupported argument '%s' to 'fetchMercurial'", state.symbols[attr.name]).atPos(attr.pos).debugThrow();
|
|
}
|
|
|
|
if (url.empty())
|
|
state.error<EvalError>("'url' argument required").atPos(pos).debugThrow();
|
|
|
|
} else
|
|
url = state.coerceToString(pos, *args[0], context,
|
|
"while evaluating the first argument passed to builtins.fetchMercurial",
|
|
false, false).toOwned();
|
|
|
|
// FIXME: git externals probably can be used to bypass the URI
|
|
// whitelist. Ah well.
|
|
state.checkURI(url);
|
|
|
|
if (evalSettings.pureEval && !rev)
|
|
throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
|
|
|
|
fetchers::Attrs attrs;
|
|
attrs.insert_or_assign("type", "hg");
|
|
attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url);
|
|
attrs.insert_or_assign("name", std::string(name));
|
|
if (ref) attrs.insert_or_assign("ref", *ref);
|
|
if (rev) attrs.insert_or_assign("rev", rev->gitRev());
|
|
auto input = fetchers::Input::fromAttrs(std::move(attrs));
|
|
|
|
// FIXME: use name
|
|
auto [storePath, input2] = input.fetch(state.store);
|
|
|
|
auto attrs2 = state.buildBindings(8);
|
|
state.mkStorePathString(storePath, attrs2.alloc(state.sOutPath));
|
|
if (input2.getRef())
|
|
attrs2.alloc("branch").mkString(*input2.getRef());
|
|
// Backward compatibility: set 'rev' to
|
|
// 0000000000000000000000000000000000000000 for a dirty tree.
|
|
auto rev2 = input2.getRev().value_or(Hash(HashAlgorithm::SHA1));
|
|
attrs2.alloc("rev").mkString(rev2.gitRev());
|
|
attrs2.alloc("shortRev").mkString(rev2.gitRev().substr(0, 12));
|
|
if (auto revCount = input2.getRevCount())
|
|
attrs2.alloc("revCount").mkInt(*revCount);
|
|
v.mkAttrs(attrs2);
|
|
|
|
state.allowPath(storePath);
|
|
}
|
|
|
|
static RegisterPrimOp r_fetchMercurial({
|
|
.name = "fetchMercurial",
|
|
.arity = 1,
|
|
.fun = prim_fetchMercurial
|
|
});
|
|
|
|
}
|