From: Michael Vogt Date: Thu, 17 Oct 2013 06:03:41 +0000 (+0200) Subject: Merge branch 'debian/sid' into feature/install-progress-refactor X-Git-Tag: 0.9.13.exp1~24 X-Git-Url: https://git.saurik.com/apt.git/commitdiff_plain/e8022b09e73ee89d3b748e1c8dba82abba5b37f3?ds=inline;hp=-c Merge branch 'debian/sid' into feature/install-progress-refactor Conflicts: apt-pkg/deb/dpkgpm.cc --- e8022b09e73ee89d3b748e1c8dba82abba5b37f3 diff --combined apt-pkg/deb/dpkgpm.cc index fbb5e4c96,f870fab93..1b234c0ed --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@@ -19,7 -19,6 +19,7 @@@ #include #include #include +#include #include #include @@@ -55,14 -54,16 +55,14 @@@ class pkgDPkgPMPrivat public: pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0), term_out(NULL), history_out(NULL), - last_reported_progress(0.0), nr_terminal_rows(0), - fancy_progress_output(false) + last_reported_progress(0.0), progress(NULL) { dpkgbuf[0] = '\0'; - if(_config->FindB("Dpkg::Progress-Fancy", false) == true) - { - fancy_progress_output = true; - _config->Set("DpkgPM::Progress", true); - } } + ~pkgDPkgPMPrivate() + { + } + bool stdin_is_dev_null; // the buffer we use for the dpkg status-fd reading char dpkgbuf[1024]; @@@ -72,7 -73,8 +72,7 @@@ string dpkg_error; float last_reported_progress; - int nr_terminal_rows; - bool fancy_progress_output; + APT::Progress::PackageManager *progress; }; namespace @@@ -511,9 -513,11 +511,9 @@@ void pkgDPkgPM::DoTerminalPty(int maste // --------------------------------------------------------------------- /* */ -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; @@@ -542,8 -546,8 +542,8 @@@ // A dpkg error message may contain additional ":" (like // "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..." // so we need to ensure to not split too much - std::vector list = StringSplit(line, ": ", 3); - if(list.size() != 3) + std::vector list = StringSplit(line, ": ", 4); + if(list.size() < 3) { if (Debug == true) std::clog << "ignoring line: not enough ':'" << std::endl; @@@ -553,16 -557,32 +553,37 @@@ std::string pkgname = list[1]; if (pkgname.find(":") == std::string::npos) { - string const nativeArch = _config->Find("APT::Architecture"); - pkgname = pkgname + ":" + nativeArch; + // find the package in the group that is in a touched by dpkg + // if there are multiple dpkg will send us a full pkgname:arch + pkgCache::GrpIterator Grp = Cache.FindGrp(pkgname); + if (Grp.end() == false) + { + pkgCache::PkgIterator P = Grp.PackageList(); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if(Cache[P].Mode != pkgDepCache::ModeKeep) + { + pkgname = P.FullName(); + break; + } + } + } } const char* const pkg = pkgname.c_str(); const char* action = list[2].c_str(); + + std::string short_pkgname = StringSplit(pkgname, ":")[0]; ++ std::string i18n_pkgname = short_pkgname; ++ if (pkgname.find(":") != string::npos) ++ { ++ strprintf(i18n_pkgname, "%s (%s)", short_pkgname.c_str(), ++ StringSplit(pkgname, ":")[1].c_str()); ++ } // 'processing' from dpkg looks like // '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 = @@@ -575,11 -595,17 +596,11 @@@ 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; @@@ -587,15 -613,28 +608,15 @@@ 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; } @@@ -608,18 -647,28 +629,20 @@@ { // 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, short_pkgname.c_str()); + std::string translation; - strprintf(translation, _(states[PackageOpsDone[pkg]].str), pkg); ++ strprintf(translation, _(states[PackageOpsDone[pkg]].str), ++ i18n_pkgname.c_str()); // we moved from one dpkg state to a new one, report that PackageOpsDone[pkg]++; PackagesDone++; - // build the status str - status << "pmstatus:" << short_pkgname - << ":" << (PackagesDone/float(PackagesTotal)*100.0) - << ":" << s - << endl; - if(_config->FindB("DPkgPM::Progress", false) == true) - SendTerminalProgress(PackagesDone/float(PackagesTotal)*100.0); - - 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, ++ d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, + translation); } if (Debug == true) - std::clog << "(parsed from dpkg) pkg: " << pkg - std::clog << "(parsed from dpkg) pkg: " << short_pkgname ++ std::clog << "(parsed from dpkg) pkg: " << pkgname << " action: " << action << endl; } /*}}}*/ @@@ -674,7 -723,7 +697,7 @@@ void pkgDPkgPM::handleDisappearAction(s // --------------------------------------------------------------------- /* */ -void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd) +void pkgDPkgPM::DoDpkgStatusFd(int statusfd) { char *p, *q; int len; @@@ -689,7 -738,7 +712,7 @@@ 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 } @@@ -855,6 -904,52 +878,6 @@@ bool pkgDPkgPM::CloseLog( return true; } /*}}}*/ -// DPkgPM::SendTerminalProgress /*{{{*/ -// --------------------------------------------------------------------- -/* Send progress info to the terminal - */ -void pkgDPkgPM::SendTerminalProgress(float percentage) -{ - int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1); - - if(percentage < (d->last_reported_progress + reporting_steps)) - return; - - std::string progress_str; - strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage); - if (d->fancy_progress_output) - { - int row = d->nr_terminal_rows; - - static string save_cursor = "\033[s"; - static string restore_cursor = "\033[u"; - - static string set_bg_color = "\033[42m"; // green - static string set_fg_color = "\033[30m"; // black - - static string restore_bg = "\033[49m"; - static string restore_fg = "\033[39m"; - - std::cout << save_cursor - // move cursor position to last row - << "\033[" << row << ";0f" - << set_bg_color - << set_fg_color - << progress_str - << restore_cursor - << restore_bg - << restore_fg; - } - else - { - std::cout << progress_str << "\r\n"; - } - std::flush(std::cout); - - d->last_reported_progress = percentage; -} - /*}}}*/ -/*{{{*/ // This implements a racy version of pselect for those architectures // that don't have a working implementation. // FIXME: Probably can be removed on Lenny+1 @@@ -876,20 -971,54 +899,20 @@@ static int racy_pselect(int nfds, fd_se } /*}}}*/ -void pkgDPkgPM::SetupTerminalScrollArea(int nr_rows) -{ - if(!d->fancy_progress_output) - return; - - // scroll down a bit to avoid visual glitch when the screen - // area shrinks by one row - std::cout << "\n"; - - // save cursor - std::cout << "\033[s"; - - // set scroll region (this will place the cursor in the top left) - std::cout << "\033[1;" << nr_rows - 1 << "r"; - - // restore cursor but ensure its inside the scrolling area - std::cout << "\033[u"; - static const char *move_cursor_up = "\033[1A"; - std::cout << move_cursor_up; - std::flush(std::cout); -} - -void pkgDPkgPM::CleanupTerminal() -{ - // reset scroll area - SetupTerminalScrollArea(d->nr_terminal_rows + 1); - if(d->fancy_progress_output) - { - // override the progress line (sledgehammer) - static const char* clear_screen_below_cursor = "\033[J"; - std::cout << clear_screen_below_cursor; - std::flush(std::cout); - } -} - // DPkgPM::Go - Run the sequence /*{{{*/ // --------------------------------------------------------------------- /* 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; @@@ -1234,7 -1363,8 +1257,7 @@@ _error->PushToStack(); if (tcgetattr(STDOUT_FILENO, &tt) == 0) { - ioctl(1, TIOCGWINSZ, (char *)&win); - d->nr_terminal_rows = win.ws_row; + ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win); if (openpty(&master, &slave, NULL, &tt, &win) < 0) { _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?")); @@@ -1264,12 -1394,20 +1287,14 @@@ _error->DumpErrors(std::cerr); _error->RevertToStack(); - // Fork dpkg - pid_t Child; + // this is the dpkg status-fd, we need to keep it _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()); - } - Child = ExecFork(); + // Tell the progress that its starting and fork dpkg ++ // FIXME: this is called once per dpkg run which is *too often* + d->progress->Start(); ++ + pid_t Child = ExecFork(); // This is the child if (Child == 0) { @@@ -1306,6 -1444,9 +1331,6 @@@ if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0) _exit(100); } - // setup terminal - SetupTerminalScrollArea(d->nr_terminal_rows); - SendTerminalProgress(PackagesDone/float(PackagesTotal)*100.0); /* No Job Control Stop Env is a magic dpkg var that prevents it from using sigstop */ @@@ -1368,14 -1509,13 +1393,15 @@@ FD_SET(_dpkgin, &rfds); if(master >= 0) FD_SET(master, &rfds); - tv.tv_sec = 1; - tv.tv_nsec = 0; + tv.tv_sec = 0; + tv.tv_nsec = d->progress->GetPulseInterval(); select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL, &tv, &original_sigmask); if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS)) select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL, &tv, &original_sigmask); + d->progress->Pulse(); ++ if (select_ret == 0) continue; else if (select_ret < 0 && errno == EINTR) @@@ -1391,7 -1531,7 +1417,7 @@@ if(master >= 0 && FD_ISSET(0, &rfds)) DoStdin(master); if(FD_ISSET(_dpkgin, &rfds)) - DoDpkgStatusFd(_dpkgin, OutStatusFd); + DoDpkgStatusFd(_dpkgin); } close(_dpkgin); @@@ -1401,9 -1541,6 +1427,6 @@@ signal(SIGHUP,old_SIGHUP); - // tell the progress - d->progress->Stop(); - if(master >= 0) { tcsetattr(0, TCSAFLUSH, &tt); @@@ -1434,6 -1571,7 +1457,7 @@@ if(stopOnError) { CloseLog(); - CleanupTerminal(); ++ d->progress->Stop(); return false; } } @@@ -1441,7 -1579,10 +1465,9 @@@ CloseLog(); // dpkg is done at this point - if(_config->FindB("DPkgPM::Progress", false) == true) - SendTerminalProgress(100); + d->progress->StatusChanged("", PackagesDone, PackagesTotal, ""); ++ d->progress->Stop(); + - CleanupTerminal(); if (pkgPackageManager::SigINTStop) _error->Warning(_("Operation was interrupted before it could finish")); diff --combined apt-pkg/deb/dpkgpm.h index 1f4bbafc7,1a58e1af5..302507105 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@@ -23,7 -23,6 +23,7 @@@ using std::map class pkgDPkgPMPrivate; + class pkgDPkgPM : public pkgPackageManager { private: @@@ -88,6 -87,7 +88,7 @@@ // Terminal progress void SetupTerminalScrollArea(int nr_scrolled_rows); void SendTerminalProgress(float percentage); + void CleanupTerminal(); // apport integration void WriteApportReport(const char *pkgpath, const char *errormsg); @@@ -99,15 -99,14 +100,15 @@@ // 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: