]> git.saurik.com Git - apt.git/commitdiff
Merge branch 'debian/sid' into feature/install-progress-refactor
authorMichael Vogt <mvo@debian.org>
Thu, 17 Oct 2013 06:03:41 +0000 (08:03 +0200)
committerMichael Vogt <mvo@debian.org>
Thu, 17 Oct 2013 06:03:41 +0000 (08:03 +0200)
Conflicts:
apt-pkg/deb/dpkgpm.cc

1  2 
apt-pkg/deb/dpkgpm.cc
apt-pkg/deb/dpkgpm.h

diff --combined apt-pkg/deb/dpkgpm.cc
index fbb5e4c96d4e5cbdfbcb4297aa3903ef21aa073b,f870fab936f7139c7b04cb726b0090e599aeb3aa..1b234c0ed61da4da88f5ec56f3b428213466f89e
@@@ -19,7 -19,6 +19,7 @@@
  #include <apt-pkg/fileutl.h>
  #include <apt-pkg/cachefile.h>
  #include <apt-pkg/packagemanager.h>
 +#include <apt-pkg/iprogress.h>
  
  #include <unistd.h>
  #include <stdlib.h>
@@@ -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;
     // 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<std::string> list = StringSplit(line, ": ", 3);
-    if(list.size() != 3)
+    std::vector<std::string> list = StringSplit(line, ": ", 4);
+    if(list.size() < 3)
     {
        if (Debug == true)
         std::clog << "ignoring line: not enough ':'" << std::endl;
     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 char *, const char *> * const iter =
            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;
  
     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;
     }
  
     {
        // 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;
     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<const char *> Args;
        _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?"));
         _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)
        {
            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 */
         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)
         if(master >= 0 && FD_ISSET(0, &rfds))
            DoStdin(master);
         if(FD_ISSET(_dpkgin, &rfds))
 -          DoDpkgStatusFd(_dpkgin, OutStatusFd);
 +          DoDpkgStatusFd(_dpkgin);
        }
        close(_dpkgin);
  
        
        signal(SIGHUP,old_SIGHUP);
  
-       // tell the progress
-       d->progress->Stop();
        if(master >= 0) 
        {
         tcsetattr(0, TCSAFLUSH, &tt);
         if(stopOnError) 
         {
            CloseLog();
 -            CleanupTerminal();
++            d->progress->Stop();
            return false;
         }
        }      
     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 1f4bbafc786cb768e1b50c95ac689fd0de973140,1a58e1af5959fb07e515cb45aa020d227ba9e00f..302507105982e8d344244e3668f610245b918b94
@@@ -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);
     // 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: