diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc index 305345615..013643faf 100644 --- a/src/libmain/progress-bar.cc +++ b/src/libmain/progress-bar.cc @@ -69,6 +69,7 @@ private: ActivityId parent; std::optional name; std::optional> startTime; + PathSet buildsRemaining, substitutionsRemaining; }; struct ActivitiesByType @@ -250,16 +251,49 @@ public: resetHelp(*state); } else { state->helpShown = true; - state->statusLines.insert_or_assign({idHelp, 0}, ""); - state->statusLines.insert_or_assign({idHelp, 1}, ANSI_BOLD "The following keys are available:"); - state->statusLines.insert_or_assign({idHelp, 2}, ANSI_BOLD " 'v' to increase verbosity."); - state->statusLines.insert_or_assign({idHelp, 3}, ANSI_BOLD " '-' to decrease verbosity."); - state->statusLines.insert_or_assign({idHelp, 4}, ANSI_BOLD " 'l' to show build log output."); - state->statusLines.insert_or_assign({idHelp, 5}, ANSI_BOLD " 'q' to quit."); - state->statusLines.insert_or_assign({idHelp, 6}, ""); + size_t n = 0; + state->statusLines.insert_or_assign({idHelp, n++}, ""); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD "The following keys are available:"); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD " 'v' to increase verbosity."); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD " '-' to decrease verbosity."); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD " 'l' to show build log output."); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD " 'r' to show what paths remain to be built/substituted."); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD " 'h' to hide this help message."); + state->statusLines.insert_or_assign({idHelp, n++}, ANSI_BOLD " 'q' to quit."); + state->statusLines.insert_or_assign({idHelp, n++}, ""); } draw(*state); } + if (c == 'r') { + auto state(state_.lock()); + + PathSet buildsRemaining, substitutionsRemaining; + for (auto & act : state->activities) { + for (auto & path : act.buildsRemaining) buildsRemaining.insert(path); + for (auto & path : act.substitutionsRemaining) substitutionsRemaining.insert(path); + } + + std::string msg; + + // FIXME: sort by name? + + if (!buildsRemaining.empty()) { + msg += fmt("\n" ANSI_BOLD "%d derivations remaining to be built:\n" ANSI_NORMAL, buildsRemaining.size()); + for (auto & path : buildsRemaining) + msg += fmt(" • %s\n", path); + } + + if (!substitutionsRemaining.empty()) { + msg += fmt("\n" ANSI_BOLD "%d paths remaining to be substituted:\n" ANSI_NORMAL, substitutionsRemaining.size()); + for (auto & path : substitutionsRemaining) + msg += fmt(" • %s\n", path); + } + + if (buildsRemaining.empty() && substitutionsRemaining.empty()) + msg = "\n" ANSI_BOLD "Nothing left to be built or substituted."; + + draw(*state, chomp(msg)); + } } }); @@ -460,6 +494,10 @@ public: { auto state(state_.lock()); + auto i = state->its.find(act); + assert(i != state->its.end()); + ActInfo & actInfo = *i->second; + if (type == resFileLinked) { state->filesLinked++; state->bytesLinked += getI(fields, 0); @@ -469,8 +507,6 @@ public: else if (type == resBuildLogLine || type == resPostBuildLogLine) { auto lastLine = chomp(getS(fields, 0)); if (!lastLine.empty()) { - auto i = state->its.find(act); - assert(i != state->its.end()); i->second->lastLine = lastLine; if (progressBarSettings.printBuildLogs) { auto suffix = "> "; @@ -494,16 +530,11 @@ public: } else if (type == resSetPhase) { - auto i = state->its.find(act); - assert(i != state->its.end()); i->second->phase = getS(fields, 0); update(*state); } else if (type == resProgress) { - auto i = state->its.find(act); - assert(i != state->its.end()); - ActInfo & actInfo = *i->second; if (!actInfo.ignored) { actInfo.done = getI(fields, 0); actInfo.expected = getI(fields, 1); @@ -514,9 +545,6 @@ public: } else if (type == resSetExpected) { - auto i = state->its.find(act); - assert(i != state->its.end()); - ActInfo & actInfo = *i->second; if (!actInfo.ignored) { auto type = (ActivityType) getI(fields, 0); auto & j = actInfo.expectedByType[type]; @@ -526,6 +554,18 @@ public: update(*state); } } + + else if (type == resExpectBuild) + actInfo.buildsRemaining.insert(getS(fields, 0)); + + else if (type == resUnexpectBuild) + actInfo.buildsRemaining.erase(getS(fields, 0)); + + else if (type == resExpectSubstitution) + actInfo.substitutionsRemaining.insert(getS(fields, 0)); + + else if (type == resUnexpectSubstitution) + actInfo.substitutionsRemaining.erase(getS(fields, 0)); } void update(State & state) diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc index f1227a6a1..ea16b1736 100644 --- a/src/libstore/build/worker.cc +++ b/src/libstore/build/worker.cc @@ -103,12 +103,16 @@ static void removeGoal(std::shared_ptr goal, std::map(goal)) + if (auto drvGoal = std::dynamic_pointer_cast(goal)) { + act.result(resUnexpectBuild, store.printStorePath(drvGoal->drvPath)); nix::removeGoal(drvGoal, derivationGoals); - else if (auto subGoal = std::dynamic_pointer_cast(goal)) + } + else if (auto subGoal = std::dynamic_pointer_cast(goal)) { + act.result(resUnexpectSubstitution, store.printStorePath(subGoal->storePath)); nix::removeGoal(subGoal, substitutionGoals); - else + } else assert(false); + if (topGoals.find(goal) != topGoals.end()) { topGoals.erase(goal); /* If a top-level goal failed, then kill all other goals @@ -223,6 +227,12 @@ void Worker::run(const Goals & _topGoals) uint64_t downloadSize, narSize; store.queryMissing(topPaths, willBuild, willSubstitute, unknown, downloadSize, narSize); + for (auto & path : willBuild) + act.result(resExpectBuild, store.printStorePath(path)); + + for (auto & path : willSubstitute) + act.result(resExpectSubstitution, store.printStorePath(path)); + debug("entered goal loop"); while (1) { diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 35f1facc5..9e564eb29 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -32,6 +32,10 @@ typedef enum { resProgress = 105, resSetExpected = 106, resPostBuildLogLine = 107, + resExpectBuild = 108, + resUnexpectBuild = 109, + resExpectSubstitution = 110, + resUnexpectSubstitution = 111, } ResultType; typedef uint64_t ActivityId;