diff options
-rw-r--r-- | CMake/Translations.cmake | 1 | ||||
-rw-r--r-- | apt-pkg/depcache.cc | 56 | ||||
-rw-r--r-- | apt-pkg/depcache.h | 4 | ||||
-rw-r--r-- | apt-pkg/init.cc | 2 | ||||
-rw-r--r-- | apt-pkg/install-progress.cc | 12 | ||||
-rw-r--r-- | apt-private/private-install.cc | 71 | ||||
-rw-r--r-- | apt-private/private-output.cc | 16 | ||||
-rw-r--r-- | doc/examples/configure-index | 3 | ||||
-rw-r--r-- | test/libapt/install_progress_test.cc | 20 |
9 files changed, 173 insertions, 12 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-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 <unordered_map> #include <utility> #include <vector> +#include <dirent.h> #include <sys/stat.h> @@ -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-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 <sstream> #include <vector> #include <fcntl.h> +#include <langinfo.h> #include <sys/ioctl.h> #include <unistd.h> @@ -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<int>(std::floor(Percent * BarSize)))); + double dummy; + double const BarDoneFractional = std::modf(Percent * BarSize, &dummy); + const char *const BarDoneFractionalChar = (const char *[]){ + " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}[static_cast<int>(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/apt-private/private-install.cc b/apt-private/private-install.cc index 3efae0112..ecbd703d8 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -28,6 +28,8 @@ #include <map> #include <set> #include <vector> +#include <langinfo.h> +#include <sys/statvfs.h> #include <apt-private/acqprogress.h> #include <apt-private/private-cachefile.h> @@ -322,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 @@ -333,10 +335,69 @@ 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") : _(" Installed size: %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(_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 / %sB available\n"), + SizeToStr(Cache->UsrSize() + InitrdSize).c_str(), SizeToStr((st.f_bsize * st.f_bavail)).c_str()); + + if (Cache->UsrSize() > 0 && static_cast<unsigned long long>(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; + 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. + // (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 + { + // 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, " "); + 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 @@ -380,7 +441,9 @@ 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 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); diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc index f6df3f46c..95dc740cc 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 /*{{{*/ @@ -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. /*{{{*/ 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 "<DIR>" { MountPath "/media/apt"; // Media AutoDetect mount path }; + + Boot "<DIR>"; + Usr "<DIR>"; }; // Things that effect the APT dselect method 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 <apt-pkg/install-progress.h> +#include <locale> #include <string> #include <gtest/gtest.h> @@ -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); } |