From 9d864c7dab6499eb99d8ec8c932826b1db67c335 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 19:05:00 +0200 Subject: Rename "Installed size:" to "Space needed:" --- apt-private/private-install.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 3efae0112..4cf10b481 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -335,7 +335,7 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo if (Cache->UsrSize() >= 0) //TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - ioprintf(c1out,outVer < 30 ? _("After this operation, %sB of additional disk space will be used.\n") : _(" Installed size: %sB\n"), + ioprintf(c1out,outVer < 30 ? _("After this operation, %sB of additional disk space will be used.\n") : _(" Space needed: %sB\n"), SizeToStr(Cache->UsrSize()).c_str()); else //TRANSLATOR: The required space between number and unit is already included -- cgit v1.2.3-70-g09d2 From 979a018c2fd3fa253c7edc05f35f202f631c2d05 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 19:27:32 +0200 Subject: Space needed: Show space available in /usr --- apt-private/private-install.cc | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 4cf10b481..a7fa54f31 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -333,10 +334,30 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo // Size delta if (Cache->UsrSize() >= 0) + { //TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - ioprintf(c1out,outVer < 30 ? _("After this operation, %sB of additional disk space will be used.\n") : _(" Space needed: %sB\n"), - SizeToStr(Cache->UsrSize()).c_str()); + if (outVer < 30) + ioprintf(c1out, _("After this operation, %sB of additional disk space will be used.\n"), + SizeToStr(Cache->UsrSize()).c_str()); + else + { + struct statvfs st; + if (statvfs("/usr", &st) == 0) + { + // TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + ioprintf(c1out, _(" Space needed: %sB / approx. %sB available\n"), + SizeToStr(Cache->UsrSize()).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); + } + else + { + // TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + ioprintf(c1out, _(" Space needed: %sB\n"), SizeToStr(Cache->UsrSize()).c_str()); + } + } + } else //TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB -- cgit v1.2.3-70-g09d2 From cf71004551eca23f6d73648bc19f65e8b2a08ce9 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 21:22:36 +0200 Subject: Hide nice subtree character and indentation of summary from translations Also allow us to have utf-8 characters in xgettext, but msgcomm still fails so ugh. This avoids translations messing up the formatting a bit more, at least, and makes apt build again --- CMake/Translations.cmake | 1 + apt-private/private-install.cc | 8 +++++--- apt-private/private-output.cc | 14 +++++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CMake/Translations.cmake b/CMake/Translations.cmake index 24925105c..a7fe6c95b 100644 --- a/CMake/Translations.cmake +++ b/CMake/Translations.cmake @@ -16,6 +16,7 @@ function(apt_add_translation_domain) set(domain ${NLS_DOMAIN}) set(xgettext_params --add-comments + --from-code=utf-8 --foreign --package-name=${PROJECT_NAME} --package-version=${PACKAGE_VERSION} diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index a7fa54f31..13c90c6fc 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -345,16 +345,18 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo struct statvfs st; if (statvfs("/usr", &st) == 0) { + ioprintf(c1out, " "); // TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - ioprintf(c1out, _(" Space needed: %sB / approx. %sB available\n"), - SizeToStr(Cache->UsrSize()).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); + ioprintf(c1out, _("Space needed: %sB / approx. %sB available\n"), + SizeToStr(Cache->UsrSize() + InitrdSize).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); } else { // TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - ioprintf(c1out, _(" Space needed: %sB\n"), SizeToStr(Cache->UsrSize()).c_str()); + ioprintf(c1out, " "); + ioprintf(c1out, _("Space needed: %sB\n"), SizeToStr(Cache->UsrSize()).c_str()); } } } diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc index bbf50397f..30db3d5e7 100644 --- a/apt-private/private-output.cc +++ b/apt-private/private-output.cc @@ -758,9 +758,11 @@ void Stats(ostream &out, pkgDepCache &Dep, APT::PackageVector const &HeldBackPac if (Dep[I].Delete() == false && (Dep[I].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall) ReInstall++; } - if (outVer >= 30) - ioprintf(out, _("Summary:\n")); - ioprintf(out,outVer < 30 ? _("%lu upgraded, %lu newly installed, ") : _(" Upgrading: %lu, Installing: %lu, "), + if (outVer >= 30) { + ioprintf(out, _("Summary:")); + ioprintf(out, "\n "); + } + ioprintf(out,outVer < 30 ? _("%lu upgraded, %lu newly installed, ") : _("Upgrading: %lu, Installing: %lu, "), Upgrade,Install); if (ReInstall != 0) @@ -771,10 +773,12 @@ void Stats(ostream &out, pkgDepCache &Dep, APT::PackageVector const &HeldBackPac ioprintf(out, outVer < 30 ? _("%lu to remove and %lu not upgraded.\n") : _("Removing: %lu, Not Upgrading: %lu\n"), Dep.DelCount(), HeldBackPackages.size()); - // FIXME: outVer - if (Dep.BadCount() != 0) + if (Dep.BadCount() != 0) { + if (outVer >= 30) + ioprintf(out, " "); ioprintf(out,_("%lu not fully installed or removed.\n"), Dep.BadCount()); + } } /*}}}*/ // YnPrompt - Yes No Prompt. /*{{{*/ -- cgit v1.2.3-70-g09d2 From f7e5ed3c8dffcdfc2c55c63f2e3cbcb390bbf013 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 20:27:48 +0200 Subject: Show space estimate for /boot, if separate; or estimate initrd for /usr Calculate an estimate of 110% of the biggest initrd + system.map as the additional space a kernel needs in /boot. If /boot is a different file system than /usr, print the size of the kernels + the additional space they will need separately; otherwise include it in our /usr figure. --- apt-pkg/depcache.cc | 56 ++++++++++++++++++++++++++++++++++++++++++ apt-pkg/depcache.h | 4 ++- apt-pkg/init.cc | 2 ++ apt-private/private-install.cc | 23 ++++++++++++++++- doc/examples/configure-index | 3 +++ 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index e3e8d627c..76a5c09ba 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -2613,3 +2614,58 @@ bool pkgDepCache::PhasingApplied(pkgCache::PkgIterator Pkg) const return true; } /*}}}*/ + +// DepCache::BootSize /*{{{*/ +double pkgDepCache::BootSize(bool initrdOnly) +{ + double BootSize = 0; + int BootCount = 0; + auto VirtualKernelPkg = FindPkg("$kernel", "any"); + if (VirtualKernelPkg.end()) + return 0; + + for (pkgCache::PrvIterator Prv = VirtualKernelPkg.ProvidesList(); Prv.end() == false; ++Prv) + { + auto Pkg = Prv.OwnerPkg(); + if ((*this)[Pkg].NewInstall()) + BootSize += (*this)[Pkg].InstallVer->InstalledSize, BootCount++; + } + if (BootCount == 0) + return 0; + if (initrdOnly) + BootSize = 0; + + DIR *boot = opendir(_config->FindDir("Dir::Boot").c_str()); + struct dirent *ent; + if (boot) + { + double initrdSize = 0; + double mapSize = 0; + while ((ent = readdir(boot))) + { + enum + { + INITRD, + MAP + } type; + if (APT::String::Startswith(ent->d_name, "initrd.img-")) + type = INITRD; + else if (APT::String::Startswith(ent->d_name, "System.map-")) + type = MAP; + else + continue; + + auto path = _config->FindDir("Dir::Boot") + ent->d_name; + + if (struct stat st; stat(path.c_str(), &st) == 0) + { + double &targetSize = type == INITRD ? initrdSize : mapSize; + targetSize = std::max(targetSize, double(st.st_size)); + } + } + closedir(boot); + return initrdSize ? BootSize + BootCount * (initrdSize + mapSize) * 1.1 : 0; + } + return 0; +} + /*}}}*/ diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 5dd022b56..23047b97a 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -490,7 +490,9 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace virtual ~pkgDepCache(); bool CheckConsistency(char const *const msgtag = ""); - +#ifdef APT_COMPILING_APT + double BootSize(bool initrdOnly); +#endif protected: // methods call by IsInstallOk bool IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg, diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 75935404f..487f94f20 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -147,6 +147,8 @@ bool pkgInitConfig(Configuration &Cnf) // Configuration Cnf.CndSet("Dir::Etc", &CONF_DIR[1]); + Cnf.CndSet("Dir::Boot", "boot"); + Cnf.CndSet("Dir::Usr", "usr"); Cnf.CndSet("Dir::Etc::sourcelist","sources.list"); Cnf.CndSet("Dir::Etc::sourceparts","sources.list.d"); Cnf.CndSet("Dir::Etc::main","apt.conf"); diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 13c90c6fc..c67b71cb3 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -343,13 +344,33 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo else { struct statvfs st; - if (statvfs("/usr", &st) == 0) + if (statvfs(_config->FindDir("Dir::Usr").c_str(), &st) == 0) { + struct statvfs st_boot; + double BootSize = 0; + double InitrdSize = 0; + if (statvfs(_config->FindDir("Dir::Boot").c_str(), &st_boot) == 0 && st_boot.f_fsid != st.f_fsid) + BootSize = Cache->BootSize(false); + else + InitrdSize = Cache->BootSize(true); /* initrd only, adding to /usr space */ + ioprintf(c1out, " "); // TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB ioprintf(c1out, _("Space needed: %sB / approx. %sB available\n"), SizeToStr(Cache->UsrSize() + InitrdSize).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); + + if (BootSize != 0) + { + bool Unicode = strcmp(nl_langinfo(CODESET), "UTF-8") == 0; + ioprintf(c1out, Unicode ? " └─ " : " - "); + // TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - + // The first %s is the location of the boot directory (determined from Dir::Boot), + // and it tells the space being needed there. + ioprintf(c1out, _("in %s: approx. %sB / %sB available\n"), + _config->FindFile("Dir::Boot").c_str(), SizeToStr(BootSize).c_str(), SizeToStr((st_boot.f_bsize * st_boot.f_bavail)).c_str()); + } } else { diff --git a/doc/examples/configure-index b/doc/examples/configure-index index cc9a2e765..72e907507 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -487,6 +487,9 @@ Dir "" { MountPath "/media/apt"; // Media AutoDetect mount path }; + + Boot ""; + Usr ""; }; // Things that effect the APT dselect method -- cgit v1.2.3-70-g09d2 From 5afcac6ffbf41d4d3a586b64b43882d5e86fc67f Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 21:39:07 +0200 Subject: Remove approx. from space estimates; and do some alignment This aligns the /boot message with the parent one, and also align the formatting of the partially downloaded size message to add spaces around / --- apt-private/private-install.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index c67b71cb3..d3486b96f 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -324,7 +324,7 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo if (DebBytes != FetchBytes) //TRANSLATOR: The required space between number and unit is already included // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB - ioprintf(c1out,outVer < 30 ? _("Need to get %sB/%sB of archives.\n") : _(" Download size: %sB/%sB\n"), + ioprintf(c1out,outVer < 30 ? _("Need to get %sB/%sB of archives.\n") : _(" Download size: %sB / %sB\n"), SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); else if (DebBytes != 0) //TRANSLATOR: The required space between number and unit is already included @@ -357,7 +357,7 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo ioprintf(c1out, " "); // TRANSLATOR: The required space between number and unit is already included // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - ioprintf(c1out, _("Space needed: %sB / approx. %sB available\n"), + ioprintf(c1out, _("Space needed: %sB / %sB available\n"), SizeToStr(Cache->UsrSize() + InitrdSize).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); if (BootSize != 0) @@ -368,7 +368,8 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB - // The first %s is the location of the boot directory (determined from Dir::Boot), // and it tells the space being needed there. - ioprintf(c1out, _("in %s: approx. %sB / %sB available\n"), + // (We have two spaces to align with parent "space needed:"for /boot) + ioprintf(c1out, _("in %s: %sB / %sB available\n"), _config->FindFile("Dir::Boot").c_str(), SizeToStr(BootSize).c_str(), SizeToStr((st_boot.f_bsize * st_boot.f_bavail)).c_str()); } } -- cgit v1.2.3-70-g09d2 From cf9bebba1c92e937f639a229d46fea4e24cfa9df Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 20:51:50 +0200 Subject: Add warnings if space estimate exceeds free space --- apt-private/private-install.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index d3486b96f..b5dd895bc 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -360,6 +360,14 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo ioprintf(c1out, _("Space needed: %sB / %sB available\n"), SizeToStr(Cache->UsrSize() + InitrdSize).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); + if (Cache->UsrSize() > 0 && static_cast(Cache->UsrSize()) > (st.f_bsize * st.f_bavail)) + { + // TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + _error->Warning(_("More space needed than available: %sB > %sB, installation may fail"), + SizeToStr(Cache->UsrSize()).c_str(), + SizeToStr((st.f_bsize * st.f_bavail)).c_str()); + } if (BootSize != 0) { bool Unicode = strcmp(nl_langinfo(CODESET), "UTF-8") == 0; @@ -371,6 +379,14 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo // (We have two spaces to align with parent "space needed:"for /boot) ioprintf(c1out, _("in %s: %sB / %sB available\n"), _config->FindFile("Dir::Boot").c_str(), SizeToStr(BootSize).c_str(), SizeToStr((st_boot.f_bsize * st_boot.f_bavail)).c_str()); + if (BootSize > (st_boot.f_bsize * st_boot.f_bavail)) + // TRANSLATOR: The required space between number and unit is already included + // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB + // The first %s is the location of the boot directory (determined from Dir::Boot) + _error->Warning(_("More space needed in %s than available: %sB > %sB, installation may fail"), + _config->FindFile("Dir::Boot").c_str(), + SizeToStr(BootSize).c_str(), + SizeToStr((st_boot.f_bsize * st_boot.f_bavail)).c_str()); } } else -- cgit v1.2.3-70-g09d2 From 964ffc6664d7301c9947c4c83656846b4789f097 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 21:11:03 +0200 Subject: install: Show downgrades as yellow dnf shows downgrades as green because the package comes from a remote repository, but I think yellow is more indicative that they are unsupported. Ganneff asked for yellow for kept packages too, however I'm not adding yellow there, as kept packages are more indicative of an archive error, likely temporary, rather than an action item for the user. --- apt-private/private-output.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc index 30db3d5e7..5b7a3bab3 100644 --- a/apt-private/private-output.cc +++ b/apt-private/private-output.cc @@ -642,7 +642,7 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) }, &PrettyFullName, CurrentToCandidateVersion(&Cache), - "APT::Color::Green"); + "APT::Color::Yellow"); } /*}}}*/ // ShowHold - Show held but changed packages /*{{{*/ -- cgit v1.2.3-70-g09d2 From 0ea8b5a34118d57e8aad7229360a5acafa1d1c1e Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 22:04:15 +0200 Subject: Use "Continue anyway?" if a warning is queued --- apt-private/private-install.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index b5dd895bc..b53aea167 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -441,7 +441,8 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo if (_config->FindI("quiet",0) < 2 && _config->FindB("APT::Get::Assume-Yes",false) == false) { - if (YnPrompt(outVer < 30 ? _("Do you want to continue?") : _("Continue?")) == false) + // YnPrompt shows all warnings before prompting, so ask stronger if we have any + if (YnPrompt(outVer < 30 ? _("Do you want to continue?") : (_error->empty() ? _("Continue?") : _("Continue anyway?"))) == false) { c2out << _("Abort.") << std::endl; exit(1); -- cgit v1.2.3-70-g09d2 From ffe5a25fdb0dd178ba36b9f72c5213565adf19f0 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 22:37:38 +0200 Subject: apt: Default to N in the y/N prompt if there were warnings This especially helps with the running out of space warnings to be safe. --- apt-private/private-install.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index b53aea167..ecbd703d8 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -441,8 +441,9 @@ bool InstallPackages(CacheFile &Cache, APT::PackageVector &HeldBackPackages, boo if (_config->FindI("quiet",0) < 2 && _config->FindB("APT::Get::Assume-Yes",false) == false) { - // YnPrompt shows all warnings before prompting, so ask stronger if we have any - if (YnPrompt(outVer < 30 ? _("Do you want to continue?") : (_error->empty() ? _("Continue?") : _("Continue anyway?"))) == false) + // YnPrompt shows all warnings before prompting, so ask stronger and default to N if we have any. + auto Default = outVer < 30 ? true : _error->empty(); + if (not YnPrompt(outVer < 30 ? _("Do you want to continue?") : (Default ? _("Continue?") : _("Continue anyway?")), Default)) { c2out << _("Abort.") << std::endl; exit(1); -- cgit v1.2.3-70-g09d2 From ac8fe4b030754584cda9cb1707fc3d9f0d792366 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sat, 13 Apr 2024 23:59:41 +0200 Subject: apt: Use unicode install progress bar on UTF-8 locales This produces a much more appealing progress bar and it can even show parts of the progress being done. --- apt-pkg/install-progress.cc | 12 +++++++++++- test/libapt/install_progress_test.cc | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/apt-pkg/install-progress.cc b/apt-pkg/install-progress.cc index 2b0dc21ea..fe3324426 100644 --- a/apt-pkg/install-progress.cc +++ b/apt-pkg/install-progress.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -344,14 +345,23 @@ void PackageManagerFancy::Stop() std::string PackageManagerFancy::GetTextProgressStr(float Percent, int OutputSize) { + bool Unicode = strcmp(nl_langinfo(CODESET), "UTF-8") == 0; std::string output; if (unlikely(OutputSize < 3)) return output; int const BarSize = OutputSize - 2; // bar without the leading "[" and trailing "]" int const BarDone = std::max(0, std::min(BarSize, static_cast(std::floor(Percent * BarSize)))); + double dummy; + double const BarDoneFractional = std::modf(Percent * BarSize, &dummy); + const char *const BarDoneFractionalChar = (const char *[]){ + " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}[static_cast(std::floor(BarDoneFractional * 8))]; output.append("["); - std::fill_n(std::fill_n(std::back_inserter(output), BarDone, '#'), BarSize - BarDone, '.'); + for (int i = 0; i < BarDone; i++) + output.append(Unicode ? "█" : "#"); + if (BarDone + 1 <= BarSize) + output.append(Unicode ? BarDoneFractionalChar : "."); + std::fill_n(std::back_inserter(output), BarSize - BarDone - 1, Unicode ? ' ' : '.'); output.append("]"); return output; } diff --git a/test/libapt/install_progress_test.cc b/test/libapt/install_progress_test.cc index 68101af9b..7015c619c 100644 --- a/test/libapt/install_progress_test.cc +++ b/test/libapt/install_progress_test.cc @@ -2,6 +2,7 @@ #include +#include #include #include @@ -10,6 +11,7 @@ TEST(InstallProgressTest, FancyGetTextProgressStr) { APT::Progress::PackageManagerFancy p; + char *originalLocale = setlocale(LC_ALL, "C"); EXPECT_EQ(60u, p.GetTextProgressStr(0.5, 60).size()); EXPECT_EQ("[#.]", p.GetTextProgressStr(0.5, 4)); EXPECT_EQ("[..........]", p.GetTextProgressStr(0.0, 12)); @@ -22,4 +24,22 @@ TEST(InstallProgressTest, FancyGetTextProgressStr) // deal with incorrect inputs gracefully (or should we die instead?) EXPECT_EQ("[..........]", p.GetTextProgressStr(-1.0, 12)); EXPECT_EQ("[##########]", p.GetTextProgressStr(2.0, 12)); + + setlocale(LC_ALL, "C.UTF-8"); + + EXPECT_EQ("[█ ]", p.GetTextProgressStr(0.5, 4)); + EXPECT_EQ("[ ]", p.GetTextProgressStr(0.0, 12)); + EXPECT_EQ("[█ ]", p.GetTextProgressStr(0.1, 12)); + EXPECT_EQ("[████ ]", p.GetTextProgressStr(0.4, 12)); + EXPECT_EQ("[████▉ ]", p.GetTextProgressStr(0.4999, 12)); + EXPECT_EQ("[█████ ]", p.GetTextProgressStr(0.5000, 12)); + EXPECT_EQ("[█████ ]", p.GetTextProgressStr(0.5001, 12)); + EXPECT_EQ("[█████████ ]", p.GetTextProgressStr(0.9001, 12)); + EXPECT_EQ("[██████████]", p.GetTextProgressStr(1.0, 12)); + + // deal with incorrect inputs gracefully (or should we die instead?) + EXPECT_EQ("[ ]", p.GetTextProgressStr(-1.0, 12)); + EXPECT_EQ("[██████████]", p.GetTextProgressStr(2.0, 12)); + + setlocale(LC_ALL, originalLocale); } -- cgit v1.2.3-70-g09d2