Skip to content

Commit

Permalink
primops: cleanup error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
LnL7 committed Jul 3, 2019
1 parent 8372a51 commit cfe3cbb
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 62 deletions.
62 changes: 33 additions & 29 deletions src/libexpr/primops/fetchGit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ struct GitInfo

std::regex revRegex("^[0-9a-fA-F]{40}$");

string runGit(const Strings & args)
{
try {
return runProgram("git", true, args);
} catch (ExecError & e) {
if (WEXITSTATUS(e.status) == 127)
throw ExecError(e.status,
"%s\n"
"The program 'git' is currently not installed. It is required for builtins.fetchGit\n"
"You can install it by running the following:\n"
"nix-env -f '<nixpkgs>' -iA git",
e.what());
throw;
}
}

GitInfo exportGit(ref<Store> store, const std::string & uri,
std::optional<std::string> ref, std::string rev,
const std::string & name)
Expand All @@ -37,7 +53,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
bool clean = true;

try {
runProgram("git", true, { "-C", uri, "diff-index", "--quiet", "HEAD", "--" });
runGit({ "-C", uri, "diff-index", "--quiet", "HEAD", "--" });
} catch (ExecError e) {
if (!WIFEXITED(e.status) || WEXITSTATUS(e.status) != 1) throw;
clean = false;
Expand All @@ -53,7 +69,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
gitInfo.shortRev = std::string(gitInfo.rev, 0, 7);

auto files = tokenizeString<std::set<std::string>>(
runProgram("git", true, { "-C", uri, "ls-files", "-z" }), "\0"s);
runGit({ "-C", uri, "ls-files", "-z" }), "\0"s);

PathFilter filter = [&](const Path & p) -> bool {
assert(hasPrefix(p, uri));
Expand All @@ -76,7 +92,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
}

// clean working tree, but no ref or rev specified. Use 'HEAD'.
rev = chomp(runProgram("git", true, { "-C", uri, "rev-parse", "HEAD" }));
rev = chomp(runGit({ "-C", uri, "rev-parse", "HEAD" }));
ref = "HEAD"s;
}

Expand All @@ -91,7 +107,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,

if (!pathExists(cacheDir)) {
createDirs(dirOf(cacheDir));
runProgram("git", true, { "init", "--bare", cacheDir });
runGit({ "init", "--bare", cacheDir });
}

Path localRefFile = cacheDir + "/refs/heads/" + *ref;
Expand All @@ -102,7 +118,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
repo. */
if (rev != "") {
try {
runProgram("git", true, { "-C", cacheDir, "cat-file", "-e", rev });
runGit({ "-C", cacheDir, "cat-file", "-e", rev });
doFetch = false;
} catch (ExecError & e) {
if (WIFEXITED(e.status)) {
Expand All @@ -124,7 +140,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,

// FIXME: git stderr messes up our progress indicator, so
// we're using --quiet for now. Should process its stderr.
runProgram("git", true, { "-C", cacheDir, "fetch", "--quiet", "--force", "--", uri, fmt("%s:%s", *ref, *ref) });
runGit({ "-C", cacheDir, "fetch", "--quiet", "--force", "--", uri, fmt("%s:%s", *ref, *ref) });

struct timeval times[2];
times[0].tv_sec = now;
Expand Down Expand Up @@ -164,7 +180,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,

// FIXME: should pipe this, or find some better way to extract a
// revision.
auto tar = runProgram("git", true, { "-C", cacheDir, "archive", gitInfo.rev });
auto tar = runGit({ "-C", cacheDir, "archive", gitInfo.rev });

Path tmpDir = createTempDir();
AutoDelete delTmpDir(tmpDir, true);
Expand All @@ -173,7 +189,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,

gitInfo.storePath = store->addToStore(name, tmpDir);

gitInfo.revCount = std::stoull(runProgram("git", true, { "-C", cacheDir, "rev-list", "--count", gitInfo.rev }));
gitInfo.revCount = std::stoull(runGit({ "-C", cacheDir, "rev-list", "--count", gitInfo.rev }));

nlohmann::json json;
json["storePath"] = gitInfo.storePath;
Expand Down Expand Up @@ -225,29 +241,17 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
// whitelist. Ah well.
state.checkURI(url);

try {
auto gitInfo = exportGit(state.store, url, ref, rev, name);
auto gitInfo = exportGit(state.store, url, ref, rev, name);

state.mkAttrs(v, 8);
mkString(*state.allocAttr(v, state.sOutPath), gitInfo.storePath, PathSet({gitInfo.storePath}));
mkString(*state.allocAttr(v, state.symbols.create("rev")), gitInfo.rev);
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev);
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount);
v.attrs->sort();
state.mkAttrs(v, 8);
mkString(*state.allocAttr(v, state.sOutPath), gitInfo.storePath, PathSet({gitInfo.storePath}));
mkString(*state.allocAttr(v, state.symbols.create("rev")), gitInfo.rev);
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev);
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount);
v.attrs->sort();

if (state.allowedPaths)
state.allowedPaths->insert(state.store->toRealPath(gitInfo.storePath));
} catch (ExecError & e) {
if (e.status / 256 == 127) {
std::ostringstream out;
out << e.what() << std::endl;
out << "The program 'git' is currently not installed. It is required for builtins.fetchGit" << std::endl;
out << "You can install it by running the following:" << std::endl;
out << "nix-env -f '<nixpkgs>' -iA git";
throw ExecError(e.status, out.str());
}
throw;
}
if (state.allowedPaths)
state.allowedPaths->insert(state.store->toRealPath(gitInfo.storePath));
}

