summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <mvo@debian.org>2013-10-05 10:49:26 +0200
committerMichael Vogt <mvo@debian.org>2013-10-05 10:49:26 +0200
commitb821e492d6dc4e1e8fd1f83590e12e3fbccad717 (patch)
treeac6d28f28fe13078aa578e1fb0fdd956a7e6ae84
parent318289bb17b827611fea6570f71df525b60a0e97 (diff)
parent75cd2506ce7ea411f7a0e888310d622ad330828c (diff)
Merge remote-tracking branch 'mvo/bugfix/dpkg-progress-multiarch' into debian/sid
-rw-r--r--apt-pkg/contrib/strutl.cc31
-rw-r--r--apt-pkg/contrib/strutl.h25
-rw-r--r--apt-pkg/deb/dpkgpm.cc68
-rw-r--r--test/libapt/strutil_test.cc27
4 files changed, 123 insertions, 28 deletions
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index 0955b69f7..77e48962c 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -1118,6 +1118,37 @@ vector<string> VectorizeString(string const &haystack, char const &split)
return exploded;
}
/*}}}*/
+// StringSplit - split a string into a string vector by token /*{{{*/
+// ---------------------------------------------------------------------
+/* See header for details.
+ */
+vector<string> StringSplit(std::string const &s, std::string const &sep,
+ unsigned int maxsplit)
+{
+ vector<string> split;
+ size_t start, pos;
+
+ // no seperator given, this is bogus
+ if(sep.size() == 0)
+ return split;
+
+ start = pos = 0;
+ while (pos != string::npos)
+ {
+ pos = s.find(sep, start);
+ split.push_back(s.substr(start, pos-start));
+
+ // if maxsplit is reached, the remaining string is the last item
+ if(split.size() >= maxsplit)
+ {
+ split[split.size()-1] = s.substr(start);
+ break;
+ }
+ start = pos+sep.size();
+ }
+ return split;
+}
+ /*}}}*/
// RegexChoice - Simple regex list/list matcher /*{{{*/
// ---------------------------------------------------------------------
/* */
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
index 530896141..b42e06491 100644
--- a/apt-pkg/contrib/strutl.h
+++ b/apt-pkg/contrib/strutl.h
@@ -17,7 +17,7 @@
#define STRUTL_H
-
+#include <limits>
#include <stdlib.h>
#include <string>
#include <cstring>
@@ -62,9 +62,32 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0)
bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base = 0);
bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len);
bool Hex2Num(const std::string &Str,unsigned char *Num,unsigned int Length);
+
+// input changing string split
bool TokSplitString(char Tok,char *Input,char **List,
unsigned long ListMax);
+
+// split a given string by a char
std::vector<std::string> VectorizeString(std::string const &haystack, char const &split) __attrib_const;
+
+/* \brief Return a vector of strings from string "input" where "sep"
+ * is used as the delimiter string.
+ *
+ * \param input The input string.
+ *
+ * \param sep The seperator to use.
+ *
+ * \param maxsplit (optional) The maximum amount of splitting that
+ * should be done .
+ *
+ * The optional "maxsplit" argument can be used to limit the splitting,
+ * if used the string is only split on maxsplit places and the last
+ * item in the vector contains the remainder string.
+ */
+std::vector<std::string> StringSplit(std::string const &input,
+ std::string const &sep,
+ unsigned int maxsplit=std::numeric_limits<unsigned int>::max()) __attrib_const;
+
void ioprintf(std::ostream &out,const char *format,...) __like_printf(2);
void strprintf(std::string &out,const char *format,...) __like_printf(2);
char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3);
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc
index 3c1013761..a5097a04f 100644
--- a/apt-pkg/deb/dpkgpm.cc
+++ b/apt-pkg/deb/dpkgpm.cc
@@ -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)
@@ -883,10 +887,16 @@ bool pkgDPkgPM::CloseLog()
*/
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: [" << percentage << "%]"
+ << "Progress: [" << std::setw(3) << int(percentage) << "%]"
<< "\r\n";
+ d->last_reported_progress = percentage;
}
/*}}}*/
/*{{{*/
@@ -1035,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)
{
@@ -1444,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)
{
@@ -1474,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"));
diff --git a/test/libapt/strutil_test.cc b/test/libapt/strutil_test.cc
index bfe0d7222..110a20d27 100644
--- a/test/libapt/strutil_test.cc
+++ b/test/libapt/strutil_test.cc
@@ -42,5 +42,32 @@ int main(int argc,char *argv[])
output = DeEscapeString(input);
equals(output, expected);
+ // Split
+ input = "status: libnet1:amd64: unpacked";
+ vector<std::string> result = StringSplit(input, ": ");
+ equals(result[0], "status");
+ equals(result[1], "libnet1:amd64");
+ equals(result[2], "unpacked");
+ equals(result.size(), 3);
+
+ input = "status: libnet1:amd64: unpacked";
+ result = StringSplit(input, "xxx");
+ equals(result[0], input);
+ equals(result.size(), 1);
+
+ input = "status: libnet1:amd64: unpacked";
+ result = StringSplit(input, "");
+ equals(result.size(), 0);
+
+ input = "x:y:z";
+ result = StringSplit(input, ":", 2);
+ equals(result.size(), 2);
+ equals(result[0], "x");
+ equals(result[1], "y:z");
+
+ input = "abc";
+ result = StringSplit(input, "");
+ equals(result.size(), 0);
+
return 0;
}