1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 19:46:02 +01:00
This commit is contained in:
Marcel 2025-11-07 22:51:13 +00:00 committed by GitHub
commit 0ae52d1101
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 205 additions and 14 deletions

View file

@ -467,8 +467,6 @@ public:
std::string getStatus(State & state)
{
auto MiB = 1024.0 * 1024.0;
std::string res;
auto renderActivity =
@ -516,6 +514,65 @@ public:
return s;
};
auto renderSizeActivity = [&](ActivityType type, const std::string & itemFmt = "%s") {
auto & act = state.activitiesByType[type];
uint64_t done = act.done, expected = act.done, running = 0, failed = act.failed;
for (auto & j : act.its) {
done += j.second->done;
expected += j.second->expected;
running += j.second->running;
failed += j.second->failed;
}
expected = std::max(expected, act.expected);
std::optional<SizeUnit> commonUnit;
std::string s;
if (running || done || expected || failed) {
if (running)
if (expected != 0) {
commonUnit = getCommonSizeUnit({(int64_t) running, (int64_t) done, (int64_t) expected});
s =
fmt(ANSI_BLUE "%s" ANSI_NORMAL "/" ANSI_GREEN "%s" ANSI_NORMAL "/%s",
commonUnit ? renderSizeWithoutUnit(running, *commonUnit) : renderSize(running),
commonUnit ? renderSizeWithoutUnit(done, *commonUnit) : renderSize(done),
commonUnit ? renderSizeWithoutUnit(expected, *commonUnit) : renderSize(expected));
} else {
commonUnit = getCommonSizeUnit({(int64_t) running, (int64_t) done});
s =
fmt(ANSI_BLUE "%s" ANSI_NORMAL "/" ANSI_GREEN "%s" ANSI_NORMAL,
commonUnit ? renderSizeWithoutUnit(running, *commonUnit) : renderSize(running),
commonUnit ? renderSizeWithoutUnit(done, *commonUnit) : renderSize(done));
}
else if (expected != done)
if (expected != 0) {
commonUnit = getCommonSizeUnit({(int64_t) done, (int64_t) expected});
s =
fmt(ANSI_GREEN "%s" ANSI_NORMAL "/%s",
commonUnit ? renderSizeWithoutUnit(done, *commonUnit) : renderSize(done),
commonUnit ? renderSizeWithoutUnit(expected, *commonUnit) : renderSize(expected));
} else {
commonUnit = getSizeUnit(done);
s = fmt(ANSI_GREEN "%s" ANSI_NORMAL, renderSizeWithoutUnit(done, *commonUnit));
}
else {
commonUnit = getSizeUnit(done);
s = fmt(done ? ANSI_GREEN "%s" ANSI_NORMAL : "%s", renderSizeWithoutUnit(done, *commonUnit));
}
if (commonUnit)
s = fmt("%s %siB", s, getSizeUnitSuffix(*commonUnit));
s = fmt(itemFmt, s);
if (failed)
s += fmt(" (" ANSI_RED "%s failed" ANSI_NORMAL ")", renderSize(failed));
}
return s;
};
auto showActivity =
[&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) {
auto s = renderActivity(type, itemFmt, numberFmt, unit);
@ -529,7 +586,7 @@ public:
showActivity(actBuilds, "%s built");
auto s1 = renderActivity(actCopyPaths, "%s copied");
auto s2 = renderActivity(actCopyPath, "%s MiB", "%.1f", MiB);
auto s2 = renderSizeActivity(actCopyPath);
if (!s1.empty() || !s2.empty()) {
if (!res.empty())
@ -545,12 +602,12 @@ public:
}
}
showActivity(actFileTransfer, "%s MiB DL", "%.1f", MiB);
renderSizeActivity(actFileTransfer, "%s DL");
{
auto s = renderActivity(actOptimiseStore, "%s paths optimised");
if (s != "") {
s += fmt(", %.1f MiB / %d inodes freed", state.bytesLinked / MiB, state.filesLinked);
s += fmt(", %s / %d inodes freed", renderSize(state.bytesLinked), state.filesLinked);
if (!res.empty())
res += ", ";
res += s;

View file

@ -146,6 +146,59 @@ TEST(string2Int, trivialConversions)
ASSERT_EQ(string2Int<int>("-100"), -100);
}
/* ----------------------------------------------------------------------------
* getSizeUnit
* --------------------------------------------------------------------------*/
TEST(getSizeUnit, misc)
{
ASSERT_EQ(getSizeUnit(0), SizeUnit::Base);
ASSERT_EQ(getSizeUnit(100), SizeUnit::Base);
ASSERT_EQ(getSizeUnit(100), SizeUnit::Base);
ASSERT_EQ(getSizeUnit(972), SizeUnit::Base);
ASSERT_EQ(getSizeUnit(973), SizeUnit::Base); // FIXME: should round down
ASSERT_EQ(getSizeUnit(1024), SizeUnit::Base);
ASSERT_EQ(getSizeUnit(-1024), SizeUnit::Base);
ASSERT_EQ(getSizeUnit(1024 * 1024), SizeUnit::Kilo);
ASSERT_EQ(getSizeUnit(1100 * 1024), SizeUnit::Mega);
ASSERT_EQ(getSizeUnit(2ULL * 1024 * 1024 * 1024), SizeUnit::Giga);
ASSERT_EQ(getSizeUnit(2100ULL * 1024 * 1024 * 1024), SizeUnit::Tera);
}
/* ----------------------------------------------------------------------------
* getCommonSizeUnit
* --------------------------------------------------------------------------*/
TEST(getCommonSizeUnit, misc)
{
ASSERT_EQ(getCommonSizeUnit({0}), SizeUnit::Base);
ASSERT_EQ(getCommonSizeUnit({0, 100}), SizeUnit::Base);
ASSERT_EQ(getCommonSizeUnit({100, 0}), SizeUnit::Base);
ASSERT_EQ(getCommonSizeUnit({100, 1024 * 1024}), std::nullopt);
ASSERT_EQ(getCommonSizeUnit({1024 * 1024, 100}), std::nullopt);
ASSERT_EQ(getCommonSizeUnit({1024 * 1024, 1024 * 1024}), SizeUnit::Kilo);
ASSERT_EQ(getCommonSizeUnit({2100ULL * 1024 * 1024 * 1024, 2100ULL * 1024 * 1024 * 1024}), SizeUnit::Tera);
}
/* ----------------------------------------------------------------------------
* renderSizeWithoutUnit
* --------------------------------------------------------------------------*/
TEST(renderSizeWithoutUnit, misc)
{
ASSERT_EQ(renderSizeWithoutUnit(0, SizeUnit::Base, true), " 0.0");
ASSERT_EQ(renderSizeWithoutUnit(100, SizeUnit::Base, true), " 0.1");
ASSERT_EQ(renderSizeWithoutUnit(100, SizeUnit::Base), "0.1");
ASSERT_EQ(renderSizeWithoutUnit(972, SizeUnit::Base, true), " 0.9");
ASSERT_EQ(renderSizeWithoutUnit(973, SizeUnit::Base, true), " 1.0"); // FIXME: should round down
ASSERT_EQ(renderSizeWithoutUnit(1024, SizeUnit::Base, true), " 1.0");
ASSERT_EQ(renderSizeWithoutUnit(-1024, SizeUnit::Base, true), " -1.0");
ASSERT_EQ(renderSizeWithoutUnit(1024 * 1024, SizeUnit::Kilo, true), "1024.0");
ASSERT_EQ(renderSizeWithoutUnit(1100 * 1024, SizeUnit::Mega, true), " 1.1");
ASSERT_EQ(renderSizeWithoutUnit(2ULL * 1024 * 1024 * 1024, SizeUnit::Giga, true), " 2.0");
ASSERT_EQ(renderSizeWithoutUnit(2100ULL * 1024 * 1024 * 1024, SizeUnit::Tera, true), " 2.1");
}
/* ----------------------------------------------------------------------------
* renderSize
* --------------------------------------------------------------------------*/

View file

@ -99,6 +99,42 @@ N string2IntWithUnitPrefix(std::string_view s)
throw UsageError("'%s' is not an integer", s);
}
// Base also uses 'K', because it should also displayed as KiB => 100 Bytes => 0.1 KiB
#define NIX_UTIL_SIZE_UNITS \
NIX_UTIL_DEFINE_SIZE_UNIT(Base, 'K') \
NIX_UTIL_DEFINE_SIZE_UNIT(Kilo, 'K') \
NIX_UTIL_DEFINE_SIZE_UNIT(Mega, 'M') \
NIX_UTIL_DEFINE_SIZE_UNIT(Giga, 'G') \
NIX_UTIL_DEFINE_SIZE_UNIT(Tera, 'T') \
NIX_UTIL_DEFINE_SIZE_UNIT(Peta, 'P') \
NIX_UTIL_DEFINE_SIZE_UNIT(Exa, 'E') \
NIX_UTIL_DEFINE_SIZE_UNIT(Zetta, 'Z') \
NIX_UTIL_DEFINE_SIZE_UNIT(Yotta, 'Y')
enum class SizeUnit {
#define NIX_UTIL_DEFINE_SIZE_UNIT(name, suffix) name,
NIX_UTIL_SIZE_UNITS
#undef NIX_UTIL_DEFINE_SIZE_UNIT
};
constexpr inline auto sizeUnits = std::to_array<SizeUnit>({
#define NIX_UTIL_DEFINE_SIZE_UNIT(name, suffix) SizeUnit::name,
NIX_UTIL_SIZE_UNITS
#undef NIX_UTIL_DEFINE_SIZE_UNIT
});
SizeUnit getSizeUnit(int64_t value);
/**
* Returns the unit if all values would be rendered using the same unit
* otherwise returns `std::nullopt`.
*/
std::optional<SizeUnit> getCommonSizeUnit(std::initializer_list<int64_t> values);
std::string renderSizeWithoutUnit(int64_t value, SizeUnit unit, bool align = false);
char getSizeUnitSuffix(SizeUnit unit);
/**
* Pretty-print a byte value, e.g. 12433615056 is rendered as `11.6
* GiB`. If `align` is set, the number will be right-justified by

View file

@ -132,17 +132,62 @@ std::optional<N> string2Float(const std::string_view s)
template std::optional<double> string2Float<double>(const std::string_view s);
template std::optional<float> string2Float<float>(const std::string_view s);
static const int64_t conversionNumber = 1024;
SizeUnit getSizeUnit(int64_t value)
{
auto unit = sizeUnits.begin();
uint64_t absValue = std::abs(value);
while (absValue > conversionNumber && unit < sizeUnits.end()) {
unit++;
absValue /= conversionNumber;
}
return *unit;
}
std::optional<SizeUnit> getCommonSizeUnit(std::initializer_list<int64_t> values)
{
assert(values.size() > 0);
auto it = values.begin();
SizeUnit unit = getSizeUnit(*it);
it++;
for (; it != values.end(); it++) {
if (unit != getSizeUnit(*it)) {
return std::nullopt;
}
}
return unit;
}
std::string renderSizeWithoutUnit(int64_t value, SizeUnit unit, bool align)
{
// bytes should also displayed as KiB => 100 Bytes => 0.1 KiB
auto power = std::max<std::underlying_type_t<SizeUnit>>(1, std::to_underlying(unit));
double denominator = std::pow(conversionNumber, power);
double result = (double) value / denominator;
return fmt(align ? "%6.1f" : "%.1f", result);
}
char getSizeUnitSuffix(SizeUnit unit)
{
switch (unit) {
#define NIX_UTIL_DEFINE_SIZE_UNIT(name, suffix) \
case SizeUnit::name: \
return suffix;
NIX_UTIL_SIZE_UNITS
#undef NIX_UTIL_DEFINE_SIZE_UNIT
}
assert(false);
}
std::string renderSize(int64_t value, bool align)
{
static const std::array<char, 9> prefixes{{'K', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'}};
size_t power = 0;
double abs_value = std::abs(value);
while (abs_value > 1024 && power < prefixes.size()) {
++power;
abs_value /= 1024;
}
double res = (double) value / std::pow(1024.0, power);
return fmt(align ? "%6.1f %ciB" : "%.1f %ciB", power == 0 ? res / 1024 : res, prefixes.at(power));
SizeUnit unit = getSizeUnit(value);
return fmt("%s %ciB", renderSizeWithoutUnit(value, unit, align), getSizeUnitSuffix(unit));
}
bool hasPrefix(std::string_view s, std::string_view prefix)