diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index 5b8ab3387..c2319a3d1 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -248,7 +248,7 @@ connected: std::cerr << "# accept\n" << storeUri << "\n"; auto inputs = readStrings(source); - auto outputs = readStrings(source); + auto wantedOutputs = readStrings(source); AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + escapeUri(storeUri) + ".upload-lock", true); @@ -273,6 +273,7 @@ connected: uploadLock = -1; auto drv = store->readDerivation(*drvPath); + auto outputHashes = staticOutputHashes(*store, drv); drv.inputSrcs = store->parseStorePathSet(inputs); auto result = sshStore->buildDerivation(*drvPath, drv); @@ -280,16 +281,35 @@ connected: if (!result.success()) throw Error("build of '%s' on '%s' failed: %s", store->printStorePath(*drvPath), storeUri, result.errorMsg); - StorePathSet missing; - for (auto & path : outputs) - if (!store->isValidPath(store->parseStorePath(path))) missing.insert(store->parseStorePath(path)); + std::set missingRealisations; + StorePathSet missingPaths; + if (settings.isExperimentalFeatureEnabled("ca-derivations")) { + for (auto & outputName : wantedOutputs) { + auto thisOutputHash = outputHashes.at(outputName); + auto thisOutputId = DrvOutput{ thisOutputHash, outputName }; + if (!store->queryRealisation(thisOutputId)) { + notice("Missing output %s", outputName); + assert(result.builtOutputs.count(thisOutputId)); + auto newRealisation = result.builtOutputs.at(thisOutputId); + missingRealisations.insert(newRealisation); + missingPaths.insert(newRealisation.outPath); + } + } + } else { + auto outputPaths = drv.outputsAndOptPaths(*store); + for (auto & [outputName, hopefullyOutputPath] : outputPaths) { + assert(hopefullyOutputPath.second); + if (!store->isValidPath(*hopefullyOutputPath.second)) + missingPaths.insert(*hopefullyOutputPath.second); + } + } - if (!missing.empty()) { + if (!missingPaths.empty()) { Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri)); if (auto localStore = store.dynamic_pointer_cast()) - for (auto & i : missing) - localStore->locksHeld.insert(store->printStorePath(i)); /* FIXME: ugly */ - copyPaths(ref(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute); + for (auto & path : missingPaths) + localStore->locksHeld.insert(store->printStorePath(path)); /* FIXME: ugly */ + copyPaths(ref(sshStore), store, missingPaths, NoRepair, NoCheckSigs, NoSubstitute); } return 0; diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index d8a89a2d0..b074410b0 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -1159,13 +1159,14 @@ HookReply DerivationGoal::tryBuildHook() /* Tell the hooks the missing outputs that have to be copied back from the remote system. */ { - StorePathSet missingPaths; - for (auto & [_, status] : initialOutputs) { + StringSet missingOutputs; + for (auto & [outputName, status] : initialOutputs) { if (!status.known) continue; if (buildMode != bmCheck && status.known->isValid()) continue; - missingPaths.insert(status.known->path); + missingOutputs.insert(outputName); + /* missingPaths.insert(status.known->path); */ } - worker_proto::write(worker.store, hook->sink, missingPaths); + worker_proto::write(worker.store, hook->sink, missingOutputs); } hook->sink = FdSink(); diff --git a/src/libstore/realisation.hh b/src/libstore/realisation.hh index 7c91d802a..fc92d3c17 100644 --- a/src/libstore/realisation.hh +++ b/src/libstore/realisation.hh @@ -33,6 +33,8 @@ struct Realisation { GENERATE_CMP(Realisation, me->id, me->outPath); }; +typedef std::map DrvOutputs; + struct OpaquePath { StorePath path; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index be07f02dc..52d633372 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -12,6 +12,7 @@ #include "logging.hh" #include "callback.hh" #include "filetransfer.hh" +#include namespace nix { @@ -49,6 +50,21 @@ void write(const Store & store, Sink & out, const ContentAddress & ca) out << renderContentAddress(ca); } +Realisation read(const Store & store, Source & from, Phantom _) +{ + std::string rawInput = readString(from); + return Realisation::fromJSON( + nlohmann::json::parse(rawInput), + "remote-protocol" + ); +} +void write(const Store & store, Sink & out, const Realisation & realisation) +{ out << realisation.toJSON().dump(); } + +DrvOutput read(const Store & store, Source & from, Phantom _) +{ return DrvOutput::parse(readString(from)); } +void write(const Store & store, Sink & out, const DrvOutput & drvOutput) +{ out << drvOutput.to_string(); } std::optional read(const Store & store, Source & from, Phantom> _) { diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 6dcd43ed1..ea6389ba4 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -162,6 +162,8 @@ struct BuildResult non-determinism.) */ bool isNonDeterministic = false; + DrvOutputs builtOutputs; + /* The start/stop times of the build (or one of the rounds, if it was repeated). */ time_t startTime = 0, stopTime = 0; diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index f2cdc7ca3..5e094c378 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -86,6 +86,8 @@ namespace worker_proto { MAKE_WORKER_PROTO(, std::string); MAKE_WORKER_PROTO(, StorePath); MAKE_WORKER_PROTO(, ContentAddress); +MAKE_WORKER_PROTO(, Realisation); +MAKE_WORKER_PROTO(, DrvOutput); MAKE_WORKER_PROTO(template, std::set);