void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, 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;
-
/* dpkg sends strings like this:
'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
- 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
- Newer versions of dpkg sent also:
- 'processing: install: pkg'
- 'processing: configure: pkg'
- 'processing: remove: pkg'
- 'processing: purge: pkg'
- 'processing: disappear: pkg'
- 'processing: trigproc: trigger'
-
+ 'processing: {install,configure,remove,purge,disappear,trigproc}: pkg'
+ 'processing: {install,configure,remove,purge,disappear,trigproc}: trigger'
*/
+
// we need to split on ": " (note the appended space) as the ':' is
// part of the pkgname:arch information that dpkg sends
//
std::clog << "ignoring line: not enough ':'" << std::endl;
return;
}
+
+ // build the (prefix, pkgname, action) tuple, position of this
+ // is different for "processing" or "status" messages
+ std::string prefix = APT::String::Strip(list[0]);
+ std::string pkgname;
+ std::string action_str;
+ ostringstream status;
+
+ // "processing" has the form "processing: action: pkg or trigger"
+ // with action = ["install", "configure", "remove", "purge", "disappear",
+ // "trigproc"]
+ if (prefix == "processing")
+ {
+ pkgname = APT::String::Strip(list[2]);
+ action_str = APT::String::Strip(list[1]);
+
+ // this is what we support in the processing stage
+ if(action_str != "install" && action_str != "configure" &&
+ action_str != "remove" && action_str != "purge" &&
+ action_str != "purge")
+ {
+ if (Debug == true)
+ std::clog << "ignoring processing action: '" << action_str
+ << "'" << std::endl;
+ return;
+ }
+ }
+ // "status" has the form: "status: pkg: state"
+ // with state in ["half-installed", "unpacked", "half-configured",
+ // "installed", "config-files", "not-installed"]
+ else if (prefix == "status")
+ {
+ pkgname = APT::String::Strip(list[1]);
+ action_str = APT::String::Strip(list[2]);
+ } else {
+ if (Debug == true)
+ std::clog << "unknown prefix '" << prefix << "'" << std::endl;
+ return;
+ }
+
+
+ /* handle the special cases first:
+
+ 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
+ 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
+ */
+ if (prefix == "status")
+ {
+ if(action_str == "error")
+ {
+ 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;
+ pkgFailures++;
+ WriteApportReport(list[1].c_str(), list[3].c_str());
+ return;
+ }
+ else if(action_str == "conffile")
+ {
+ 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;
+ return;
+ }
+ }
+
+ // at this point we know that we should have a valid pkgname, so build all
+ // the info from it
+
// 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;
+ // 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();
+ const char* action = action_str.c_str();
+ std::string short_pkgname = StringSplit(pkgname, ":")[0];
+ std::string arch = "";
+ if (pkgname.find(":") != string::npos)
+ arch = StringSplit(pkgname, ":")[1];
+ std::string i18n_pkgname = pkgname;
+ if (arch.size() != 0)
+ strprintf(i18n_pkgname, "%s (%s)", short_pkgname.c_str(), arch.c_str());
// 'processing' from dpkg looks like
// 'processing: action: pkg'
- if(strncmp(list[0].c_str(), "processing", strlen("processing")) == 0)
+ if(prefix == "processing")
{
char s[200];
const char* const pkg_or_trigger = list[2].c_str();
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;
- 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;
- return;
- }
+ }
- vector<struct DpkgState> const &states = PackageOps[pkg];
- const char *next_action = NULL;
- if(PackageOpsDone[pkg] < states.size())
- next_action = states[PackageOpsDone[pkg]].state;
- // check if the package moved to the next dpkg state
- if(next_action && (strcmp(action, next_action) == 0))
+ if (prefix == "status")
{
- // 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);
-
- // 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;
- 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;
+ vector<struct DpkgState> const &states = PackageOps[pkg];
+ const char *next_action = NULL;
+ if(PackageOpsDone[pkg] < states.size())
+ next_action = states[PackageOpsDone[pkg]].state;
+ // check if the package moved to the next dpkg state
+ if(next_action && (strcmp(action, next_action) == 0))
+ {
+ // 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());
+
+ // 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;
+ }
+ if (Debug == true)
+ std::clog << "(parsed from dpkg) pkg: " << short_pkgname
+ << " action: " << action << endl;
}
- if (Debug == true)
- std::clog << "(parsed from dpkg) pkg: " << pkg
- << " action: " << action << endl;
}
/*}}}*/
// DPkgPM::handleDisappearAction /*{{{*/
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 (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 */
signal(SIGHUP,old_SIGHUP);
- // 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;
- }
-
if(master >= 0)
{
tcsetattr(0, TCSAFLUSH, &tt);
if(stopOnError)
{
CloseLog();
+ CleanupTerminal();
return false;
}
}
if(_config->FindB("DPkgPM::Progress", false) == true)
SendTerminalProgress(100);
+ CleanupTerminal();
+
if (pkgPackageManager::SigINTStop)
_error->Warning(_("Operation was interrupted before it could finish"));