From e6ad8031b774af9bdd5d460d9983450bb5a03d0d Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Sun, 13 Oct 2013 15:05:04 +0200 Subject: [PATCH] move the status-fd progress reporting out of the pkgDPkgPM class, at this point, breaks ABI/API, lets see what we can do about this --- apt-pkg/deb/dpkgpm.cc | 99 +++++++++------------------------- apt-pkg/deb/dpkgpm.h | 7 +-- apt-pkg/iprogress.cc | 95 +++++++++++++++++++++++++++++--- apt-pkg/iprogress.h | 56 ++++++++++++++++--- apt-pkg/packagemanager.cc | 14 +++-- apt-pkg/packagemanager.h | 18 +++++-- apt-private/private-install.cc | 24 ++++++++- 7 files changed, 211 insertions(+), 102 deletions(-) diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 35adb91f6..0c3be4ce5 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -55,20 +55,12 @@ class pkgDPkgPMPrivate public: pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0), term_out(NULL), history_out(NULL), - last_reported_progress(0.0) + last_reported_progress(0.0), progress(NULL) { dpkgbuf[0] = '\0'; - if(_config->FindB("Dpkg::Progress-Fancy", false) == true) - progress = new APT::Progress::PackageManagerFancy(); - else if (_config->FindB("Dpkg::Progress", - _config->FindB("DpkgPM::Progress", false)) == true) - progress = new APT::Progress::PackageManagerText(); - else - progress = new APT::Progress::PackageManager(); } ~pkgDPkgPMPrivate() { - delete progress; } bool stdin_is_dev_null; @@ -519,11 +511,9 @@ void pkgDPkgPM::DoTerminalPty(int master) // --------------------------------------------------------------------- /* */ -void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) +void pkgDPkgPM::ProcessDpkgStatusLine(char *line) { bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false); - // the status we output - ostringstream status; if (Debug == true) std::clog << "got from dpkg '" << line << "'" << std::endl; @@ -573,7 +563,6 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) // 'processing: action: pkg' if(strncmp(list[0].c_str(), "processing", strlen("processing")) == 0) { - char s[200]; const char* const pkg_or_trigger = list[2].c_str(); action = list[1].c_str(); const std::pair * const iter = @@ -586,17 +575,11 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) std::clog << "ignoring unknown action: " << action << std::endl; return; } - snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger); - - status << "pmstatus:" << pkg_or_trigger - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << s - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + std::string pkg_action; + strprintf(pkg_action, _(iter->second), pkg_or_trigger); + d->progress->StatusChanged(pkg_or_trigger, PackagesDone, PackagesTotal, + pkg_action); if (strncmp(action, "disappear", strlen("disappear")) == 0) handleDisappearAction(pkg_or_trigger); return; @@ -604,28 +587,15 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) if(strncmp(action,"error",strlen("error")) == 0) { - status << "pmerror:" << list[1] - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << list[3] - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + d->progress->Error(list[1], PackagesDone, PackagesTotal, list[3]); pkgFailures++; WriteApportReport(list[1].c_str(), list[3].c_str()); return; } else if(strncmp(action,"conffile",strlen("conffile")) == 0) { - status << "pmconffile:" << list[1] - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << list[3] - << endl; - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + d->progress->ConffilePrompt(list[1], PackagesDone, PackagesTotal, + list[3]); return; } @@ -638,24 +608,15 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) { // only read the translation if there is actually a next // action - const char *translation = _(states[PackageOpsDone[pkg]].str); - char s[200]; - snprintf(s, sizeof(s), translation, pkg); + std::string translation; + strprintf(translation, _(states[PackageOpsDone[pkg]].str), pkg); // we moved from one dpkg state to a new one, report that PackageOpsDone[pkg]++; PackagesDone++; - // build the status str - status << "pmstatus:" << pkg - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << s - << endl; - d->progress->StatusChanged(pkg, PackagesDone, PackagesTotal); - - if(OutStatusFd > 0) - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - if (Debug == true) - std::clog << "send: '" << status.str() << "'" << endl; + // and send to the progress + d->progress->StatusChanged(pkg, PackagesDone, PackagesTotal, + translation); } if (Debug == true) std::clog << "(parsed from dpkg) pkg: " << pkg @@ -713,7 +674,7 @@ void pkgDPkgPM::handleDisappearAction(string const &pkgname) // --------------------------------------------------------------------- /* */ -void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd) +void pkgDPkgPM::DoDpkgStatusFd(int statusfd) { char *p, *q; int len; @@ -728,7 +689,7 @@ void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd) while((q=(char*)memchr(p, '\n', d->dpkgbuf+d->dpkgbuf_pos-p)) != NULL) { *q = 0; - ProcessDpkgStatusLine(OutStatusFd, p); + ProcessDpkgStatusLine(p); p=q+1; // continue with next line } @@ -920,14 +881,15 @@ static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds, // --------------------------------------------------------------------- /* This globs the operations and calls dpkg * - * If it is called with "OutStatusFd" set to a valid file descriptor - * apt will report the install progress over this fd. It maps the - * dpkg states a package goes through to human readable (and i10n-able) + * If it is called with a progress object apt will report the install + * progress to this object. It maps the dpkg states a package goes + * through to human readable (and i10n-able) * names and calculates a percentage for each step. */ -bool pkgDPkgPM::Go(int OutStatusFd) +bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) { pkgPackageManager::SigINTStop = false; + d->progress = progress; // Generate the base argument list for dpkg std::vector Args; @@ -1304,16 +1266,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) // Fork dpkg pid_t Child; - _config->Set("APT::Keep-Fds::",fd[1]); - // send status information that we are about to fork dpkg - if(OutStatusFd > 0) { - ostringstream status; - status << "pmstatus:dpkg-exec:" - << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << _("Running dpkg") - << endl; - FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); - } + d->progress->Started(); Child = ExecFork(); // This is the child @@ -1360,15 +1313,11 @@ bool pkgDPkgPM::Go(int OutStatusFd) cerr << "Could not exec dpkg!" << endl; _exit(100); } - d->progress->Started(); // apply ionice if (_config->FindB("DPkg::UseIoNice", false) == true) ionice(Child); - // clear the Keep-Fd again - _config->Clear("APT::Keep-Fds",fd[1]); - // Wait for dpkg int Status = 0; @@ -1437,7 +1386,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) if(master >= 0 && FD_ISSET(0, &rfds)) DoStdin(master); if(FD_ISSET(_dpkgin, &rfds)) - DoDpkgStatusFd(_dpkgin, OutStatusFd); + DoDpkgStatusFd(_dpkgin); } close(_dpkgin); @@ -1487,7 +1436,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) CloseLog(); // dpkg is done at this point - d->progress->StatusChanged("", PackagesDone, PackagesTotal); + d->progress->StatusChanged("", PackagesDone, PackagesTotal, ""); if (pkgPackageManager::SigINTStop) _error->Warning(_("Operation was interrupted before it could finish")); diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index 53e352d4e..1f4bbafc7 100644 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@ -99,14 +99,15 @@ class pkgDPkgPM : public pkgPackageManager // input processing void DoStdin(int master); void DoTerminalPty(int master); - void DoDpkgStatusFd(int statusfd, int OutStatusFd); - void ProcessDpkgStatusLine(int OutStatusFd, char *line); + void DoDpkgStatusFd(int statusfd); + void ProcessDpkgStatusLine(char *line); // The Actuall installation implementation virtual bool Install(PkgIterator Pkg,std::string File); virtual bool Configure(PkgIterator Pkg); virtual bool Remove(PkgIterator Pkg,bool Purge = false); - virtual bool Go(int StatusFd=-1); + + virtual bool Go(APT::Progress::PackageManager *progress); virtual void Reset(); public: diff --git a/apt-pkg/iprogress.cc b/apt-pkg/iprogress.cc index 398059051..6c5d33d4a 100644 --- a/apt-pkg/iprogress.cc +++ b/apt-pkg/iprogress.cc @@ -1,16 +1,22 @@ +#include +#include #include #include + #include #include #include +#include + namespace APT { namespace Progress { bool PackageManager::StatusChanged(std::string PackageName, - unsigned int StepsDone, - unsigned int TotalSteps) + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction) { int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1); percentage = StepsDone/(float)TotalSteps * 100.0; @@ -22,6 +28,80 @@ bool PackageManager::StatusChanged(std::string PackageName, return true; } +PackageManagerProgressFd::PackageManagerProgressFd(int progress_fd) +{ + OutStatusFd = progress_fd; +} + +void PackageManagerProgressFd::Started() +{ + _config->Set("APT::Keep-Fds::", OutStatusFd); + + // send status information that we are about to fork dpkg + if(OutStatusFd > 0) { + std::ostringstream status; + status << "pmstatus:dpkg-exec:" + << (StepsDone/float(StepsTotal)*100.0) + << ":" << _("Running dpkg") + << std::endl; + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); + } +} + +void PackageManagerProgressFd::Finished() +{ + // clear the Keep-Fd again + _config->Clear("APT::Keep-Fds", OutStatusFd); +} + +void PackageManagerProgressFd::Error(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ErrorMessage) +{ + std::ostringstream status; + status << "pmerror:" << PackageName + << ":" << (StepsDone/float(TotalSteps)*100.0) + << ":" << ErrorMessage + << std::endl; + if(OutStatusFd > 0) + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); +} + +void PackageManagerProgressFd::ConffilePrompt(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ConfMessage) +{ + std::ostringstream status; + status << "pmconffile:" << PackageName + << ":" << (StepsDone/float(TotalSteps)*100.0) + << ":" << ConfMessage + << std::endl; + if(OutStatusFd > 0) + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); +} + + +bool PackageManagerProgressFd::StatusChanged(std::string PackageName, + unsigned int xStepsDone, + unsigned int xTotalSteps, + std::string pkg_action) +{ + StepsDone = xStepsDone; + StepsTotal = xTotalSteps; + + // build the status str + std::ostringstream status; + status << "pmstatus:" << PackageName + << ":" << (StepsDone/float(StepsTotal)*100.0) + << ":" << pkg_action + << std::endl; + if(OutStatusFd > 0) + FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size()); + return true; +} + void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows) { // scroll down a bit to avoid visual glitch when the screen @@ -72,9 +152,11 @@ void PackageManagerFancy::Finished() bool PackageManagerFancy::StatusChanged(std::string PackageName, unsigned int StepsDone, - unsigned int TotalSteps) + unsigned int TotalSteps, + std::string HumanReadableAction) { - if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps)) + if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, + HumanReadableAction)) return false; int row = nr_terminal_rows; @@ -105,9 +187,10 @@ bool PackageManagerFancy::StatusChanged(std::string PackageName, bool PackageManagerText::StatusChanged(std::string PackageName, unsigned int StepsDone, - unsigned int TotalSteps) + unsigned int TotalSteps, + std::string HumanReadableAction) { - if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps)) + if (!PackageManager::StatusChanged(PackageName, StepsDone, TotalSteps, HumanReadableAction)) return false; std::cout << progress_str << "\r\n"; diff --git a/apt-pkg/iprogress.h b/apt-pkg/iprogress.h index 5f1655ab9..6519e9445 100644 --- a/apt-pkg/iprogress.h +++ b/apt-pkg/iprogress.h @@ -1,13 +1,13 @@ #ifndef PKGLIB_IPROGRESS_H -#define PKGLIB_IPROGRSS_H +#define PKGLIB_IPROGRESS_H +#include +#include -#include namespace APT { namespace Progress { - class PackageManager { private: @@ -20,15 +20,54 @@ namespace Progress { int last_reported_progress; public: - PackageManager() : percentage(0.0), last_reported_progress(0) {}; + PackageManager() + : percentage(0.0), last_reported_progress(0) {}; virtual ~PackageManager() {}; virtual void Started() {}; virtual void Finished() {}; + + virtual pid_t fork() {return fork(); }; virtual bool StatusChanged(std::string PackageName, unsigned int StepsDone, - unsigned int TotalSteps); + unsigned int TotalSteps, + std::string HumanReadableAction) ; + virtual void Error(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ErrorMessage) {}; + virtual void ConffilePrompt(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ConfMessage) {}; + }; + + class PackageManagerProgressFd : public PackageManager + { + protected: + int OutStatusFd; + int StepsDone; + int StepsTotal; + + public: + PackageManagerProgressFd(int progress_fd); + virtual void Started(); + virtual void Finished(); + + virtual bool StatusChanged(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string HumanReadableAction); + virtual void Error(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ErrorMessage); + virtual void ConffilePrompt(std::string PackageName, + unsigned int StepsDone, + unsigned int TotalSteps, + std::string ConfMessage); + }; class PackageManagerFancy : public PackageManager @@ -43,7 +82,8 @@ namespace Progress { virtual void Finished(); virtual bool StatusChanged(std::string PackageName, unsigned int StepsDone, - unsigned int TotalSteps); + unsigned int TotalSteps, + std::string HumanReadableAction); }; class PackageManagerText : public PackageManager @@ -51,8 +91,8 @@ namespace Progress { public: virtual bool StatusChanged(std::string PackageName, unsigned int StepsDone, - unsigned int TotalSteps); - + unsigned int TotalSteps, + std::string HumanReadableAction); }; diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 8c0d2e855..32bc5284e 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -1032,28 +1032,32 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() // PM::DoInstallPostFork - Does install part that happens after the fork /*{{{*/ // --------------------------------------------------------------------- pkgPackageManager::OrderResult -pkgPackageManager::DoInstallPostFork(int statusFd) +pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress) { +// FIXME: port to new structure +#if 0 if(statusFd > 0) // FIXME: use SetCloseExec here once it taught about throwing // exceptions instead of doing _exit(100) on failure fcntl(statusFd,F_SETFD,FD_CLOEXEC); - bool goResult = Go(statusFd); +#endif + bool goResult = Go(progress); if(goResult == false) return Failed; return Res; }; - + /*}}}*/ // PM::DoInstall - Does the installation /*{{{*/ // --------------------------------------------------------------------- /* This uses the filenames in FileNames and the information in the DepCache to perform the installation of packages.*/ -pkgPackageManager::OrderResult pkgPackageManager::DoInstall(int statusFd) +pkgPackageManager::OrderResult +pkgPackageManager::DoInstall(APT::Progress::PackageManager *progress) { if(DoInstallPreFork() == Failed) return Failed; - return DoInstallPostFork(statusFd); + return DoInstallPostFork(progress); } /*}}}*/ diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h index 4956e816f..5c15ac0e4 100644 --- a/apt-pkg/packagemanager.h +++ b/apt-pkg/packagemanager.h @@ -24,6 +24,7 @@ #define PKGLIB_PACKAGEMANAGER_H #include +#include #include #include @@ -40,6 +41,7 @@ class pkgSourceList; class pkgOrderList; class pkgRecords; + class pkgPackageManager : protected pkgCache::Namespace { public: @@ -84,7 +86,7 @@ class pkgPackageManager : protected pkgCache::Namespace virtual bool Install(PkgIterator /*Pkg*/,std::string /*File*/) {return false;}; virtual bool Configure(PkgIterator /*Pkg*/) {return false;}; virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;}; - virtual bool Go(int statusFd=-1) {return true;}; + virtual bool Go(APT::Progress::PackageManager *progress) {return true;}; virtual void Reset() {}; // the result of the operation @@ -97,7 +99,17 @@ class pkgPackageManager : protected pkgCache::Namespace pkgRecords *Recs); // Do the installation - OrderResult DoInstall(int statusFd=-1); + OrderResult DoInstall(APT::Progress::PackageManager *progress); + + // compat + OrderResult DoInstall(int statusFd=-1) { + APT::Progress::PackageManager *progress = new + APT::Progress::PackageManagerProgressFd(statusFd); + OrderResult res = DoInstall(progress); + delete progress; + return res; + } + // stuff that needs to be done before the fork() of a library that // uses apt @@ -107,7 +119,7 @@ class pkgPackageManager : protected pkgCache::Namespace }; // stuff that needs to be done after the fork - OrderResult DoInstallPostFork(int statusFd=-1); + OrderResult DoInstallPostFork(APT::Progress::PackageManager *progress); bool FixMissing(); /** \brief returns all packages dpkg let disappear */ diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 643a6b370..d1066c869 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,11 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) { pkgSimulate PM(Cache); int status_fd = _config->FindI("APT::Status-Fd",-1); - pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd); + APT::Progress::PackageManager *progress = NULL; + if (status_fd > 0) + progress = new APT::Progress::PackageManagerProgressFd(status_fd); + pkgPackageManager::OrderResult Res = PM.DoInstall(progress); + delete progress; if (Res == pkgPackageManager::Failed) return false; if (Res != pkgPackageManager::Completed) @@ -332,8 +337,23 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) } _system->UnLock(); + + // FIXME: make this a factory + // select the right progress int status_fd = _config->FindI("APT::Status-Fd",-1); - pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd); + APT::Progress::PackageManager *progress = NULL; + if (status_fd > 0) + progress = new APT::Progress::PackageManagerProgressFd(status_fd); + else if(_config->FindB("Dpkg::Progress-Fancy", false) == true) + progress = new APT::Progress::PackageManagerFancy(); + else if (_config->FindB("Dpkg::Progress", + _config->FindB("DpkgPM::Progress", false)) == true) + progress = new APT::Progress::PackageManagerText(); + else + progress = new APT::Progress::PackageManager(); + pkgPackageManager::OrderResult Res = PM->DoInstall(progress); + delete progress; + if (Res == pkgPackageManager::Failed || _error->PendingError() == true) return false; if (Res == pkgPackageManager::Completed) -- 2.45.2