static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);
Expand Down
70 changes: 37 additions & 33 deletions src/libexpr/primops/fetchMercurial.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ struct HgInfo

std::regex commitHashRegex("^[0-9a-fA-F]{40}$");

string runMercurial(const Strings & args)
{
try {
return runProgram("hg", true, args);
} catch (ExecError & e) {
if (WEXITSTATUS(e.status) == 127)
throw ExecError(e.status,
"%s\n"
"The program 'hg' is currently not installed. It is required for builtins.fetchMercurial\n"
"You can install it by running the following:\n"
"nix-env -f '<nixpkgs>' -iA mercurial",
e.what());
throw;
}
}

HgInfo exportMercurial(ref<Store> store, const std::string & uri,
std::string rev, const std::string & name)
{
Expand All @@ -32,7 +48,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,

if (rev == "" && hasPrefix(uri, "/") && pathExists(uri + "/.hg")) {

bool clean = runProgram("hg", true, { "status", "-R", uri, "--modified", "--added", "--removed" }) == "";
bool clean = runMercurial({ "status", "-R", uri, "--modified", "--added", "--removed" }) == "";

if (!clean) {

Expand All @@ -43,10 +59,10 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,

HgInfo hgInfo;
hgInfo.rev = "0000000000000000000000000000000000000000";
hgInfo.branch = chomp(runProgram("hg", true, { "branch", "-R", uri }));
hgInfo.branch = chomp(runMercurial({ "branch", "-R", uri }));

auto files = tokenizeString<std::set<std::string>>(
runProgram("hg", true, { "status", "-R", uri, "--clean", "--modified", "--added", "--no-status", "--print0" }), "\0"s);
runMercurial({ "status", "-R", uri, "--clean", "--modified", "--added", "--no-status", "--print0" }), "\0"s);

PathFilter filter = [&](const Path & p) -> bool {
assert(hasPrefix(p, uri));
Expand Down Expand Up @@ -94,29 +110,29 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,

if (pathExists(cacheDir)) {
try {
runProgram("hg", true, { "pull", "-R", cacheDir, "--", uri });
runMercurial({ "pull", "-R", cacheDir, "--", uri });
}
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, "--", uri });
runMercurial({ "recover", "-R", cacheDir });
runMercurial({ "pull", "-R", cacheDir, "--", uri });
} else {
throw ExecError(e.status, fmt("'hg pull' %s", statusToString(e.status)));
}
}
} else {
createDirs(dirOf(cacheDir));
runProgram("hg", true, { "clone", "--noupdate", "--", uri, cacheDir });
runMercurial({ "clone", "--noupdate", "--", uri, cacheDir });
}
}

writeFile(stampFile, "");
}

auto tokens = tokenizeString<std::vector<std::string>>(
runProgram("hg", true, { "log", "-R", cacheDir, "-r", rev, "--template", "{node} {rev} {branch}" }));
runMercurial({ "log", "-R", cacheDir, "-r", rev, "--template", "{node} {rev} {branch}" }));
assert(tokens.size() == 3);

HgInfo hgInfo;
Expand Down Expand Up @@ -146,7 +162,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string & uri,
Path tmpDir = createTempDir();
AutoDelete delTmpDir(tmpDir, true);

runProgram("hg", true, { "archive", "-R", cacheDir, "-r", rev, tmpDir });
runMercurial({ "archive", "-R", cacheDir, "-r", rev, tmpDir });

deletePath(tmpDir + "/.hg_archival.txt");

Expand Down Expand Up @@ -200,30 +216,18 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
// whitelist. Ah well.
state.checkURI(url);

try {
auto hgInfo = exportMercurial(state.store, url, rev, name);

state.mkAttrs(v, 8);
mkString(*state.allocAttr(v, state.sOutPath), hgInfo.storePath, PathSet({hgInfo.storePath}));
mkString(*state.allocAttr(v, state.symbols.create("branch")), hgInfo.branch);
mkString(*state.allocAttr(v, state.symbols.create("rev")), hgInfo.rev);
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), std::string(hgInfo.rev, 0, 12));
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), hgInfo.revCount);
v.attrs->sort();

if (state.allowedPaths)
state.allowedPaths->insert(state.store->toRealPath(hgInfo.storePath));
} catch (ExecError & e) {
if (e.status / 256 == 127) {
std::ostringstream out;
out << e.what() << std::endl;
out << "The program 'hg' is currently not installed. It is required for builtins.fetchMercurial" << std::endl;
out << "You can install it by running the following:" << std::endl;
out << "nix-env -f '<nixpkgs>' -iA mercurial";
throw ExecError(e.status, out.str());
}
throw;
}
auto hgInfo = exportMercurial(state.store, url, rev, name);

state.mkAttrs(v, 8);
mkString(*state.allocAttr(v, state.sOutPath), hgInfo.storePath, PathSet({hgInfo.storePath}));
mkString(*state.allocAttr(v, state.symbols.create("branch")), hgInfo.branch);
mkString(*state.allocAttr(v, state.symbols.create("rev")), hgInfo.rev);
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), std::string(hgInfo.rev, 0, 12));
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), hgInfo.revCount);
v.attrs->sort();

if (state.allowedPaths)
state.allowedPaths->insert(state.store->toRealPath(hgInfo.storePath));
}

static RegisterPrimOp r("fetchMercurial", 1, prim_fetchMercurial);
Expand Down

0 comments on commit cfe3cbb

Please sign in to comment.