Report substituter errors to clients of the Nix daemon

This commit is contained in:
Eelco Dolstra 2012-08-01 11:19:24 -04:00
parent 4d1b64f118
commit c770a2422a
5 changed files with 53 additions and 30 deletions

View File

@ -184,13 +184,9 @@ sub getAvailableCaches {
my @trustedUrls = (@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // "")); my @trustedUrls = (@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // ""));
@urls = (); @urls = ();
foreach my $url (@untrustedUrls) { foreach my $url (@untrustedUrls) {
if (any { $url eq $_ } @trustedUrls) { die "binary cache $url is not trusted (please add it to trusted-binary-caches in $Nix::Config::confDir/nix.conf)\n"
push @urls, $url; unless any { $url eq $_ } @trustedUrls;
} else { push @urls, $url;
# FIXME: should die here, but we currently can't
# deliver error messages to clients.
warn "warning: binary cache $url is not trusted (please add it to trusted-binary-caches in $Nix::Config::confDir/nix.conf)\n";
}
} }
} }

View File

@ -909,10 +909,11 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
debug(format("starting substituter program `%1%'") % substituter); debug(format("starting substituter program `%1%'") % substituter);
Pipe toPipe, fromPipe; Pipe toPipe, fromPipe, errorPipe;
toPipe.create(); toPipe.create();
fromPipe.create(); fromPipe.create();
errorPipe.create();
run.pid = fork(); run.pid = fork();
@ -940,6 +941,8 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
throw SysError("dupping stdin"); throw SysError("dupping stdin");
if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1) if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)
throw SysError("dupping stdout"); throw SysError("dupping stdout");
if (dup2(errorPipe.writeSide, STDERR_FILENO) == -1)
throw SysError("dupping stderr");
closeMostFDs(set<int>()); closeMostFDs(set<int>());
execl(substituter.c_str(), substituter.c_str(), "--query", NULL); execl(substituter.c_str(), substituter.c_str(), "--query", NULL);
throw SysError(format("executing `%1%'") % substituter); throw SysError(format("executing `%1%'") % substituter);
@ -953,6 +956,7 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
run.to = toPipe.writeSide.borrow(); run.to = toPipe.writeSide.borrow();
run.from = fromPipe.readSide.borrow(); run.from = fromPipe.readSide.borrow();
run.error = errorPipe.readSide.borrow();
} }
@ -973,13 +977,21 @@ PathSet LocalStore::querySubstitutablePaths(const PathSet & paths)
RunningSubstituter & run(runningSubstituters[*i]); RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run); startSubstituter(*i, run);
string s = "have "; string s = "have ";
foreach (PathSet::const_iterator, i, paths) foreach (PathSet::const_iterator, j, paths)
if (res.find(*i) == res.end()) { s += *i; s += " "; } if (res.find(*j) == res.end()) { s += *j; s += " "; }
writeLine(run.to, s); writeLine(run.to, s);
while (true) { while (true) {
Path path = readLine(run.from); /* FIXME: we only read stderr when an error occurs, so
if (path == "") break; substituters should only write (short) messages to
res.insert(path); stderr when they fail. I.e. they shouldn't write debug
output. */
try {
Path path = readLine(run.from);
if (path == "") break;
res.insert(path);
} catch (EndOfFile e) {
throw Error(format("substituter `%1%' failed: %2%") % *i % chomp(drainFD(run.error)));
}
} }
} }
return res; return res;
@ -998,22 +1010,26 @@ void LocalStore::querySubstitutablePathInfos(const Path & substituter,
writeLine(run.to, s); writeLine(run.to, s);
while (true) { while (true) {
Path path = readLine(run.from); try {
if (path == "") break; Path path = readLine(run.from);
if (paths.find(path) == paths.end()) if (path == "") break;
throw Error(format("got unexpected path `%1%' from substituter") % path); if (paths.find(path) == paths.end())
paths.erase(path); throw Error(format("got unexpected path `%1%' from substituter") % path);
SubstitutablePathInfo & info(infos[path]); paths.erase(path);
info.deriver = readLine(run.from); SubstitutablePathInfo & info(infos[path]);
if (info.deriver != "") assertStorePath(info.deriver); info.deriver = readLine(run.from);
int nrRefs = getIntLine<int>(run.from); if (info.deriver != "") assertStorePath(info.deriver);
while (nrRefs--) { int nrRefs = getIntLine<int>(run.from);
Path p = readLine(run.from); while (nrRefs--) {
assertStorePath(p); Path p = readLine(run.from);
info.references.insert(p); assertStorePath(p);
info.references.insert(p);
}
info.downloadSize = getIntLine<long long>(run.from);
info.narSize = getIntLine<long long>(run.from);
} catch (EndOfFile e) {
throw Error(format("substituter `%1%' failed: %2%") % substituter % chomp(drainFD(run.error)));
} }
info.downloadSize = getIntLine<long long>(run.from);
info.narSize = getIntLine<long long>(run.from);
} }
} }

View File

@ -45,7 +45,7 @@ struct OptimiseStats
struct RunningSubstituter struct RunningSubstituter
{ {
Pid pid; Pid pid;
AutoCloseFD to, from; AutoCloseFD to, from, error;
}; };

View File

@ -253,7 +253,7 @@ string readLine(int fd)
if (errno != EINTR) if (errno != EINTR)
throw SysError("reading a line"); throw SysError("reading a line");
} else if (rd == 0) } else if (rd == 0)
throw Error("unexpected EOF reading a line"); throw EndOfFile("unexpected EOF reading a line");
else { else {
if (ch == '\n') return s; if (ch == '\n') return s;
s += ch; s += ch;
@ -1015,6 +1015,13 @@ string concatStringsSep(const string & sep, const Strings & ss)
} }
string chomp(const string & s)
{
size_t i = s.find_last_not_of(" \n\r\t");
return i == string::npos ? "" : string(s, 0, i);
}
string statusToString(int status) string statusToString(int status)
{ {
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {

View File

@ -292,6 +292,10 @@ Strings tokenizeString(const string & s, const string & separators = " \t\n\r");
string concatStringsSep(const string & sep, const Strings & ss); string concatStringsSep(const string & sep, const Strings & ss);
/* Remove trailing whitespace from a string. */
string chomp(const string & s);
/* Convert the exit status of a child as returned by wait() into an /* Convert the exit status of a child as returned by wait() into an
error string. */ error string. */
string statusToString(int status); string statusToString(int status);