]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/dpkgpm.cc
Merge remote-tracking branch 'origin/bugfix/dpkg-progress-multiarch' into bugfix...
[apt.git] / apt-pkg / deb / dpkgpm.cc
index 4b5467eff14a6a138708ebf61cc00e67bb108666..a5097a04fcef8b50799b8125db9d1b4f7f2c8c84 100644 (file)
@@ -37,6 +37,7 @@
 #include <map>
 #include <pwd.h>
 #include <grp.h>
+#include <iomanip>
 
 #include <termios.h>
 #include <unistd.h>
@@ -52,7 +53,8 @@ class pkgDPkgPMPrivate
 {
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
-                       term_out(NULL), history_out(NULL)
+                       term_out(NULL), history_out(NULL), 
+                        last_reported_progress(0.0)
    {
       dpkgbuf[0] = '\0';
    }
@@ -63,6 +65,8 @@ public:
    FILE *term_out;
    FILE *history_out;
    string dpkg_error;
+
+   float last_reported_progress;
 };
 
 namespace
@@ -512,7 +516,8 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 
 
    /* dpkg sends strings like this:
-      'status:   <pkg>:  <pkg  qstate>'
+      'status:   <pkg>: <pkg  qstate>'
+      'status:   <pkg>:<arch>: <pkg  qstate>'
       errors look like this:
       'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data 
       and conffile-prompt like this
@@ -527,29 +532,36 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
       'processing: trigproc: trigger'
            
    */
-   char* list[6];
-   //        dpkg sends multiline error messages sometimes (see
-   //        #374195 for a example. we should support this by
-   //        either patching dpkg to not send multiline over the
-   //        statusfd or by rewriting the code here to deal with
-   //        it. for now we just ignore it and not crash
-   TokSplitString(':', line, list, sizeof(list)/sizeof(list[0]));
-   if( list[0] == NULL || list[1] == NULL || list[2] == NULL) 
+   // we need to split on ": " (note the appended space) as the ':' is
+   // part of the pkgname:arch information that dpkg sends
+   // 
+   // 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)
    {
       if (Debug == true)
         std::clog << "ignoring line: not enough ':'" << std::endl;
       return;
    }
-   const char* const pkg = list[1];
-   const char* action = _strstrip(list[2]);
+   // dpkg does not send always send "pkgname:arch" so we add it here if needed
+   std::string pkgname = list[1];
+   if (pkgname.find(":") == std::string::npos)
+   {
+      string const nativeArch = _config->Find("APT::Architecture");
+      pkgname = pkgname + ":" + nativeArch;
+   }
+   const char* const pkg = pkgname.c_str();
+   const char* action = list[2].c_str();
 
    // 'processing' from dpkg looks like
    // 'processing: action: pkg'
-   if(strncmp(list[0], "processing", strlen("processing")) == 0)
+   if(strncmp(list[0].c_str(), "processing", strlen("processing")) == 0)
    {
       char s[200];
-      const char* const pkg_or_trigger = _strstrip(list[2]);
-      action = _strstrip( list[1]);
+      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::find_if(PackageProcessingOpsBegin,
                     PackageProcessingOpsEnd,
@@ -578,14 +590,6 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 
    if(strncmp(action,"error",strlen("error")) == 0)
    {
-      // urgs, sometime has ":" in its error string so that we
-      // end up with the error message split between list[3]
-      // and list[4], e.g. the message: 
-      // "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..."
-      // concat them again
-      if( list[4] != NULL )
-        list[3][strlen(list[3])] = ':';
-
       status << "pmerror:" << list[1]
             << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
             << ":" << list[3]
@@ -595,7 +599,7 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
       if (Debug == true)
         std::clog << "send: '" << status.str() << "'" << endl;
       pkgFailures++;
-      WriteApportReport(list[1], list[3]);
+      WriteApportReport(list[1].c_str(), list[3].c_str());
       return;
    }
    else if(strncmp(action,"conffile",strlen("conffile")) == 0)
@@ -632,6 +636,9 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
             << ":"  << (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)
@@ -874,6 +881,24 @@ 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;
+
+   // FIXME: use colors too
+   std::cout << "\r\n"
+             << "Progress: [" << std::setw(3) << int(percentage) << "%]"
+             << "\r\n";
+   d->last_reported_progress = percentage;
+}
+                                                                       /*}}}*/
 /*{{{*/
 // This implements a racy version of pselect for those architectures
 // that don't have a working implementation.
@@ -1020,7 +1045,7 @@ bool pkgDPkgPM::Go(int OutStatusFd)
       if((*I).Pkg.end() == true)
         continue;
 
-      string const name = (*I).Pkg.Name();
+      string const name = (*I).Pkg.FullName();
       PackageOpsDone[name] = 0;
       for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i)
       {
@@ -1294,7 +1319,7 @@ bool pkgDPkgPM::Go(int OutStatusFd)
         FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size());
       }
       Child = ExecFork();
-            
+      
       // This is the child
       if (Child == 0)
       {
@@ -1429,7 +1454,7 @@ bool pkgDPkgPM::Go(int OutStatusFd)
         tcsetattr(0, TCSAFLUSH, &tt);
         close(master);
       }
-       
+
       // Check for an error code.
       if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
       {
@@ -1459,6 +1484,10 @@ bool pkgDPkgPM::Go(int OutStatusFd)
       }      
    }
    CloseLog();
+
+   // dpkg is done at this point
+   if(_config->FindB("DPkgPM::Progress", false) == true)
+      SendTerminalProgress(100);
    
    if (pkgPackageManager::SigINTStop)
        _error->Warning(_("Operation was interrupted before it could finish"));