* Make nix-env --dry-run print the paths to be substituted correctly

again.  (After the previous substituter mechanism refactoring I
  didn't update the code that obtains the references of substitutable
  paths.)  This required some refactoring: the substituter programs
  are now kept running and receive/respond to info requests via
  stdin/stdout.
This commit is contained in:
Eelco Dolstra 2008-08-02 12:54:35 +00:00
parent fc691e1cbd
commit 3c92ea399d
14 changed files with 338 additions and 272 deletions

View file

@ -83,6 +83,13 @@ LocalStore::~LocalStore()
{
try {
flushDelayedUpdates();
foreach (RunningSubstituters::iterator, i, runningSubstituters) {
i->second.toBuf.reset();
i->second.to.reset();
i->second.pid.wait(true);
}
} catch (...) {
ignoreException();
}
@ -367,8 +374,6 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
std::map<Path, ValidPathInfo>::iterator lookup = pathInfoCache.find(path);
if (lookup != pathInfoCache.end()) return lookup->second;
//printMsg(lvlError, "queryPathInfo: " + path);
/* Read the info file. */
Path infoFile = infoFileFor(path);
if (!pathExists(infoFile))
@ -467,33 +472,105 @@ Path LocalStore::queryDeriver(const Path & path)
}
PathSet LocalStore::querySubstitutablePaths()
void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter & run)
{
if (!substitutablePathsLoaded) {
for (Paths::iterator i = substituters.begin(); i != substituters.end(); ++i) {
debug(format("running `%1%' to find out substitutable paths") % *i);
Strings args;
args.push_back("--query-paths");
Strings ss = tokenizeString(runProgram(*i, false, args), "\n");
for (Strings::iterator j = ss.begin(); j != ss.end(); ++j) {
if (!isStorePath(*j))
throw Error(format("`%1%' returned a bad substitutable path `%2%'")
% *i % *j);
substitutablePaths.insert(*j);
}
if (run.pid != -1) return;
debug(format("starting substituter program `%1%'") % substituter);
Pipe toPipe, fromPipe;
toPipe.create();
fromPipe.create();
run.pid = fork();
switch (run.pid) {
case -1:
throw SysError("unable to fork");
case 0: /* child */
try {
fromPipe.readSide.close();
toPipe.writeSide.close();
if (dup2(toPipe.readSide, STDIN_FILENO) == -1)
throw SysError("dupping stdin");
if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)
throw SysError("dupping stdout");
closeMostFDs(set<int>());
execl(substituter.c_str(), substituter.c_str(), "--query", NULL);
throw SysError(format("executing `%1%'") % substituter);
} catch (std::exception & e) {
std::cerr << "error: " << e.what() << std::endl;
}
substitutablePathsLoaded = true;
quickExit(1);
}
return substitutablePaths;
/* Parent. */
toPipe.readSide.close();
fromPipe.writeSide.close();
run.toBuf = boost::shared_ptr<stdio_filebuf>(new stdio_filebuf(toPipe.writeSide.borrow(), std::ios_base::out));
run.to = boost::shared_ptr<std::ostream>(new std::ostream(&*run.toBuf));
run.fromBuf = boost::shared_ptr<stdio_filebuf>(new stdio_filebuf(fromPipe.readSide.borrow(), std::ios_base::in));
run.from = boost::shared_ptr<std::istream>(new std::istream(&*run.fromBuf));
}
bool LocalStore::hasSubstitutes(const Path & path)
{
if (!substitutablePathsLoaded)
querySubstitutablePaths();
return substitutablePaths.find(path) != substitutablePaths.end();
foreach (Paths::iterator, i, substituters) {
RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run);
*run.to << "have\n" << path << "\n" << std::flush;
string s;
int res;
getline(*run.from, s);
if (!string2Int(s, res)) abort();
if (res) return true;
}
return false;
}
bool LocalStore::querySubstitutablePathInfo(const Path & path,
SubstitutablePathInfo & info)
{
foreach (Paths::iterator, i, substituters) {
RunningSubstituter & run(runningSubstituters[*i]);
startSubstituter(*i, run);
*run.to << "info\n" << path << "\n" << std::flush;
string s;
int res;
getline(*run.from, s);
if (!string2Int(s, res)) abort();
if (res) {
getline(*run.from, info.deriver);
int nrRefs;
getline(*run.from, s);
if (!string2Int(s, nrRefs)) abort();
while (nrRefs--) {
Path p; getline(*run.from, p);
info.references.insert(p);
}
info.downloadSize = 0;
return true;
}
}
return false;
}