1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#include "lix/libexpr/primops.hh"
#include "lix/libexpr/eval-settings.hh"
#include "lix/libfetchers/fetchers.hh"
#include "lix/libutil/url-parts.hh"
namespace nix {
Value prim_fetchMercurial(EvalState & state, Value ** args)
{
std::string url;
std::optional<Hash> rev;
std::optional<std::string> ref;
std::string_view name = "source";
NixStringContext context;
state.forceValue(*args[0], noPos);
if (args[0]->type() == nAttrs) {
for (auto & attr : *args[0]->attrs()) {
std::string_view n(state.ctx.symbols[attr.name]);
if (n == "url")
url = state
.coerceToString(
attr.pos,
attr.value,
context,
"while evaluating the `url` attribute passed to "
"builtins.fetchMercurial",
StringCoercionMode::Strict,
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, HashType::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.ctx.errors
.make<EvalError>(
"unsupported argument '%s' to 'fetchMercurial'",
state.ctx.symbols[attr.name]
)
.atPos(attr.pos)
.debugThrow();
}
}
if (url.empty())
state.ctx.errors.make<EvalError>("'url' argument required").debugThrow();
} else
url = state.coerceToString(noPos, *args[0], context,
"while evaluating the first argument passed to builtins.fetchMercurial",
StringCoercionMode::Strict, false).toOwned();
// FIXME: git externals probably can be used to bypass the URI
// whitelist. Ah well.
state.ctx.paths.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 [tree, input2] = state.aio.blockOn(input.fetch(state.ctx.store));
auto attrs2 = state.ctx.buildBindings(8);
attrs2.insert(state.ctx.symbols.sym_outPath, state.ctx.paths.mkStorePathString(tree.storePath));
if (input2.getRef())
attrs2.insert("branch", {NewValueAs::string, *input2.getRef()});
// Backward compatibility: set 'rev' to
// 0000000000000000000000000000000000000000 for a dirty tree.
auto rev2 = input2.getRev().value_or(Hash(HashType::SHA1));
attrs2.insert("rev", {NewValueAs::string, rev2.gitRev()});
attrs2.insert("shortRev", {NewValueAs::string, rev2.gitRev().substr(0, 12)});
if (auto revCount = input2.getRevCount())
attrs2.insert("revCount", {NewValueAs::integer, NixInt::Inner(*revCount)});
state.ctx.paths.allowPath(tree.storePath);
return {NewValueAs::attrs, attrs2};
}
}
|