Make the post-build-hook also run for unresolved CA derivations

Fix #4837
This commit is contained in:
regnat 2021-06-24 11:41:51 +02:00
parent 01a3f4d7ec
commit be7a4a6a13
4 changed files with 89 additions and 52 deletions

View file

@ -739,6 +739,63 @@ void DerivationGoal::cleanupPostOutputsRegisteredModeNonCheck()
{ {
} }
void runPostBuildHook(
Store & store,
Logger & logger,
const StorePath & drvPath,
StorePathSet outputPaths
)
{
auto hook = settings.postBuildHook;
if (hook == "")
return;
Activity act(logger, lvlInfo, actPostBuildHook,
fmt("running post-build-hook '%s'", settings.postBuildHook),
Logger::Fields{store.printStorePath(drvPath)});
PushActivity pact(act.id);
std::map<std::string, std::string> hookEnvironment = getEnv();
hookEnvironment.emplace("DRV_PATH", store.printStorePath(drvPath));
hookEnvironment.emplace("OUT_PATHS", chomp(concatStringsSep(" ", store.printStorePathSet(outputPaths))));
RunOptions opts(settings.postBuildHook, {});
opts.environment = hookEnvironment;
struct LogSink : Sink {
Activity & act;
std::string currentLine;
LogSink(Activity & act) : act(act) { }
void operator() (std::string_view data) override {
for (auto c : data) {
if (c == '\n') {
flushLine();
} else {
currentLine += c;
}
}
}
void flushLine() {
act.result(resPostBuildLogLine, currentLine);
currentLine.clear();
}
~LogSink() {
if (currentLine != "") {
currentLine += '\n';
flushLine();
}
}
};
LogSink sink(act);
opts.standardOut = &sink;
opts.mergeStderrToStdout = true;
runProgram2(opts);
}
void DerivationGoal::buildDone() void DerivationGoal::buildDone()
{ {
@ -804,57 +861,15 @@ void DerivationGoal::buildDone()
being valid. */ being valid. */
registerOutputs(); registerOutputs();
if (settings.postBuildHook != "") {
Activity act(*logger, lvlInfo, actPostBuildHook,
fmt("running post-build-hook '%s'", settings.postBuildHook),
Logger::Fields{worker.store.printStorePath(drvPath)});
PushActivity pact(act.id);
StorePathSet outputPaths; StorePathSet outputPaths;
for (auto i : drv->outputs) { for (auto & [_, path] : finalOutputs)
outputPaths.insert(finalOutputs.at(i.first)); outputPaths.insert(path);
} runPostBuildHook(
std::map<std::string, std::string> hookEnvironment = getEnv(); worker.store,
*logger,
hookEnvironment.emplace("DRV_PATH", worker.store.printStorePath(drvPath)); drvPath,
hookEnvironment.emplace("OUT_PATHS", chomp(concatStringsSep(" ", worker.store.printStorePathSet(outputPaths)))); outputPaths
);
RunOptions opts(settings.postBuildHook, {});
opts.environment = hookEnvironment;
struct LogSink : Sink {
Activity & act;
std::string currentLine;
LogSink(Activity & act) : act(act) { }
void operator() (std::string_view data) override {
for (auto c : data) {
if (c == '\n') {
flushLine();
} else {
currentLine += c;
}
}
}
void flushLine() {
act.result(resPostBuildLogLine, currentLine);
currentLine.clear();
}
~LogSink() {
if (currentLine != "") {
currentLine += '\n';
flushLine();
}
}
};
LogSink sink(act);
opts.standardOut = &sink;
opts.mergeStderrToStdout = true;
runProgram2(opts);
}
if (buildMode == bmCheck) { if (buildMode == bmCheck) {
cleanupPostOutputsRegisteredModeCheck(); cleanupPostOutputsRegisteredModeCheck();
@ -910,6 +925,8 @@ void DerivationGoal::resolvedFinished() {
auto resolvedHashes = staticOutputHashes(worker.store, *resolvedDrv); auto resolvedHashes = staticOutputHashes(worker.store, *resolvedDrv);
StorePathSet outputPaths;
// `wantedOutputs` might be empty, which means “all the outputs” // `wantedOutputs` might be empty, which means “all the outputs”
auto realWantedOutputs = wantedOutputs; auto realWantedOutputs = wantedOutputs;
if (realWantedOutputs.empty()) if (realWantedOutputs.empty())
@ -930,6 +947,7 @@ void DerivationGoal::resolvedFinished() {
newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation->outPath); newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation->outPath);
signRealisation(newRealisation); signRealisation(newRealisation);
worker.store.registerDrvOutput(newRealisation); worker.store.registerDrvOutput(newRealisation);
outputPaths.insert(realisation->outPath);
} else { } else {
// If we don't have a realisation, then it must mean that something // If we don't have a realisation, then it must mean that something
// failed when building the resolved drv // failed when building the resolved drv
@ -937,6 +955,13 @@ void DerivationGoal::resolvedFinished() {
} }
} }
runPostBuildHook(
worker.store,
*logger,
drvPath,
outputPaths
);
// This is potentially a bit fishy in terms of error reporting. Not sure // This is potentially a bit fishy in terms of error reporting. Not sure
// how to do it in a cleaner way // how to do it in a cleaner way
amDone(nrFailed == 0 ? ecSuccess : ecFailed, ex); amDone(nrFailed == 0 ? ecSuccess : ecFailed, ex);

11
tests/ca/post-hook.sh Executable file
View file

@ -0,0 +1,11 @@
#!/usr/bin/env bash
source common.sh
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
export NIX_TESTS_CA_BY_DEFAULT=1
cd ..
source ./post-hook.sh

View file

@ -39,6 +39,7 @@ nix_tests = \
search.sh \ search.sh \
nix-copy-ssh.sh \ nix-copy-ssh.sh \
post-hook.sh \ post-hook.sh \
ca/post-hook.sh \
function-trace.sh \ function-trace.sh \
recursive.sh \ recursive.sh \
describe-stores.sh \ describe-stores.sh \

View file

@ -4,7 +4,7 @@ clearStore
rm -f $TEST_ROOT/result rm -f $TEST_ROOT/result
export REMOTE_STORE=$TEST_ROOT/remote_store export REMOTE_STORE=file:$TEST_ROOT/remote_store
# Build the dependencies and push them to the remote store # Build the dependencies and push them to the remote store
nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook $PWD/push-to-store.sh nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook $PWD/push-to-store.sh