2017-11-01 15:32:53 +00:00
|
|
|
#include "primops.hh"
|
|
|
|
#include "eval-inline.hh"
|
|
|
|
#include "store-api.hh"
|
2020-03-30 14:04:18 +00:00
|
|
|
#include "fetchers.hh"
|
|
|
|
#include "url.hh"
|
2017-11-01 15:32:53 +00:00
|
|
|
|
|
|
|
#include <regex>
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
|
|
|
{
|
|
|
|
std::string url;
|
2020-03-30 14:04:18 +00:00
|
|
|
std::optional<Hash> rev;
|
|
|
|
std::optional<std::string> ref;
|
2017-11-01 15:32:53 +00:00
|
|
|
std::string name = "source";
|
|
|
|
PathSet context;
|
|
|
|
|
|
|
|
state.forceValue(*args[0]);
|
|
|
|
|
|
|
|
if (args[0]->type == tAttrs) {
|
|
|
|
|
|
|
|
state.forceAttrs(*args[0], pos);
|
|
|
|
|
|
|
|
for (auto & attr : *args[0]->attrs) {
|
|
|
|
string n(attr.name);
|
|
|
|
if (n == "url")
|
|
|
|
url = state.coerceToString(*attr.pos, *attr.value, context, false, false);
|
2020-03-30 14:04:18 +00:00
|
|
|
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);
|
|
|
|
if (std::regex_match(value, revRegex))
|
|
|
|
rev = Hash(value, htSHA1);
|
|
|
|
else
|
|
|
|
ref = value;
|
|
|
|
}
|
2017-11-01 15:32:53 +00:00
|
|
|
else if (n == "name")
|
|
|
|
name = state.forceStringNoCtx(*attr.value, *attr.pos);
|
|
|
|
else
|
2017-11-02 22:37:42 +00:00
|
|
|
throw EvalError("unsupported argument '%s' to 'fetchMercurial', at %s", attr.name, *attr.pos);
|
2017-11-01 15:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (url.empty())
|
|
|
|
throw EvalError(format("'url' argument required, at %1%") % pos);
|
|
|
|
|
|
|
|
} else
|
|
|
|
url = state.coerceToString(pos, *args[0], context, false, false);
|
|
|
|
|
|
|
|
// FIXME: git externals probably can be used to bypass the URI
|
|
|
|
// whitelist. Ah well.
|
|
|
|
state.checkURI(url);
|
|
|
|
|
2020-03-30 14:04:18 +00:00
|
|
|
if (evalSettings.pureEval && !rev)
|
|
|
|
throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision");
|
|
|
|
|
|
|
|
auto parsedUrl = parseURL(
|
|
|
|
url.find("://") != std::string::npos
|
|
|
|
? "hg+" + url
|
|
|
|
: "hg+file://" + url);
|
|
|
|
if (rev) parsedUrl.query.insert_or_assign("rev", rev->gitRev());
|
|
|
|
if (ref) parsedUrl.query.insert_or_assign("ref", *ref);
|
|
|
|
// FIXME: use name
|
|
|
|
auto input = fetchers::inputFromURL(parsedUrl);
|
|
|
|
|
|
|
|
auto [tree, input2] = input->fetchTree(state.store);
|
2017-11-01 15:32:53 +00:00
|
|
|
|
|
|
|
state.mkAttrs(v, 8);
|
2020-03-30 14:04:18 +00:00
|
|
|
auto storePath = state.store->printStorePath(tree.storePath);
|
|
|
|
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
|
|
|
|
if (input2->getRef())
|
|
|
|
mkString(*state.allocAttr(v, state.symbols.create("branch")), *input2->getRef());
|
|
|
|
// Backward compatibility: set 'rev' to
|
|
|
|
// 0000000000000000000000000000000000000000 for a dirty tree.
|
|
|
|
auto rev2 = input2->getRev().value_or(Hash(htSHA1));
|
|
|
|
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev2.gitRev());
|
|
|
|
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), std::string(rev2.gitRev(), 0, 12));
|
|
|
|
if (tree.info.revCount)
|
|
|
|
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *tree.info.revCount);
|
2017-11-01 15:32:53 +00:00
|
|
|
v.attrs->sort();
|
2018-01-16 17:50:38 +00:00
|
|
|
|
|
|
|
if (state.allowedPaths)
|
2020-03-30 14:04:18 +00:00
|
|
|
state.allowedPaths->insert(tree.actualPath);
|
2017-11-01 15:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static RegisterPrimOp r("fetchMercurial", 1, prim_fetchMercurial);
|
|
|
|
|
|
|
|
}
|