forked from lix-project/lix
* Some refactoring.
* Throw more exceptions as BuildErrors instead of Errors. This matters when --keep-going is turned on. (A BuildError is caught and terminates the goal in question, an Error terminates the program.)
This commit is contained in:
parent
9dbfe242e3
commit
06c4929958
|
@ -99,7 +99,7 @@ public:
|
||||||
|
|
||||||
void addWaitee(GoalPtr waitee);
|
void addWaitee(GoalPtr waitee);
|
||||||
|
|
||||||
virtual void waiteeDone(GoalPtr waitee, bool success);
|
virtual void waiteeDone(GoalPtr waitee, ExitCode result);
|
||||||
|
|
||||||
virtual void handleChildOutput(int fd, const string & data)
|
virtual void handleChildOutput(int fd, const string & data)
|
||||||
{
|
{
|
||||||
|
@ -123,8 +123,13 @@ public:
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cancel()
|
||||||
|
{
|
||||||
|
amDone(ecFailed);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void amDone(bool success = true);
|
void amDone(ExitCode result);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -189,13 +194,24 @@ public:
|
||||||
/* Can we start another child process? */
|
/* Can we start another child process? */
|
||||||
bool canBuildMore();
|
bool canBuildMore();
|
||||||
|
|
||||||
/* Registers / unregisters a running child process. */
|
/* Registers a running child process. `inBuildSlot' means that
|
||||||
|
the process counts towards the jobs limit. */
|
||||||
void childStarted(GoalPtr goal, pid_t pid,
|
void childStarted(GoalPtr goal, pid_t pid,
|
||||||
const set<int> & fds, bool inBuildSlot);
|
const set<int> & fds, bool inBuildSlot);
|
||||||
|
|
||||||
|
/* Unregisters a running child process. `wakeSleepers' should be
|
||||||
|
false if there is no sense in waking up goals that are sleeping
|
||||||
|
because they can't run yet (e.g., there is no free build slot,
|
||||||
|
or the hook would still say `postpone'). */
|
||||||
void childTerminated(pid_t pid, bool wakeSleepers = true);
|
void childTerminated(pid_t pid, bool wakeSleepers = true);
|
||||||
|
|
||||||
/* Add a goal to the set of goals waiting for a build slot. */
|
/* Put `goal' to sleep until a build slot becomes available (which
|
||||||
void waitForBuildSlot(GoalPtr goal, bool reallyWait = false);
|
might be right away). */
|
||||||
|
void waitForBuildSlot(GoalPtr goal);
|
||||||
|
|
||||||
|
/* Put `goal' to sleep until a child process terminates, i.e., a
|
||||||
|
call is made to childTerminate(..., true). */
|
||||||
|
void waitForChildTermination(GoalPtr goal);
|
||||||
|
|
||||||
/* Loop until the specified top-level goals have finished. */
|
/* Loop until the specified top-level goals have finished. */
|
||||||
void run(const Goals & topGoals);
|
void run(const Goals & topGoals);
|
||||||
|
@ -205,19 +221,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SubstError : public Error
|
MakeError(SubstError, Error)
|
||||||
{
|
MakeError(BuildError, Error)
|
||||||
public:
|
|
||||||
SubstError(const format & f) : Error(f) { };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class BuildError : public Error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BuildError(const format & f) : Error(f) { };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -230,7 +235,7 @@ void Goal::addWaitee(GoalPtr waitee)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Goal::waiteeDone(GoalPtr waitee, bool success)
|
void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
|
||||||
{
|
{
|
||||||
assert(waitees.find(waitee) != waitees.end());
|
assert(waitees.find(waitee) != waitees.end());
|
||||||
waitees.erase(waitee);
|
waitees.erase(waitee);
|
||||||
|
@ -238,9 +243,9 @@ void Goal::waiteeDone(GoalPtr waitee, bool success)
|
||||||
trace(format("waitee `%1%' done; %2% left") %
|
trace(format("waitee `%1%' done; %2% left") %
|
||||||
waitee->name % waitees.size());
|
waitee->name % waitees.size());
|
||||||
|
|
||||||
if (!success) ++nrFailed;
|
if (result == ecFailed) ++nrFailed;
|
||||||
|
|
||||||
if (waitees.empty() || (!success && !keepGoing)) {
|
if (waitees.empty() || (result == ecFailed && !keepGoing)) {
|
||||||
|
|
||||||
/* If we failed and keepGoing is not set, we remove all
|
/* If we failed and keepGoing is not set, we remove all
|
||||||
remaining waitees. */
|
remaining waitees. */
|
||||||
|
@ -260,14 +265,15 @@ void Goal::waiteeDone(GoalPtr waitee, bool success)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Goal::amDone(bool success)
|
void Goal::amDone(ExitCode result)
|
||||||
{
|
{
|
||||||
trace("done");
|
trace("done");
|
||||||
assert(exitCode == ecBusy);
|
assert(exitCode == ecBusy);
|
||||||
exitCode = success ? ecSuccess : ecFailed;
|
assert(result == ecSuccess || result == ecFailed);
|
||||||
|
exitCode = result;
|
||||||
for (WeakGoals::iterator i = waiters.begin(); i != waiters.end(); ++i) {
|
for (WeakGoals::iterator i = waiters.begin(); i != waiters.end(); ++i) {
|
||||||
GoalPtr goal = i->lock();
|
GoalPtr goal = i->lock();
|
||||||
if (goal) goal->waiteeDone(shared_from_this(), success);
|
if (goal) goal->waiteeDone(shared_from_this(), result);
|
||||||
}
|
}
|
||||||
waiters.clear();
|
waiters.clear();
|
||||||
worker.removeGoal(shared_from_this());
|
worker.removeGoal(shared_from_this());
|
||||||
|
@ -439,7 +445,7 @@ void UserLock::acquire()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error(format("all build users are currently in use; "
|
throw BuildError(format("all build users are currently in use; "
|
||||||
"consider creating additional users and adding them to the `%1%' group")
|
"consider creating additional users and adding them to the `%1%' group")
|
||||||
% buildUsersGroup);
|
% buildUsersGroup);
|
||||||
}
|
}
|
||||||
|
@ -715,7 +721,7 @@ void DerivationGoal::haveDerivation()
|
||||||
printMsg(lvlError,
|
printMsg(lvlError,
|
||||||
format("cannot build missing derivation `%1%'")
|
format("cannot build missing derivation `%1%'")
|
||||||
% drvPath);
|
% drvPath);
|
||||||
amDone(false);
|
amDone(ecFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,7 +739,7 @@ void DerivationGoal::haveDerivation()
|
||||||
|
|
||||||
/* If they are all valid, then we're done. */
|
/* If they are all valid, then we're done. */
|
||||||
if (invalidOutputs.size() == 0) {
|
if (invalidOutputs.size() == 0) {
|
||||||
amDone(true);
|
amDone(ecSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,7 +770,7 @@ void DerivationGoal::outputsSubstituted()
|
||||||
nrFailed = 0;
|
nrFailed = 0;
|
||||||
|
|
||||||
if (checkPathValidity(false).size() == 0) {
|
if (checkPathValidity(false).size() == 0) {
|
||||||
amDone(true);
|
amDone(ecSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,7 +800,7 @@ void DerivationGoal::inputsRealised()
|
||||||
format("cannot build derivation `%1%': "
|
format("cannot build derivation `%1%': "
|
||||||
"%2% inputs could not be realised")
|
"%2% inputs could not be realised")
|
||||||
% drvPath % nrFailed);
|
% drvPath % nrFailed);
|
||||||
amDone(false);
|
amDone(ecFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,14 +827,14 @@ void DerivationGoal::tryToBuild()
|
||||||
return;
|
return;
|
||||||
case rpPostpone:
|
case rpPostpone:
|
||||||
/* Not now; wait until at least one child finishes. */
|
/* Not now; wait until at least one child finishes. */
|
||||||
worker.waitForBuildSlot(shared_from_this(), true);
|
worker.waitForChildTermination(shared_from_this());
|
||||||
return;
|
return;
|
||||||
case rpDecline:
|
case rpDecline:
|
||||||
/* We should do it ourselves. */
|
/* We should do it ourselves. */
|
||||||
break;
|
break;
|
||||||
case rpDone:
|
case rpDone:
|
||||||
/* Somebody else did it. */
|
/* Somebody else did it. */
|
||||||
amDone();
|
amDone(ecSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,7 +847,7 @@ void DerivationGoal::tryToBuild()
|
||||||
/* Acquire locks and such. If we then see that the build has
|
/* Acquire locks and such. If we then see that the build has
|
||||||
been done by somebody else, we're done. */
|
been done by somebody else, we're done. */
|
||||||
if (!prepareBuild()) {
|
if (!prepareBuild()) {
|
||||||
amDone();
|
amDone(ecSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,7 +856,7 @@ void DerivationGoal::tryToBuild()
|
||||||
|
|
||||||
} catch (BuildError & e) {
|
} catch (BuildError & e) {
|
||||||
printMsg(lvlError, e.msg());
|
printMsg(lvlError, e.msg());
|
||||||
amDone(false);
|
amDone(ecFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,61 +898,62 @@ void DerivationGoal::buildDone()
|
||||||
if (buildUser.enabled())
|
if (buildUser.enabled())
|
||||||
buildUser.kill();
|
buildUser.kill();
|
||||||
|
|
||||||
/* Some cleanup per path. We do this here and not in
|
try {
|
||||||
computeClosure() for convenience when the build has failed. */
|
|
||||||
for (DerivationOutputs::iterator i = drv.outputs.begin();
|
|
||||||
i != drv.outputs.end(); ++i)
|
|
||||||
{
|
|
||||||
Path path = i->second.path;
|
|
||||||
if (!pathExists(path)) continue;
|
|
||||||
|
|
||||||
struct stat st;
|
/* Some cleanup per path. We do this here and not in
|
||||||
if (lstat(path.c_str(), &st))
|
computeClosure() for convenience when the build has
|
||||||
throw SysError(format("getting attributes of path `%1%'") % path);
|
failed. */
|
||||||
|
for (DerivationOutputs::iterator i = drv.outputs.begin();
|
||||||
|
i != drv.outputs.end(); ++i)
|
||||||
|
{
|
||||||
|
Path path = i->second.path;
|
||||||
|
if (!pathExists(path)) continue;
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (lstat(path.c_str(), &st) == -1)
|
||||||
|
throw SysError(format("getting attributes of path `%1%'") % path);
|
||||||
|
|
||||||
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
||||||
/* Check that the output is not group or world writable, as
|
/* Check that the output is not group or world writable,
|
||||||
that means that someone else can have interfered with the
|
as that means that someone else can have interfered
|
||||||
build. Also, the output should be owned by the build
|
with the build. Also, the output should be owned by
|
||||||
user. */
|
the build user. */
|
||||||
if ((st.st_mode & (S_IWGRP | S_IWOTH)) ||
|
if ((st.st_mode & (S_IWGRP | S_IWOTH)) ||
|
||||||
(buildUser.enabled() && st.st_uid != buildUser.getUID()))
|
(buildUser.enabled() && st.st_uid != buildUser.getUID()))
|
||||||
throw Error(format("suspicious ownership or permission on `%1%'; rejecting this build output") % path);
|
throw BuildError(format("suspicious ownership or permission on `%1%'; rejecting this build output") % path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Gain ownership of the build result using the setuid wrapper
|
/* Gain ownership of the build result using the setuid
|
||||||
if we're not root. If we *are* root, then
|
wrapper if we're not root. If we *are* root, then
|
||||||
canonicalisePathMetaData() will take care of this later
|
canonicalisePathMetaData() will take care of this later
|
||||||
on. */
|
on. */
|
||||||
if (buildUser.enabled() && !amPrivileged())
|
if (buildUser.enabled() && !amPrivileged())
|
||||||
getOwnership(path);
|
getOwnership(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the exit status. */
|
/* Check the exit status. */
|
||||||
if (!statusOk(status)) {
|
if (!statusOk(status)) {
|
||||||
deleteTmpDir(false);
|
deleteTmpDir(false);
|
||||||
printMsg(lvlError, format("builder for `%1%' %2%")
|
throw BuildError(format("builder for `%1%' %2%")
|
||||||
% drvPath % statusToString(status));
|
% drvPath % statusToString(status));
|
||||||
amDone(false);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteTmpDir(true);
|
deleteTmpDir(true);
|
||||||
|
|
||||||
/* Compute the FS closure of the outputs and register them as
|
/* Compute the FS closure of the outputs and register them as
|
||||||
being valid. */
|
being valid. */
|
||||||
try {
|
|
||||||
computeClosure();
|
computeClosure();
|
||||||
|
|
||||||
} catch (BuildError & e) {
|
} catch (BuildError & e) {
|
||||||
printMsg(lvlError, e.msg());
|
printMsg(lvlError, e.msg());
|
||||||
amDone(false);
|
amDone(ecFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the build user, if applicable. */
|
/* Release the build user, if applicable. */
|
||||||
buildUser.release();
|
buildUser.release();
|
||||||
|
|
||||||
amDone();
|
amDone(ecSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1184,6 +1191,8 @@ void DerivationGoal::terminateBuildHook()
|
||||||
debug("terminating build hook");
|
debug("terminating build hook");
|
||||||
pid_t savedPid = pid;
|
pid_t savedPid = pid;
|
||||||
pid.wait(true);
|
pid.wait(true);
|
||||||
|
/* `false' means don't wake up waiting goals, since we want to
|
||||||
|
keep this build slot ourselves (at least if the hook reply XXX. */
|
||||||
worker.childTerminated(savedPid, false);
|
worker.childTerminated(savedPid, false);
|
||||||
fromHook.readSide.close();
|
fromHook.readSide.close();
|
||||||
toHook.writeSide.close();
|
toHook.writeSide.close();
|
||||||
|
@ -1218,7 +1227,7 @@ bool DerivationGoal::prepareBuild()
|
||||||
|
|
||||||
if (validPaths.size() > 0) {
|
if (validPaths.size() > 0) {
|
||||||
/* !!! fix this; try to delete valid paths */
|
/* !!! fix this; try to delete valid paths */
|
||||||
throw Error(
|
throw BuildError(
|
||||||
format("derivation `%1%' is blocked by its output paths")
|
format("derivation `%1%' is blocked by its output paths")
|
||||||
% drvPath);
|
% drvPath);
|
||||||
}
|
}
|
||||||
|
@ -1250,7 +1259,7 @@ bool DerivationGoal::prepareBuild()
|
||||||
if (inDrv.outputs.find(*j) != inDrv.outputs.end())
|
if (inDrv.outputs.find(*j) != inDrv.outputs.end())
|
||||||
computeFSClosure(inDrv.outputs[*j].path, inputPaths);
|
computeFSClosure(inDrv.outputs[*j].path, inputPaths);
|
||||||
else
|
else
|
||||||
throw Error(
|
throw BuildError(
|
||||||
format("derivation `%1%' requires non-existent output `%2%' from input derivation `%3%'")
|
format("derivation `%1%' requires non-existent output `%2%' from input derivation `%3%'")
|
||||||
% drvPath % *j % i->first);
|
% drvPath % *j % i->first);
|
||||||
}
|
}
|
||||||
|
@ -1286,7 +1295,7 @@ void DerivationGoal::startBuilder()
|
||||||
{
|
{
|
||||||
Path path = i->second.path;
|
Path path = i->second.path;
|
||||||
if (store->isValidPath(path))
|
if (store->isValidPath(path))
|
||||||
throw Error(format("obstructed build: path `%1%' exists") % path);
|
throw BuildError(format("obstructed build: path `%1%' exists") % path);
|
||||||
if (pathExists(path)) {
|
if (pathExists(path)) {
|
||||||
debug(format("removing unregistered path `%1%'") % path);
|
debug(format("removing unregistered path `%1%'") % path);
|
||||||
deletePathWrapped(path);
|
deletePathWrapped(path);
|
||||||
|
@ -1368,12 +1377,12 @@ void DerivationGoal::startBuilder()
|
||||||
string s = drv.env["exportReferencesGraph"];
|
string s = drv.env["exportReferencesGraph"];
|
||||||
Strings ss = tokenizeString(s);
|
Strings ss = tokenizeString(s);
|
||||||
if (ss.size() % 2 != 0)
|
if (ss.size() % 2 != 0)
|
||||||
throw Error(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s);
|
throw BuildError(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s);
|
||||||
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
|
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
|
||||||
string fileName = *i++;
|
string fileName = *i++;
|
||||||
Path storePath = *i++;
|
Path storePath = *i++;
|
||||||
if (!store->isValidPath(storePath))
|
if (!store->isValidPath(storePath))
|
||||||
throw Error(format("`exportReferencesGraph' refers to an invalid path `%1%'")
|
throw BuildError(format("`exportReferencesGraph' refers to an invalid path `%1%'")
|
||||||
% storePath);
|
% storePath);
|
||||||
checkStoreName(fileName); /* !!! abuse of this function */
|
checkStoreName(fileName); /* !!! abuse of this function */
|
||||||
PathSet refs;
|
PathSet refs;
|
||||||
|
@ -1534,7 +1543,7 @@ PathSet parseReferenceSpecifiers(const Derivation & drv, string attr)
|
||||||
result.insert(*i);
|
result.insert(*i);
|
||||||
else if (drv.outputs.find(*i) != drv.outputs.end())
|
else if (drv.outputs.find(*i) != drv.outputs.end())
|
||||||
result.insert(drv.outputs.find(*i)->second.path);
|
result.insert(drv.outputs.find(*i)->second.path);
|
||||||
else throw Error(
|
else throw BuildError(
|
||||||
format("derivation contains an illegal reference specifier `%1%'")
|
format("derivation contains an illegal reference specifier `%1%'")
|
||||||
% *i);
|
% *i);
|
||||||
}
|
}
|
||||||
|
@ -1561,7 +1570,7 @@ void DerivationGoal::computeClosure()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(path.c_str(), &st))
|
if (lstat(path.c_str(), &st) == -1)
|
||||||
throw SysError(format("getting attributes of path `%1%'") % path);
|
throw SysError(format("getting attributes of path `%1%'") % path);
|
||||||
|
|
||||||
startNest(nest, lvlTalkative,
|
startNest(nest, lvlTalkative,
|
||||||
|
@ -1584,7 +1593,7 @@ void DerivationGoal::computeClosure()
|
||||||
/* The output path should be a regular file without
|
/* The output path should be a regular file without
|
||||||
execute permission. */
|
execute permission. */
|
||||||
if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
|
if (!S_ISREG(st.st_mode) || (st.st_mode & S_IXUSR) != 0)
|
||||||
throw Error(
|
throw BuildError(
|
||||||
format("output path `%1% should be a non-executable regular file")
|
format("output path `%1% should be a non-executable regular file")
|
||||||
% path);
|
% path);
|
||||||
}
|
}
|
||||||
|
@ -1592,11 +1601,11 @@ void DerivationGoal::computeClosure()
|
||||||
/* Check the hash. */
|
/* Check the hash. */
|
||||||
HashType ht = parseHashType(algo);
|
HashType ht = parseHashType(algo);
|
||||||
if (ht == htUnknown)
|
if (ht == htUnknown)
|
||||||
throw Error(format("unknown hash algorithm `%1%'") % algo);
|
throw BuildError(format("unknown hash algorithm `%1%'") % algo);
|
||||||
Hash h = parseHash(ht, i->second.hash);
|
Hash h = parseHash(ht, i->second.hash);
|
||||||
Hash h2 = recursive ? hashPath(ht, path) : hashFile(ht, path);
|
Hash h2 = recursive ? hashPath(ht, path) : hashFile(ht, path);
|
||||||
if (h != h2)
|
if (h != h2)
|
||||||
throw Error(
|
throw BuildError(
|
||||||
format("output path `%1%' should have %2% hash `%3%', instead has `%4%'")
|
format("output path `%1%' should have %2% hash `%3%', instead has `%4%'")
|
||||||
% path % algo % printHash(h) % printHash(h2));
|
% path % algo % printHash(h) % printHash(h2));
|
||||||
}
|
}
|
||||||
|
@ -1630,7 +1639,7 @@ void DerivationGoal::computeClosure()
|
||||||
PathSet allowed = parseReferenceSpecifiers(drv, drv.env["allowedReferences"]);
|
PathSet allowed = parseReferenceSpecifiers(drv, drv.env["allowedReferences"]);
|
||||||
for (PathSet::iterator i = references.begin(); i != references.end(); ++i)
|
for (PathSet::iterator i = references.begin(); i != references.end(); ++i)
|
||||||
if (allowed.find(*i) == allowed.end())
|
if (allowed.find(*i) == allowed.end())
|
||||||
throw Error(format("output is not allowed to refer to path `%1%'") % *i);
|
throw BuildError(format("output is not allowed to refer to path `%1%'") % *i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hash the contents of the path. The hash is stored in the
|
/* Hash the contents of the path. The hash is stored in the
|
||||||
|
@ -1849,7 +1858,7 @@ void SubstitutionGoal::init()
|
||||||
|
|
||||||
/* If the path already exists we're done. */
|
/* If the path already exists we're done. */
|
||||||
if (store->isValidPath(storePath)) {
|
if (store->isValidPath(storePath)) {
|
||||||
amDone();
|
amDone(ecSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1880,8 +1889,12 @@ void SubstitutionGoal::referencesValid()
|
||||||
{
|
{
|
||||||
trace("all referenced realised");
|
trace("all referenced realised");
|
||||||
|
|
||||||
if (nrFailed > 0)
|
if (nrFailed > 0) {
|
||||||
throw Error(format("some references of path `%1%' could not be realised") % storePath);
|
printMsg(lvlError,
|
||||||
|
format("some references of path `%1%' could not be realised") % storePath);
|
||||||
|
amDone(ecFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (PathSet::iterator i = references.begin();
|
for (PathSet::iterator i = references.begin();
|
||||||
i != references.end(); ++i)
|
i != references.end(); ++i)
|
||||||
|
@ -1902,7 +1915,7 @@ void SubstitutionGoal::tryNext()
|
||||||
printMsg(lvlError,
|
printMsg(lvlError,
|
||||||
format("path `%1%' is required, but it has no (remaining) substitutes")
|
format("path `%1%' is required, but it has no (remaining) substitutes")
|
||||||
% storePath);
|
% storePath);
|
||||||
amDone(false);
|
amDone(ecFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sub = subs.front();
|
sub = subs.front();
|
||||||
|
@ -1933,7 +1946,7 @@ void SubstitutionGoal::tryToRun()
|
||||||
if (store->isValidPath(storePath)) {
|
if (store->isValidPath(storePath)) {
|
||||||
debug(format("store path `%1%' has become valid") % storePath);
|
debug(format("store path `%1%' has become valid") % storePath);
|
||||||
outputLock->setDeletion(true);
|
outputLock->setDeletion(true);
|
||||||
amDone();
|
amDone(ecSuccess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2046,7 +2059,7 @@ void SubstitutionGoal::finished()
|
||||||
printMsg(lvlChatty,
|
printMsg(lvlChatty,
|
||||||
format("substitution of path `%1%' succeeded") % storePath);
|
format("substitution of path `%1%' succeeded") % storePath);
|
||||||
|
|
||||||
amDone();
|
amDone(ecSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2197,24 +2210,30 @@ void Worker::childTerminated(pid_t pid, bool wakeSleepers)
|
||||||
}
|
}
|
||||||
|
|
||||||
wantingToBuild.clear();
|
wantingToBuild.clear();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Worker::waitForBuildSlot(GoalPtr goal, bool reallyWait)
|
void Worker::waitForBuildSlot(GoalPtr goal)
|
||||||
{
|
{
|
||||||
debug("wait for build slot");
|
debug("wait for build slot");
|
||||||
if (reallyWait && children.size() == 0)
|
if (canBuildMore())
|
||||||
throw Error("waiting for a build slot, yet there are no children - "
|
|
||||||
"maybe the build hook gave an inappropriate `postpone' reply?");
|
|
||||||
if (!reallyWait && canBuildMore())
|
|
||||||
wakeUp(goal); /* we can do it right away */
|
wakeUp(goal); /* we can do it right away */
|
||||||
else
|
else
|
||||||
wantingToBuild.insert(goal);
|
wantingToBuild.insert(goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Worker::waitForChildTermination(GoalPtr goal)
|
||||||
|
{
|
||||||
|
debug("wait for child termination");
|
||||||
|
if (children.size() == 0)
|
||||||
|
throw Error("waiting for a build slot, yet there are no running children - "
|
||||||
|
"maybe the build hook gave an inappropriate `postpone' reply?");
|
||||||
|
wantingToBuild.insert(goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Worker::run(const Goals & _topGoals)
|
void Worker::run(const Goals & _topGoals)
|
||||||
{
|
{
|
||||||
for (Goals::iterator i = _topGoals.begin();
|
for (Goals::iterator i = _topGoals.begin();
|
||||||
|
@ -2342,8 +2361,12 @@ void Worker::waitForInput()
|
||||||
|
|
||||||
if (maxSilentTime != 0 &&
|
if (maxSilentTime != 0 &&
|
||||||
now - i->second.lastOutput >= (time_t) maxSilentTime)
|
now - i->second.lastOutput >= (time_t) maxSilentTime)
|
||||||
throw Error(format("%1% timed out after %2% seconds of silence")
|
{
|
||||||
|
printMsg(lvlError,
|
||||||
|
format("%1% timed out after %2% seconds of silence")
|
||||||
% goal->getName() % maxSilentTime);
|
% goal->getName() % maxSilentTime);
|
||||||
|
goal->cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue