aboutsummaryrefslogtreecommitdiff
path: root/src/libfetchers/mercurial.cc
diff options
context:
space:
mode:
authorLuke Granger-Brown <git@lukegb.com>2020-11-23 16:12:33 +0000
committerLuke Granger-Brown <git@lukegb.com>2020-11-23 16:12:33 +0000
commit226116f48272dbe25bb9d3b8fa138cf6b10ec8ef (patch)
treec796aa0073ba8c5b98284581e975ed01ac5f2e26 /src/libfetchers/mercurial.cc
parent1973669e868f4414b666d0fbd34f1a7a87322ae9 (diff)
fetchMercurial: set HGPLAIN when invoking hg
Without setting HGPLAIN, the user's environment leaks into hg invocations, which means that the output may not be in the expected format. HGPLAIN is the Mercurial-recommended solution for this in that it's intended for uses by scripts and programs which are looking to parse Mercurial's output in a consistent manner.
Diffstat (limited to 'src/libfetchers/mercurial.cc')
-rw-r--r--src/libfetchers/mercurial.cc54
1 files changed, 42 insertions, 12 deletions
diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc
index 41f60c45c..07a51059d 100644
--- a/src/libfetchers/mercurial.cc
+++ b/src/libfetchers/mercurial.cc
@@ -11,6 +11,36 @@ using namespace std::string_literals;
namespace nix::fetchers {
+namespace {
+
+RunOptions hgOptions(const Strings & args) {
+ RunOptions opts("hg", args);
+ opts.searchPath = true;
+
+ auto env = getEnv();
+ // Set HGPLAIN: this means we get consistent output from hg and avoids leakage from a user or system .hgrc.
+ env["HGPLAIN"] = "";
+ opts.environment = env;
+
+ return opts;
+}
+
+// runProgram wrapper that uses hgOptions instead of stock RunOptions.
+string runHg(const Strings & args, const std::optional<std::string> & input = {})
+{
+ RunOptions opts = hgOptions(args);
+ opts.input = input;
+
+ auto res = runProgram(opts);
+
+ if (!statusOk(res.first))
+ throw ExecError(res.first, fmt("hg %1%", statusToString(res.first)));
+
+ return res.second;
+}
+
+}
+
struct MercurialInputScheme : InputScheme
{
std::optional<Input> inputFromURL(const ParsedURL & url) override
@@ -100,11 +130,11 @@ struct MercurialInputScheme : InputScheme
assert(sourcePath);
// FIXME: shut up if file is already tracked.
- runProgram("hg", true,
+ runHg(
{ "add", *sourcePath + "/" + std::string(file) });
if (commitMsg)
- runProgram("hg", true,
+ runHg(
{ "commit", *sourcePath + "/" + std::string(file), "-m", *commitMsg });
}
@@ -130,7 +160,7 @@ struct MercurialInputScheme : InputScheme
if (!input.getRef() && !input.getRev() && isLocal && pathExists(actualUrl + "/.hg")) {
- bool clean = runProgram("hg", true, { "status", "-R", actualUrl, "--modified", "--added", "--removed" }) == "";
+ bool clean = runHg({ "status", "-R", actualUrl, "--modified", "--added", "--removed" }) == "";
if (!clean) {
@@ -143,10 +173,10 @@ struct MercurialInputScheme : InputScheme
if (settings.warnDirty)
warn("Mercurial tree '%s' is unclean", actualUrl);
- input.attrs.insert_or_assign("ref", chomp(runProgram("hg", true, { "branch", "-R", actualUrl })));
+ input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl })));
auto files = tokenizeString<std::set<std::string>>(
- runProgram("hg", true, { "status", "-R", actualUrl, "--clean", "--modified", "--added", "--no-status", "--print0" }), "\0"s);
+ runHg({ "status", "-R", actualUrl, "--clean", "--modified", "--added", "--no-status", "--print0" }), "\0"s);
PathFilter filter = [&](const Path & p) -> bool {
assert(hasPrefix(p, actualUrl));
@@ -224,33 +254,33 @@ struct MercurialInputScheme : InputScheme
if (!(input.getRev()
&& pathExists(cacheDir)
&& runProgram(
- RunOptions("hg", { "log", "-R", cacheDir, "-r", input.getRev()->gitRev(), "--template", "1" })
+ hgOptions({ "log", "-R", cacheDir, "-r", input.getRev()->gitRev(), "--template", "1" })
.killStderr(true)).second == "1"))
{
Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching Mercurial repository '%s'", actualUrl));
if (pathExists(cacheDir)) {
try {
- runProgram("hg", true, { "pull", "-R", cacheDir, "--", actualUrl });
+ runHg({ "pull", "-R", cacheDir, "--", actualUrl });
}
catch (ExecError & e) {
string transJournal = cacheDir + "/.hg/store/journal";
/* hg throws "abandoned transaction" error only if this file exists */
if (pathExists(transJournal)) {
- runProgram("hg", true, { "recover", "-R", cacheDir });
- runProgram("hg", true, { "pull", "-R", cacheDir, "--", actualUrl });
+ runHg({ "recover", "-R", cacheDir });
+ runHg({ "pull", "-R", cacheDir, "--", actualUrl });
} else {
throw ExecError(e.status, fmt("'hg pull' %s", statusToString(e.status)));
}
}
} else {
createDirs(dirOf(cacheDir));
- runProgram("hg", true, { "clone", "--noupdate", "--", actualUrl, cacheDir });
+ runHg({ "clone", "--noupdate", "--", actualUrl, cacheDir });
}
}
auto tokens = tokenizeString<std::vector<std::string>>(
- runProgram("hg", true, { "log", "-R", cacheDir, "-r", revOrRef, "--template", "{node} {rev} {branch}" }));
+ runHg({ "log", "-R", cacheDir, "-r", revOrRef, "--template", "{node} {rev} {branch}" }));
assert(tokens.size() == 3);
input.attrs.insert_or_assign("rev", Hash::parseAny(tokens[0], htSHA1).gitRev());
@@ -263,7 +293,7 @@ struct MercurialInputScheme : InputScheme
Path tmpDir = createTempDir();
AutoDelete delTmpDir(tmpDir, true);
- runProgram("hg", true, { "archive", "-R", cacheDir, "-r", input.getRev()->gitRev(), tmpDir });
+ runHg({ "archive", "-R", cacheDir, "-r", input.getRev()->gitRev(), tmpDir });
deletePath(tmpDir + "/.hg_archival.txt");