parent
e30b15ca93
commit
cc005058a9
|
@ -11,6 +11,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <boost/container/static_vector.hpp>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
|
@ -124,31 +126,32 @@ void ProgressBar::startActivity(
|
||||||
.parent = parent,
|
.parent = parent,
|
||||||
.startTime = std::chrono::steady_clock::now()
|
.startTime = std::chrono::steady_clock::now()
|
||||||
});
|
});
|
||||||
auto i = std::prev(state->activities.end());
|
|
||||||
state->its.emplace(act, i);
|
auto mostRecentAct = std::prev(state->activities.end());
|
||||||
state->activitiesByType[type].its.emplace(act, i);
|
state->its.emplace(act, mostRecentAct);
|
||||||
|
state->activitiesByType[type].its.emplace(act, mostRecentAct);
|
||||||
|
|
||||||
if (type == actBuild) {
|
if (type == actBuild) {
|
||||||
std::string name(storePathToName(getS(fields, 0)));
|
std::string name(storePathToName(getS(fields, 0)));
|
||||||
if (name.ends_with(".drv"))
|
if (name.ends_with(".drv"))
|
||||||
name = name.substr(0, name.size() - 4);
|
name = name.substr(0, name.size() - 4);
|
||||||
i->s = fmt("building " ANSI_BOLD "%s" ANSI_NORMAL, name);
|
mostRecentAct->s = fmt("building " ANSI_BOLD "%s" ANSI_NORMAL, name);
|
||||||
auto machineName = getS(fields, 1);
|
auto machineName = getS(fields, 1);
|
||||||
if (machineName != "")
|
if (machineName != "")
|
||||||
i->s += fmt(" on " ANSI_BOLD "%s" ANSI_NORMAL, machineName);
|
mostRecentAct->s += fmt(" on " ANSI_BOLD "%s" ANSI_NORMAL, machineName);
|
||||||
|
|
||||||
// Used to be curRound and nrRounds, but the
|
// Used to be curRound and nrRounds, but the
|
||||||
// implementation was broken for a long time.
|
// implementation was broken for a long time.
|
||||||
if (getI(fields, 2) != 1 || getI(fields, 3) != 1) {
|
if (getI(fields, 2) != 1 || getI(fields, 3) != 1) {
|
||||||
throw Error("log message indicated repeating builds, but this is not currently implemented");
|
throw Error("log message indicated repeating builds, but this is not currently implemented");
|
||||||
}
|
}
|
||||||
i->name = DrvName(name).name;
|
mostRecentAct->name = DrvName(name).name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == actSubstitute) {
|
if (type == actSubstitute) {
|
||||||
auto name = storePathToName(getS(fields, 0));
|
auto name = storePathToName(getS(fields, 0));
|
||||||
auto sub = getS(fields, 1);
|
auto sub = getS(fields, 1);
|
||||||
i->s = fmt(
|
mostRecentAct->s = fmt(
|
||||||
sub.starts_with("local")
|
sub.starts_with("local")
|
||||||
? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s"
|
? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s"
|
||||||
: "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s",
|
: "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s",
|
||||||
|
@ -159,17 +162,17 @@ void ProgressBar::startActivity(
|
||||||
auto name = storePathToName(getS(fields, 0));
|
auto name = storePathToName(getS(fields, 0));
|
||||||
if (name.ends_with(".drv"))
|
if (name.ends_with(".drv"))
|
||||||
name = name.substr(0, name.size() - 4);
|
name = name.substr(0, name.size() - 4);
|
||||||
i->s = fmt("post-build " ANSI_BOLD "%s" ANSI_NORMAL, name);
|
mostRecentAct->s = fmt("post-build " ANSI_BOLD "%s" ANSI_NORMAL, name);
|
||||||
i->name = DrvName(name).name;
|
mostRecentAct->name = DrvName(name).name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == actQueryPathInfo) {
|
if (type == actQueryPathInfo) {
|
||||||
auto name = storePathToName(getS(fields, 0));
|
auto name = storePathToName(getS(fields, 0));
|
||||||
i->s = fmt("querying " ANSI_BOLD "%s" ANSI_NORMAL " on %s", name, getS(fields, 1));
|
mostRecentAct->s = fmt("querying " ANSI_BOLD "%s" ANSI_NORMAL " on %s", name, getS(fields, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ancestorTakesPrecedence(*state, type, parent)) {
|
if (ancestorTakesPrecedence(*state, type, parent)) {
|
||||||
i->visible = false;
|
mostRecentAct->visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(*state);
|
update(*state);
|
||||||
|
@ -199,19 +202,22 @@ void ProgressBar::stopActivity(ActivityId act)
|
||||||
{
|
{
|
||||||
auto state(state_.lock());
|
auto state(state_.lock());
|
||||||
|
|
||||||
auto i = state->its.find(act);
|
auto const currentAct = state->its.find(act);
|
||||||
if (i != state->its.end()) {
|
if (currentAct != state->its.end()) {
|
||||||
|
|
||||||
auto & actByType = state->activitiesByType[i->second->type];
|
std::list<ActInfo>::iterator const & actInfo = currentAct->second;
|
||||||
actByType.done += i->second->done;
|
|
||||||
actByType.failed += i->second->failed;
|
|
||||||
|
|
||||||
for (auto & j : i->second->expectedByType)
|
auto & actByType = state->activitiesByType[actInfo->type];
|
||||||
state->activitiesByType[j.first].expected -= j.second;
|
actByType.done += actInfo->done;
|
||||||
|
actByType.failed += actInfo->failed;
|
||||||
|
|
||||||
|
for (auto const & [type, expected] : actInfo->expectedByType) {
|
||||||
|
state->activitiesByType[type].expected -= expected;
|
||||||
|
}
|
||||||
|
|
||||||
actByType.its.erase(act);
|
actByType.its.erase(act);
|
||||||
state->activities.erase(i->second);
|
state->activities.erase(actInfo);
|
||||||
state->its.erase(i);
|
state->its.erase(currentAct);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(*state);
|
update(*state);
|
||||||
|
@ -230,9 +236,9 @@ void ProgressBar::result(ActivityId act, ResultType type, const std::vector<Fiel
|
||||||
else if (type == resBuildLogLine || type == resPostBuildLogLine) {
|
else if (type == resBuildLogLine || type == resPostBuildLogLine) {
|
||||||
auto lastLine = chomp(getS(fields, 0));
|
auto lastLine = chomp(getS(fields, 0));
|
||||||
if (!lastLine.empty()) {
|
if (!lastLine.empty()) {
|
||||||
auto i = state->its.find(act);
|
auto found = state->its.find(act);
|
||||||
assert(i != state->its.end());
|
assert(found != state->its.end());
|
||||||
ActInfo info = *i->second;
|
ActInfo info = *found->second;
|
||||||
if (printBuildLogs) {
|
if (printBuildLogs) {
|
||||||
auto suffix = "> ";
|
auto suffix = "> ";
|
||||||
if (type == resPostBuildLogLine) {
|
if (type == resPostBuildLogLine) {
|
||||||
|
@ -240,10 +246,10 @@ void ProgressBar::result(ActivityId act, ResultType type, const std::vector<Fiel
|
||||||
}
|
}
|
||||||
log(*state, lvlInfo, ANSI_FAINT + info.name.value_or("unnamed") + suffix + ANSI_NORMAL + lastLine);
|
log(*state, lvlInfo, ANSI_FAINT + info.name.value_or("unnamed") + suffix + ANSI_NORMAL + lastLine);
|
||||||
} else {
|
} else {
|
||||||
state->activities.erase(i->second);
|
state->activities.erase(found->second);
|
||||||
info.lastLine = lastLine;
|
info.lastLine = lastLine;
|
||||||
state->activities.emplace_back(info);
|
state->activities.emplace_back(info);
|
||||||
i->second = std::prev(state->activities.end());
|
found->second = std::prev(state->activities.end());
|
||||||
update(*state);
|
update(*state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,11 +287,11 @@ void ProgressBar::result(ActivityId act, ResultType type, const std::vector<Fiel
|
||||||
auto i = state->its.find(act);
|
auto i = state->its.find(act);
|
||||||
assert(i != state->its.end());
|
assert(i != state->its.end());
|
||||||
ActInfo & actInfo = *i->second;
|
ActInfo & actInfo = *i->second;
|
||||||
auto type = (ActivityType) getI(fields, 0);
|
auto const type = static_cast<ActivityType>(getI(fields, 0));
|
||||||
auto & j = actInfo.expectedByType[type];
|
uint64_t & thisExpected = actInfo.expectedByType[type];
|
||||||
state->activitiesByType[type].expected -= j;
|
state->activitiesByType[type].expected -= thisExpected;
|
||||||
j = getI(fields, 1);
|
thisExpected = getI(fields, 1);
|
||||||
state->activitiesByType[type].expected += j;
|
state->activitiesByType[type].expected += thisExpected;
|
||||||
update(*state);
|
update(*state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,16 +360,24 @@ std::chrono::milliseconds ProgressBar::draw(State & state)
|
||||||
return nextWakeup;
|
return nextWakeup;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ProgressBar::getStatus(State & state)
|
std::string ProgressBar::getStatus(State & state) const
|
||||||
{
|
{
|
||||||
constexpr auto MiB = 1024.0 * 1024.0;
|
constexpr static auto MiB = 1024.0 * 1024.0;
|
||||||
|
|
||||||
std::string res;
|
// Each time the `showActivity` lambda is called:
|
||||||
|
// actBuild, actFileTransfer, actVerifyPaths,
|
||||||
|
// + 3 permutations for actCopyPaths, actCopyPath,
|
||||||
|
// + corrupted and unstrusted paths.
|
||||||
|
constexpr static auto MAX_PARTS = 8;
|
||||||
|
|
||||||
|
// Stack-allocated vector.
|
||||||
|
// No need to heap allocate here when we have such a low maxiumum.
|
||||||
|
boost::container::static_vector<std::string, MAX_PARTS> parts;
|
||||||
|
|
||||||
auto renderActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) {
|
auto renderActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) {
|
||||||
auto & act = state.activitiesByType[type];
|
auto const & act = state.activitiesByType[type];
|
||||||
uint64_t done = act.done, expected = act.done, running = 0, failed = act.failed;
|
uint64_t done = act.done, expected = act.done, running = 0, failed = act.failed;
|
||||||
for (auto & [actId, infoIt] : act.its) {
|
for (auto const & [actId, infoIt] : act.its) {
|
||||||
done += infoIt->done;
|
done += infoIt->done;
|
||||||
expected += infoIt->expected;
|
expected += infoIt->expected;
|
||||||
running += infoIt->running;
|
running += infoIt->running;
|
||||||
|
@ -428,31 +442,38 @@ std::string ProgressBar::getStatus(State & state)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto showActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) {
|
auto showActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) {
|
||||||
auto s = renderActivity(type, itemFmt, numberFmt, unit);
|
auto rendered = renderActivity(type, itemFmt, numberFmt, unit);
|
||||||
if (s.empty()) return;
|
if (!rendered.empty()) {
|
||||||
if (!res.empty()) res += ", ";
|
parts.emplace_back(std::move(rendered));
|
||||||
res += s;
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
showActivity(actBuilds, "%s built");
|
showActivity(actBuilds, "%s built");
|
||||||
|
|
||||||
auto s1 = renderActivity(actCopyPaths, "%s copied");
|
{
|
||||||
auto s2 = renderActivity(actCopyPath, "%s MiB", "%.1f", MiB);
|
auto const renderedMultiCopy = renderActivity(actCopyPaths, "%s copied");
|
||||||
|
auto const renderedSingleCopy = renderActivity(actCopyPath, "%s MiB", "%.1f", MiB);
|
||||||
|
|
||||||
if (!s1.empty() || !s2.empty()) {
|
if (!renderedMultiCopy.empty() || !renderedSingleCopy.empty()) {
|
||||||
if (!res.empty()) res += ", ";
|
std::string part = concatStrings(
|
||||||
if (s1.empty()) res += "0 copied"; else res += s1;
|
renderedMultiCopy.empty() ? "0 copied" : renderedMultiCopy,
|
||||||
if (!s2.empty()) { res += " ("; res += s2; res += ')'; }
|
!renderedSingleCopy.empty() ? fmt(" (%s)", renderedSingleCopy) : ""
|
||||||
|
);
|
||||||
|
parts.emplace_back(std::move(part));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showActivity(actFileTransfer, "%s MiB DL", "%.1f", MiB);
|
showActivity(actFileTransfer, "%s MiB DL", "%.1f", MiB);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto s = renderActivity(actOptimiseStore, "%s paths optimised");
|
auto renderedOptimise = renderActivity(actOptimiseStore, "%s paths optimised");
|
||||||
if (s != "") {
|
if (!renderedOptimise.empty()) {
|
||||||
s += fmt(", %.1f MiB / %d inodes freed", state.bytesLinked / MiB, state.filesLinked);
|
parts.emplace_back(std::move(renderedOptimise));
|
||||||
if (!res.empty()) res += ", ";
|
parts.emplace_back(fmt(
|
||||||
res += s;
|
"%.1f MiB / %d inodes freed",
|
||||||
|
state.bytesLinked / MiB,
|
||||||
|
state.filesLinked
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,16 +481,14 @@ std::string ProgressBar::getStatus(State & state)
|
||||||
showActivity(actVerifyPaths, "%s paths verified");
|
showActivity(actVerifyPaths, "%s paths verified");
|
||||||
|
|
||||||
if (state.corruptedPaths) {
|
if (state.corruptedPaths) {
|
||||||
if (!res.empty()) res += ", ";
|
parts.emplace_back(fmt(ANSI_RED "%d corrupted" ANSI_NORMAL, state.corruptedPaths));
|
||||||
res += fmt(ANSI_RED "%d corrupted" ANSI_NORMAL, state.corruptedPaths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.untrustedPaths) {
|
if (state.untrustedPaths) {
|
||||||
if (!res.empty()) res += ", ";
|
parts.emplace_back(fmt(ANSI_RED "%d untrusted" ANSI_NORMAL, state.untrustedPaths));
|
||||||
res += fmt(ANSI_RED "%d untrusted" ANSI_NORMAL, state.untrustedPaths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return concatStringsSep(", ", parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressBar::writeToStdout(std::string_view s)
|
void ProgressBar::writeToStdout(std::string_view s)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
|
#include "escape-string.hh"
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
#include "error.hh"
|
#include "error.hh"
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
|
@ -111,6 +112,18 @@ public:
|
||||||
Field(const std::string & s) : type(tString), s(s) { }
|
Field(const std::string & s) : type(tString), s(s) { }
|
||||||
Field(const char * s) : type(tString), s(s) { }
|
Field(const char * s) : type(tString), s(s) { }
|
||||||
Field(const uint64_t & i) : type(tInt), i(i) { }
|
Field(const uint64_t & i) : type(tInt), i(i) { }
|
||||||
|
|
||||||
|
inline std::string to_string() const
|
||||||
|
{
|
||||||
|
switch (this->type) {
|
||||||
|
case tString:
|
||||||
|
return fmt("Field { s = \"%s\" }", escapeString(this->s, EscapeStringOptions{
|
||||||
|
.escapeNonPrinting = true,
|
||||||
|
}));
|
||||||
|
case tInt:
|
||||||
|
return fmt("Field { i = %d }", this->i);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Field> Fields;
|
typedef std::vector<Field> Fields;
|
||||||
|
|
|
@ -19,13 +19,18 @@ static_assert(EXPECTED == EXPECTED_RAW, "Hey, hey, the ANSI escape code definiti
|
||||||
|
|
||||||
namespace nix
|
namespace nix
|
||||||
{
|
{
|
||||||
TEST(ProgressBar, basicStatusRender) {
|
ProgressBar & init()
|
||||||
|
{
|
||||||
initNix();
|
initNix();
|
||||||
initGC();
|
initGC();
|
||||||
|
|
||||||
startProgressBar();
|
startProgressBar();
|
||||||
ASSERT_NE(dynamic_cast<ProgressBar *>(logger), nullptr);
|
|
||||||
ProgressBar & progressBar = dynamic_cast<ProgressBar &>(*logger);
|
assert(dynamic_cast<ProgressBar *>(logger) != nullptr);
|
||||||
|
return dynamic_cast<ProgressBar &>(*logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ProgressBar, basicStatusRender) {
|
||||||
|
ProgressBar & progressBar = init();
|
||||||
|
|
||||||
Activity act(
|
Activity act(
|
||||||
progressBar,
|
progressBar,
|
||||||
|
@ -40,4 +45,40 @@ namespace nix
|
||||||
|
|
||||||
ASSERT_EQ(renderedStatus, EXPECTED);
|
ASSERT_EQ(renderedStatus, EXPECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TEST(ProgressBar, resultPermute) {
|
||||||
|
// ProgressBar & progressBar = init();
|
||||||
|
//
|
||||||
|
// Activity act(
|
||||||
|
// progressBar,
|
||||||
|
// lvlDebug,
|
||||||
|
// actBuild,
|
||||||
|
// "building '/nix/store/zdp9na4ci9s3g68xi9hnn5gbllf6ak03-lix-2.91.0-dev-lixpre20240616-0ba37dc.drv'",
|
||||||
|
// Logger::Fields{
|
||||||
|
// "/nix/store/zdp9na4ci9s3g68xi9hnn5gbllf6ak03-lix-2.91.0-dev-lixpre20240616-0ba37dc.drv",
|
||||||
|
// "",
|
||||||
|
// 1,
|
||||||
|
// 1,
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// act.progress(
|
||||||
|
// /* done */ 13,
|
||||||
|
// /* expected */ 156,
|
||||||
|
// /* running */ 2,
|
||||||
|
// /* failed */ 0
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// act.progress(
|
||||||
|
// /* done */ 13,
|
||||||
|
// /* expected */ 156,
|
||||||
|
// /* running */ 2,
|
||||||
|
// /* failed */ 0
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// auto state = progressBar.state_.lock();
|
||||||
|
// std::string const autoStatus = progressBar.getStatus(*state);
|
||||||
|
//
|
||||||
|
// ASSERT_EQ(autoStatus, "a");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue