Report substituter errors to clients of the Nix daemon
This commit is contained in:
parent
4d1b64f118
commit
c770a2422a
5 changed files with 53 additions and 30 deletions
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct OptimiseStats
|
||||||
struct RunningSubstituter
|
struct RunningSubstituter
|
||||||
{
|
{
|
||||||
Pid pid;
|
Pid pid;
|
||||||
AutoCloseFD to, from;
|
AutoCloseFD to, from, error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue