diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 94410e2bda..883e99ad0d 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -949,6 +949,20 @@ static Expr prim_unsafeDiscardStringContext(EvalState & state, const ATermVector return makeStr(s, PathSet()); } +static Expr prim_ExprToString ( EvalState & state, const ATermVector & args) +{ + return makeStr ( atPrint ( evalExpr ( state, args [ 0 ] ) ) ); +} + +static Expr prim_StringToExpr ( EvalState & state, const ATermVector & args) +{ + string s; + PathSet l; + if (! matchStr ( evalExpr ( state, args[0] ), s, l )) { + throw EvalError("__stringToExpr needs string argument!"); + } + return toATerm ( s ); +} /************************************************************* * Primop registration @@ -975,6 +989,10 @@ void EvalState::addPrimOps() addPrimOp("throw", 1, prim_throw); addPrimOp("__getEnv", 1, prim_getEnv); addPrimOp("__trace", 2, prim_trace); + + // Expr <-> String + addPrimOp("__exprToString", 1, prim_ExprToString); + addPrimOp("__stringToExpr", 1, prim_StringToExpr); addPrimOp("relativise", 2, prim_relativise); diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 6f045dbc37..af54b161e2 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -100,6 +100,7 @@ protected: { nrFailed = 0; exitCode = ecBusy; + forceInputs = false; } virtual ~Goal() @@ -107,6 +108,8 @@ protected: trace("goal destroyed"); } + bool forceInputs; + public: virtual void work() = 0; @@ -141,6 +144,11 @@ public: (important!), etc. */ virtual void cancel() = 0; + void setForceInputs(bool x) + { + forceInputs = x; + } + protected: void amDone(ExitCode result); }; @@ -745,7 +753,7 @@ public: { return drvPath; } - + private: /* The states. */ void init(); @@ -812,7 +820,6 @@ DerivationGoal::DerivationGoal(const Path & drvPath, Worker & worker) trace("created"); } - DerivationGoal::~DerivationGoal() { /* Careful: we should never ever throw an exception from a @@ -825,7 +832,6 @@ DerivationGoal::~DerivationGoal() } } - void DerivationGoal::killChild() { if (pid != -1) { @@ -905,8 +911,10 @@ void DerivationGoal::haveDerivation() /* If they are all valid, then we're done. */ if (invalidOutputs.size() == 0) { - amDone(ecSuccess); - return; + if(! forceInputs) { + amDone(ecSuccess); + return; + } } /* If this is a fixed-output derivation, it is possible that some @@ -950,8 +958,10 @@ void DerivationGoal::outputsSubstituted() nrFailed = 0; if (checkPathValidity(false).size() == 0) { - amDone(ecSuccess); - return; + if (! forceInputs){ + amDone(ecSuccess); + return; + } } /* Otherwise, at least one of the output paths could not be @@ -960,13 +970,43 @@ void DerivationGoal::outputsSubstituted() /* The inputs must be built before we can build this goal. */ /* !!! but if possible, only install the paths that we need */ for (DerivationInputs::iterator i = drv.inputDrvs.begin(); - i != drv.inputDrvs.end(); ++i) - addWaitee(worker.makeDerivationGoal(i->first)); + i != drv.inputDrvs.end(); ++i){ + GoalPtr newGoal = worker.makeDerivationGoal(i->first); + newGoal->setForceInputs(forceInputs); + addWaitee(newGoal); + } for (PathSet::iterator i = drv.inputSrcs.begin(); i != drv.inputSrcs.end(); ++i) addWaitee(worker.makeSubstitutionGoal(*i)); + /* Actually, I do some work twice just to be on the safe side */ + string s = drv.env["exportBuildReferencesGraph"]; + Strings ss = tokenizeString(s); + if (ss.size() % 2 !=0) + throw BuildError(format("odd number of tokens in `exportBuildReferencesGraph': `%1%'") % s); + for (Strings::iterator i = ss.begin(); i != ss.end(); ) { + string fileName = *i++; + Path storePath=*i++; + + if (!isInStore(storePath)) + throw BuildError(format("`exportBuildReferencesGraph' contains a non-store path `%1%'") + % storePath); + storePath = toStorePath(storePath); + if (!store->isValidPath(storePath)) + throw BuildError(format("`exportBuildReferencesGraph' contains an invalid path `%1%'") + % storePath); + + /* Build-time closure should be in dependencies + * We really want just derivation, its closure + * and outputs. Looks like we should build it. + * */ + + GoalPtr newGoal = worker.makeDerivationGoal(storePath); + newGoal->setForceInputs(true); + addWaitee(newGoal); + } + state = &DerivationGoal::inputsRealised; } @@ -984,6 +1024,12 @@ void DerivationGoal::inputsRealised() return; } + /* Maybe we just wanted to force build of inputs */ + if (checkPathValidity(false).size() == 0) { + amDone(ecSuccess); + return; + } + /* 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 build hook. */ @@ -1623,7 +1669,7 @@ void DerivationGoal::startBuilder() s = drv.env["exportBuildReferencesGraph"]; ss = tokenizeString(s); if (ss.size() % 2 != 0) - throw BuildError(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s); + throw BuildError(format("odd number of tokens in `exportBuildReferencesGraph': `%1%'") % s); for (Strings::iterator i = ss.begin(); i != ss.end(); ) { string fileName = *i++; checkStoreName(fileName); /* !!! abuse of this function */ @@ -1631,11 +1677,11 @@ void DerivationGoal::startBuilder() /* Check that the store path is valid. */ Path storePath = *i++; if (!isInStore(storePath)) - throw BuildError(format("`exportReferencesGraph' contains a non-store path `%1%'") + throw BuildError(format("`exportBuildReferencesGraph' contains a non-store path `%1%'") % storePath); storePath = toStorePath(storePath); if (!store->isValidPath(storePath)) - throw BuildError(format("`exportReferencesGraph' contains an invalid path `%1%'") + throw BuildError(format("`exportBuildReferencesGraph' contains an invalid path `%1%'") % storePath); /* Write closure info to `fileName'. */ @@ -1648,6 +1694,7 @@ void DerivationGoal::startBuilder() for (DerivationOutputs::iterator k=deriv.outputs.begin(); k != deriv.outputs.end(); k++) { refs.insert(k->second.path); + } } }