mirror of
https://github.com/NixOS/nix.git
synced 2025-11-08 19:46:02 +01:00
Merge 0c53c88367 into 479b6b73a9
This commit is contained in:
commit
0ae52d1101
4 changed files with 205 additions and 14 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue