* Don't throw an exception when a build fails. Just terminate the
goal and allow the problem to be handled elsewhere (e.g., at top-level).
This commit is contained in:
		
							parent
							
								
									795d9f8b08
								
							
						
					
					
						commit
						e4883211f9
					
				
					 1 changed files with 215 additions and 59 deletions
				
			
		| 
						 | 
					@ -48,11 +48,17 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Number of goals we are waiting for. */
 | 
					    /* Number of goals we are waiting for. */
 | 
				
			||||||
    unsigned int nrWaitees;
 | 
					    unsigned int nrWaitees;
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Number of goals we were waiting for that have failed. */
 | 
				
			||||||
 | 
					    unsigned int nrFailed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Whether amDone() has been called. */
 | 
				
			||||||
 | 
					    bool done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    Goal(Worker & _worker) : worker(_worker)
 | 
					    Goal(Worker & _worker) : worker(_worker)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        nrWaitees = 0;
 | 
					        done = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual ~Goal()
 | 
					    virtual ~Goal()
 | 
				
			||||||
| 
						 | 
					@ -60,6 +66,12 @@ protected:
 | 
				
			||||||
        printMsg(lvlVomit, "goal destroyed");
 | 
					        printMsg(lvlVomit, "goal destroyed");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void resetWaitees(int nrWaitees)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        this->nrWaitees = nrWaitees;
 | 
				
			||||||
 | 
					        nrFailed = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    virtual void work() = 0;
 | 
					    virtual void work() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,9 +82,14 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void addWaiter(GoalPtr waiter);
 | 
					    void addWaiter(GoalPtr waiter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void waiteeDone();
 | 
					    virtual void waiteeDone(bool success);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void amDone();
 | 
					protected:
 | 
				
			||||||
 | 
					    virtual void waiteeFailed()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void amDone(bool success = true);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,6 +177,13 @@ public:
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BuildError : public Error
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    BuildError(const format & f) : Error(f) { };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//////////////////////////////////////////////////////////////////////
 | 
					//////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,18 +194,25 @@ void Goal::addWaiter(GoalPtr waiter)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Goal::waiteeDone()
 | 
					void Goal::waiteeDone(bool success)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    assert(nrWaitees > 0);
 | 
					    assert(nrWaitees > 0);
 | 
				
			||||||
 | 
					    /* Note: waiteeFailed should never call amDone()! */
 | 
				
			||||||
 | 
					    if (!success) {
 | 
				
			||||||
 | 
					        ++nrFailed;
 | 
				
			||||||
 | 
					        waiteeFailed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (!--nrWaitees) worker.wakeUp(shared_from_this());
 | 
					    if (!--nrWaitees) worker.wakeUp(shared_from_this());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Goal::amDone()
 | 
					void Goal::amDone(bool success)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    printMsg(lvlVomit, "done");
 | 
					    printMsg(lvlVomit, "done");
 | 
				
			||||||
 | 
					    assert(!done);
 | 
				
			||||||
 | 
					    done = true;
 | 
				
			||||||
    for (Goals::iterator i = waiters.begin(); i != waiters.end(); ++i)
 | 
					    for (Goals::iterator i = waiters.begin(); i != waiters.end(); ++i)
 | 
				
			||||||
        (*i)->waiteeDone();
 | 
					        (*i)->waiteeDone(success);
 | 
				
			||||||
    worker.removeGoal(shared_from_this());
 | 
					    worker.removeGoal(shared_from_this());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -375,7 +406,7 @@ void NormalisationGoal::init()
 | 
				
			||||||
    /* The first thing to do is to make sure that the store expression
 | 
					    /* The first thing to do is to make sure that the store expression
 | 
				
			||||||
       exists.  If it doesn't, it may be created through a
 | 
					       exists.  If it doesn't, it may be created through a
 | 
				
			||||||
       substitute. */
 | 
					       substitute. */
 | 
				
			||||||
    nrWaitees = 1;
 | 
					    resetWaitees(1);
 | 
				
			||||||
    worker.addSubstitutionGoal(nePath, shared_from_this());
 | 
					    worker.addSubstitutionGoal(nePath, shared_from_this());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &NormalisationGoal::haveStoreExpr;
 | 
					    state = &NormalisationGoal::haveStoreExpr;
 | 
				
			||||||
| 
						 | 
					@ -386,6 +417,14 @@ void NormalisationGoal::haveStoreExpr()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("loading store expression");
 | 
					    trace("loading store expression");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        printMsg(lvlError,
 | 
				
			||||||
 | 
					            format("cannot normalise missing store expression `%1%'")
 | 
				
			||||||
 | 
					            % nePath);
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(isValidPath(nePath));
 | 
					    assert(isValidPath(nePath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Get the store expression. */
 | 
					    /* Get the store expression. */
 | 
				
			||||||
| 
						 | 
					@ -403,7 +442,7 @@ void NormalisationGoal::haveStoreExpr()
 | 
				
			||||||
         i != expr.derivation.inputs.end(); ++i)
 | 
					         i != expr.derivation.inputs.end(); ++i)
 | 
				
			||||||
        worker.addNormalisationGoal(*i, shared_from_this());
 | 
					        worker.addNormalisationGoal(*i, shared_from_this());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nrWaitees = expr.derivation.inputs.size();
 | 
					    resetWaitees(expr.derivation.inputs.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &NormalisationGoal::inputNormalised;
 | 
					    state = &NormalisationGoal::inputNormalised;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -413,6 +452,15 @@ void NormalisationGoal::inputNormalised()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("all inputs normalised");
 | 
					    trace("all inputs normalised");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        printMsg(lvlError,
 | 
				
			||||||
 | 
					            format("cannot normalise derivation `%1%': "
 | 
				
			||||||
 | 
					                "%2% closure element(s) could not be normalised")
 | 
				
			||||||
 | 
					            % nePath % nrFailed);
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Inputs must also be realised before we can build this goal. */
 | 
					    /* Inputs must also be realised before we can build this goal. */
 | 
				
			||||||
    for (PathSet::iterator i = expr.derivation.inputs.begin();
 | 
					    for (PathSet::iterator i = expr.derivation.inputs.begin();
 | 
				
			||||||
         i != expr.derivation.inputs.end(); ++i)
 | 
					         i != expr.derivation.inputs.end(); ++i)
 | 
				
			||||||
| 
						 | 
					@ -424,7 +472,7 @@ void NormalisationGoal::inputNormalised()
 | 
				
			||||||
        worker.addRealisationGoal(neInput, shared_from_this());
 | 
					        worker.addRealisationGoal(neInput, shared_from_this());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    nrWaitees = expr.derivation.inputs.size();
 | 
					    resetWaitees(expr.derivation.inputs.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &NormalisationGoal::inputRealised;
 | 
					    state = &NormalisationGoal::inputRealised;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -434,6 +482,15 @@ void NormalisationGoal::inputRealised()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("all inputs realised");
 | 
					    trace("all inputs realised");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        printMsg(lvlError,
 | 
				
			||||||
 | 
					            format("cannot normalise derivation `%1%': "
 | 
				
			||||||
 | 
					                "%2% closure element(s) could not be realised")
 | 
				
			||||||
 | 
					            % nePath % nrFailed);
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Okay, try to build.  Note that here we don't wait for a build
 | 
					    /* Okay, try to build.  Note that here we don't wait for a build
 | 
				
			||||||
       slot to become available, since we don't need one if there is a
 | 
					       slot to become available, since we don't need one if there is a
 | 
				
			||||||
       build hook. */
 | 
					       build hook. */
 | 
				
			||||||
| 
						 | 
					@ -446,42 +503,50 @@ void NormalisationGoal::tryToBuild()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("trying to build");
 | 
					    trace("trying to build");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Is the build hook willing to accept this job? */
 | 
					    try {
 | 
				
			||||||
    switch (tryBuildHook()) {
 | 
					
 | 
				
			||||||
        case rpAccept:
 | 
					        /* Is the build hook willing to accept this job? */
 | 
				
			||||||
            /* Yes, it has started doing so.  Wait until we get
 | 
					        switch (tryBuildHook()) {
 | 
				
			||||||
               EOF from the hook. */
 | 
					            case rpAccept:
 | 
				
			||||||
            state = &NormalisationGoal::buildDone;
 | 
					                /* Yes, it has started doing so.  Wait until we get
 | 
				
			||||||
            return;
 | 
					                   EOF from the hook. */
 | 
				
			||||||
        case rpPostpone:
 | 
					                state = &NormalisationGoal::buildDone;
 | 
				
			||||||
            /* Not now; wait until at least one child finishes. */
 | 
					                return;
 | 
				
			||||||
 | 
					            case rpPostpone:
 | 
				
			||||||
 | 
					                /* Not now; wait until at least one child finishes. */
 | 
				
			||||||
 | 
					                worker.waitForBuildSlot(shared_from_this());
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            case rpDecline:
 | 
				
			||||||
 | 
					                /* We should do it ourselves. */
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case rpDone:
 | 
				
			||||||
 | 
					                /* Somebody else did it (there is a successor now). */
 | 
				
			||||||
 | 
					                amDone();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Make sure that we are allowed to start a build. */
 | 
				
			||||||
 | 
					        if (!worker.canBuildMore()) {
 | 
				
			||||||
            worker.waitForBuildSlot(shared_from_this());
 | 
					            worker.waitForBuildSlot(shared_from_this());
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        case rpDecline:
 | 
					        }
 | 
				
			||||||
            /* We should do it ourselves. */
 | 
					
 | 
				
			||||||
            break;
 | 
					        /* Acquire locks and such.  If we then see that there now is a
 | 
				
			||||||
        case rpDone:
 | 
					           successor, we're done. */
 | 
				
			||||||
            /* Somebody else did it (there is a successor now). */
 | 
					        if (!prepareBuild()) {
 | 
				
			||||||
            amDone();
 | 
					            amDone();
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
    }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Make sure that we are allowed to start a build. */
 | 
					        /* Okay, we have to build. */
 | 
				
			||||||
    if (!worker.canBuildMore()) {
 | 
					        startBuilder();
 | 
				
			||||||
        worker.waitForBuildSlot(shared_from_this());
 | 
					
 | 
				
			||||||
 | 
					    } catch (BuildError & e) {
 | 
				
			||||||
 | 
					        printMsg(lvlError, e.msg());
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Acquire locks and such.  If we then see that there now is a
 | 
					 | 
				
			||||||
       successor, we're done. */
 | 
					 | 
				
			||||||
    if (!prepareBuild()) {
 | 
					 | 
				
			||||||
        amDone();
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Okay, we have to build. */
 | 
					 | 
				
			||||||
    startBuilder();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* This state will be reached when we get EOF on the child's
 | 
					    /* This state will be reached when we get EOF on the child's
 | 
				
			||||||
       log pipe. */
 | 
					       log pipe. */
 | 
				
			||||||
    state = &NormalisationGoal::buildDone;
 | 
					    state = &NormalisationGoal::buildDone;
 | 
				
			||||||
| 
						 | 
					@ -514,15 +579,23 @@ void NormalisationGoal::buildDone()
 | 
				
			||||||
    /* Check the exit status. */
 | 
					    /* Check the exit status. */
 | 
				
			||||||
    if (!statusOk(status)) {
 | 
					    if (!statusOk(status)) {
 | 
				
			||||||
        deleteTmpDir(false);
 | 
					        deleteTmpDir(false);
 | 
				
			||||||
        throw Error(format("builder for `%1%' %2%")
 | 
					        printMsg(lvlError, format("builder for `%1%' %2%")
 | 
				
			||||||
            % nePath % statusToString(status));
 | 
					            % nePath % statusToString(status));
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    deleteTmpDir(true);
 | 
					    deleteTmpDir(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Compute a closure store expression, and register it as our
 | 
					    /* Compute a closure store expression, and register it as our
 | 
				
			||||||
       successor. */
 | 
					       successor. */
 | 
				
			||||||
    createClosure();
 | 
					    try {
 | 
				
			||||||
 | 
					        createClosure();
 | 
				
			||||||
 | 
					    } catch (BuildError & e) {
 | 
				
			||||||
 | 
					        printMsg(lvlError, e.msg());
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    amDone();
 | 
					    amDone();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -791,8 +864,9 @@ void NormalisationGoal::startBuilder()
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /* Right platform? */
 | 
					    /* Right platform? */
 | 
				
			||||||
    if (expr.derivation.platform != thisSystem)
 | 
					    if (expr.derivation.platform != thisSystem)
 | 
				
			||||||
        throw Error(format("a `%1%' is required, but I am a `%2%'")
 | 
					        throw BuildError(
 | 
				
			||||||
		    % expr.derivation.platform % thisSystem);
 | 
					            format("a `%1%' is required to build `%3%', but I am a `%2%'")
 | 
				
			||||||
 | 
					            % expr.derivation.platform % thisSystem % nePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If any of the outputs already exist but are not registered,
 | 
					    /* If any of the outputs already exist but are not registered,
 | 
				
			||||||
       delete them. */
 | 
					       delete them. */
 | 
				
			||||||
| 
						 | 
					@ -923,8 +997,11 @@ void NormalisationGoal::createClosure()
 | 
				
			||||||
         i != expr.derivation.outputs.end(); ++i)
 | 
					         i != expr.derivation.outputs.end(); ++i)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Path path = *i;
 | 
					        Path path = *i;
 | 
				
			||||||
        if (!pathExists(path))
 | 
					        if (!pathExists(path)) {
 | 
				
			||||||
            throw Error(format("output path `%1%' does not exist") % path);
 | 
					            throw BuildError(
 | 
				
			||||||
 | 
					                format("builder for `%1%' failed to produce output path `%1%'")
 | 
				
			||||||
 | 
					                % nePath % path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        nf.closure.roots.insert(path);
 | 
					        nf.closure.roots.insert(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	makePathReadOnly(path);
 | 
						makePathReadOnly(path);
 | 
				
			||||||
| 
						 | 
					@ -1038,18 +1115,18 @@ void NormalisationGoal::initChild()
 | 
				
			||||||
    commonChildInit(logPipe);
 | 
					    commonChildInit(logPipe);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (chdir(tmpDir.c_str()) == -1)
 | 
					    if (chdir(tmpDir.c_str()) == -1)
 | 
				
			||||||
        throw SysError(format("changing into to `%1%'") % tmpDir);
 | 
					        throw SysError(format("changing into `%1%'") % tmpDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* When running a hook, dup the communication pipes. */
 | 
					    /* When running a hook, dup the communication pipes. */
 | 
				
			||||||
    bool inHook = fromHook.writeSide.isOpen();
 | 
					    bool inHook = fromHook.writeSide.isOpen();
 | 
				
			||||||
    if (inHook) {
 | 
					    if (inHook) {
 | 
				
			||||||
        fromHook.readSide.close();
 | 
					        fromHook.readSide.close();
 | 
				
			||||||
        if (dup2(fromHook.writeSide, 3) == -1)
 | 
					        if (dup2(fromHook.writeSide, 3) == -1)
 | 
				
			||||||
            throw SysError("dup1");
 | 
					            throw SysError("dupping from-hook write side");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        toHook.writeSide.close();
 | 
					        toHook.writeSide.close();
 | 
				
			||||||
        if (dup2(toHook.readSide, 4) == -1)
 | 
					        if (dup2(toHook.readSide, 4) == -1)
 | 
				
			||||||
            throw SysError("dup2");
 | 
					            throw SysError("dupping to-hook read side");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Close all other file descriptors. */
 | 
					    /* Close all other file descriptors. */
 | 
				
			||||||
| 
						 | 
					@ -1139,7 +1216,7 @@ void RealisationGoal::init()
 | 
				
			||||||
    /* The first thing to do is to make sure that the store expression
 | 
					    /* The first thing to do is to make sure that the store expression
 | 
				
			||||||
       exists.  If it doesn't, it may be created through a
 | 
					       exists.  If it doesn't, it may be created through a
 | 
				
			||||||
       substitute. */
 | 
					       substitute. */
 | 
				
			||||||
    nrWaitees = 1;
 | 
					    resetWaitees(1);
 | 
				
			||||||
    worker.addSubstitutionGoal(nePath, shared_from_this());
 | 
					    worker.addSubstitutionGoal(nePath, shared_from_this());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &RealisationGoal::haveStoreExpr;
 | 
					    state = &RealisationGoal::haveStoreExpr;
 | 
				
			||||||
| 
						 | 
					@ -1150,6 +1227,14 @@ void RealisationGoal::haveStoreExpr()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("loading store expression");
 | 
					    trace("loading store expression");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        printMsg(lvlError,
 | 
				
			||||||
 | 
					            format("cannot realise missing store expression `%1%'")
 | 
				
			||||||
 | 
					            % nePath);
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert(isValidPath(nePath));
 | 
					    assert(isValidPath(nePath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Get the store expression. */
 | 
					    /* Get the store expression. */
 | 
				
			||||||
| 
						 | 
					@ -1165,7 +1250,7 @@ void RealisationGoal::haveStoreExpr()
 | 
				
			||||||
         i != expr.closure.elems.end(); ++i)
 | 
					         i != expr.closure.elems.end(); ++i)
 | 
				
			||||||
        worker.addSubstitutionGoal(i->first, shared_from_this());
 | 
					        worker.addSubstitutionGoal(i->first, shared_from_this());
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    nrWaitees = expr.closure.elems.size();
 | 
					    resetWaitees(expr.closure.elems.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &RealisationGoal::elemFinished;
 | 
					    state = &RealisationGoal::elemFinished;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1175,6 +1260,16 @@ void RealisationGoal::elemFinished()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("all closure elements present");
 | 
					    trace("all closure elements present");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        printMsg(lvlError,
 | 
				
			||||||
 | 
					            format("cannot realise closure `%1%': "
 | 
				
			||||||
 | 
					                "%2% closure element(s) are not present "
 | 
				
			||||||
 | 
					                "and could not be substituted")
 | 
				
			||||||
 | 
					            % nePath % nrFailed);
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    amDone();
 | 
					    amDone();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1269,15 +1364,21 @@ void SubstitutionGoal::tryNext()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("trying next substitute");
 | 
					    trace("trying next substitute");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (subs.size() == 0) throw Error(
 | 
					    if (subs.size() == 0) {
 | 
				
			||||||
        format("path `%1%' is required, but it has no (remaining) substitutes")
 | 
					        /* None left.  Terminate this goal and let someone else deal
 | 
				
			||||||
 | 
					           with it. */
 | 
				
			||||||
 | 
					        printMsg(lvlError,
 | 
				
			||||||
 | 
					            format("path `%1%' is required, but it has no (remaining) substitutes")
 | 
				
			||||||
            % storePath);
 | 
					            % storePath);
 | 
				
			||||||
 | 
					        amDone(false);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    sub = subs.front();
 | 
					    sub = subs.front();
 | 
				
			||||||
    subs.pop_front();
 | 
					    subs.pop_front();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Normalise the substitute store expression. */
 | 
					    /* Normalise the substitute store expression. */
 | 
				
			||||||
    worker.addNormalisationGoal(sub.storeExpr, shared_from_this());
 | 
					    worker.addNormalisationGoal(sub.storeExpr, shared_from_this());
 | 
				
			||||||
    nrWaitees = 1;
 | 
					    resetWaitees(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &SubstitutionGoal::exprNormalised;
 | 
					    state = &SubstitutionGoal::exprNormalised;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1287,11 +1388,17 @@ void SubstitutionGoal::exprNormalised()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("substitute store expression normalised");
 | 
					    trace("substitute store expression normalised");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        tryNext();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Realise the substitute store expression. */
 | 
					    /* Realise the substitute store expression. */
 | 
				
			||||||
    if (!querySuccessor(sub.storeExpr, nfSub))
 | 
					    if (!querySuccessor(sub.storeExpr, nfSub))
 | 
				
			||||||
        nfSub = sub.storeExpr;
 | 
					        nfSub = sub.storeExpr;
 | 
				
			||||||
    worker.addRealisationGoal(nfSub, shared_from_this());
 | 
					    worker.addRealisationGoal(nfSub, shared_from_this());
 | 
				
			||||||
    nrWaitees = 1;
 | 
					
 | 
				
			||||||
 | 
					    resetWaitees(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &SubstitutionGoal::exprRealised;
 | 
					    state = &SubstitutionGoal::exprRealised;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1301,6 +1408,11 @@ void SubstitutionGoal::exprRealised()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    trace("substitute store expression realised");
 | 
					    trace("substitute store expression realised");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nrFailed != 0) {
 | 
				
			||||||
 | 
					        tryNext();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = &SubstitutionGoal::tryToRun;
 | 
					    state = &SubstitutionGoal::tryToRun;
 | 
				
			||||||
    worker.waitForBuildSlot(shared_from_this());
 | 
					    worker.waitForBuildSlot(shared_from_this());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1452,6 +1564,40 @@ void SubstitutionGoal::trace(const format & f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A fake goal used to receive notification of success or failure of
 | 
				
			||||||
 | 
					   other goals. */
 | 
				
			||||||
 | 
					class PseudoGoal : public Goal
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    bool success;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    PseudoGoal(Worker & _worker) : Goal(_worker)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        success = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void work() 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void waiteeDone(bool success)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!success) this->success = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool isOkay()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return success;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//////////////////////////////////////////////////////////////////////
 | 
					//////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1687,13 +1833,15 @@ Path normaliseStoreExpr(const Path & nePath)
 | 
				
			||||||
    startNest(nest, lvlDebug, format("normalising `%1%'") % nePath);
 | 
					    startNest(nest, lvlDebug, format("normalising `%1%'") % nePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Worker worker;
 | 
					    Worker worker;
 | 
				
			||||||
    worker.addNormalisationGoal(nePath, GoalPtr());
 | 
					    shared_ptr<PseudoGoal> pseudo(new PseudoGoal(worker));
 | 
				
			||||||
 | 
					    worker.addNormalisationGoal(nePath, pseudo);
 | 
				
			||||||
    worker.run();
 | 
					    worker.run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!pseudo->isOkay())
 | 
				
			||||||
 | 
					        throw Error(format("normalisation of store expression `%1%' failed") % nePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Path nfPath;
 | 
					    Path nfPath;
 | 
				
			||||||
    if (!querySuccessor(nePath, nfPath))
 | 
					    if (!querySuccessor(nePath, nfPath)) abort();
 | 
				
			||||||
        throw Error("there should be a successor");
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    return nfPath;
 | 
					    return nfPath;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1703,8 +1851,12 @@ void realiseClosure(const Path & nePath)
 | 
				
			||||||
    startNest(nest, lvlDebug, format("realising closure `%1%'") % nePath);
 | 
					    startNest(nest, lvlDebug, format("realising closure `%1%'") % nePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Worker worker;
 | 
					    Worker worker;
 | 
				
			||||||
    worker.addRealisationGoal(nePath, GoalPtr());
 | 
					    shared_ptr<PseudoGoal> pseudo(new PseudoGoal(worker));
 | 
				
			||||||
 | 
					    worker.addRealisationGoal(nePath, pseudo);
 | 
				
			||||||
    worker.run();
 | 
					    worker.run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!pseudo->isOkay())
 | 
				
			||||||
 | 
					        throw Error(format("realisation of closure `%1%' failed") % nePath);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1714,6 +1866,10 @@ void ensurePath(const Path & path)
 | 
				
			||||||
    if (isValidPath(path)) return;
 | 
					    if (isValidPath(path)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Worker worker;
 | 
					    Worker worker;
 | 
				
			||||||
    worker.addSubstitutionGoal(path, GoalPtr());
 | 
					    shared_ptr<PseudoGoal> pseudo(new PseudoGoal(worker));
 | 
				
			||||||
 | 
					    worker.addSubstitutionGoal(path, pseudo);
 | 
				
			||||||
    worker.run();
 | 
					    worker.run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!pseudo->isOkay())
 | 
				
			||||||
 | 
					        throw Error(format("path `%1%' does not exist and cannot be created") % path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue