ref: refs/heads/master
commit 7e56c824176046fb2e00212cf6c75a45cf26bec0
Author: Ján Kupec
Date: Wed Mar 25 17:09:58 2009 +0100
Install summary refactored into utils/Summary.*
- prepared for additional improvements (bnc #389128)
- added old edition/arch to xmlout (bnc #331060)
---
src/CMakeLists.txt | 2 +
src/solve-commit.cc | 572 ++---------------------------------------
src/utils/Summary.cc | 697 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/utils/Summary.h | 117 +++++++++
4 files changed, 840 insertions(+), 548 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dae4a9f..82c8d9f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -68,6 +68,7 @@ SET( zypper_utils_HEADERS
utils/pager.h
utils/prompt.h
utils/richtext.h
+ utils/Summary.h
utils/text.h
)
@@ -80,6 +81,7 @@ SET( zypper_utils_SRCS
utils/pager.cc
utils/prompt.cc
utils/richtext.cc
+ utils/Summary.cc
utils/text.cc
${zypper_utils_HEADERS}
)
diff --git a/src/solve-commit.cc b/src/solve-commit.cc
index aa25bb1..d49d2a9 100755
--- a/src/solve-commit.cc
+++ b/src/solve-commit.cc
@@ -23,6 +23,7 @@
#include "utils/misc.h"
#include "utils/getopt.h"
#include "utils/prompt.h"
+#include "utils/Summary.h"
#include "solve-commit.h"
@@ -191,350 +192,6 @@ static bool show_problems(Zypper & zypper)
return retry;
}
-struct ResNameCompare
-{
- bool operator()(ResObject::constPtr r1, ResObject::constPtr r2) const
- {
- return strcoll(r1->name().c_str(), r2->name().c_str()) < 0;
- }
-};
-
-typedef map > KindToResObjectSet;
-
-static void show_summary_resolvable_list(const string & label,
- KindToResObjectSet::const_iterator it,
- Out & out)
-{
- ostringstream s;
- s << endl << label << endl;
-
- // get terminal width from COLUMNS env. var.
- unsigned cols = 0, cols_written = 0;
- const char *cols_s = getenv("COLUMNS");
- string cols_str("80");
- if (cols_s != NULL)
- cols_str = cols_s;
- str::strtonum (cols_str, cols);
- if (cols == 0)
- cols = 77;
-
-#define INDENT " "
-//! \todo make function to wrap & indent the text
- for (setResObject::constPtr::const_iterator resit = it->second.begin();
- resit != it->second.end(); ++resit)
- {
- ResObject::constPtr res(*resit);
-
- if (out.verbosity() == Out::NORMAL)
- {
- // watch the terminal widht
- if (cols_written == 0)
- s << INDENT;
- else if (cols_written + res->name().size() + 1 > cols)
- {
- s << endl;
- cols_written = 0;
- }
-
- cols_written += res->name().size();
- }
- else
- s << INDENT;
-
- // resolvable name
- s << res->name() << (out.verbosity() > Out::NORMAL ? "" : " ");
- // plus edition and architecture for verbose output
- if (out.verbosity() > Out::NORMAL)
- {
- s << "-" << res->edition() << "." << res->arch();
-
- const string & reponame = res->repoInfo().name();
- if (!res->vendor().empty() || !reponame.empty())
- {
- s << " (";
- // plus repo providing this package
- if (!reponame.empty())
- s << reponame;
- // plus package vendor
- if (!res->vendor().empty())
- s << (reponame.empty() ? "" : ", ") << res->vendor();
- s << ")";
- }
- // new line after each package in the verbose mode
- s << endl;
- }
- }
-
- if (out.verbosity() == Out::NORMAL)
- s << endl;
-
- out.info(s.str(), Out::QUIET); //! \todo special output needed for this
-}
-
-typedef enum
-{
- TO_UPGRADE,
- TO_DOWNGRADE,
- TO_INSTALL,
- TO_REINSTALL,
- TO_REMOVE,
- TO_CHANGE_ARCH,
- TO_CHANGE_VENDOR,
- UNSUPPORTED
-} SummaryType;
-
-static void xml_print_to_transact_tag(SummaryType stype, bool end = false)
-{
- switch (stype)
- {
- case TO_UPGRADE:
- cout << "<" << (end ? "/" : "") << "to-upgrade>" << endl;
- break;
- case TO_DOWNGRADE:
- cout << "<" << (end ? "/" : "") << "to-downgrade>" << endl;
- break;
- case TO_INSTALL:
- cout << "<" << (end ? "/" : "") << "to-install>" << endl;
- break;
- case TO_REINSTALL:
- cout << "<" << (end ? "/" : "") << "to-reinstall>" << endl;
- break;
- case TO_REMOVE:
- cout << "<" << (end ? "/" : "") << "to-remove>" << endl;
- break;
- case TO_CHANGE_ARCH:
- cout << "<" << (end ? "/" : "") << "to-change-arch>" << endl;
- break;
- case TO_CHANGE_VENDOR:
- cout << "<" << (end ? "/" : "") << "to-change-vendor>" << endl;
- break;
- case UNSUPPORTED:
- cout << "<" << (end ? "/" : "") << "unsupported>" << endl;
- break;
- }
-}
-
-static void show_summary_of_type(Zypper & zypper,
- SummaryType stype,
- const KindToResObjectSet & summset)
-{
- // xml install summary
- if (zypper.out().type() == Out::TYPE_XML)
- {
- bool empty = true;
- for (KindToResObjectSet::const_iterator it = summset.begin();
- it != summset.end(); ++it)
- if (!it->second.empty()) { empty = false; break; }
- if (empty)
- return;
-
- xml_print_to_transact_tag(stype);
-
- for (KindToResObjectSet::const_iterator it = summset.begin();
- it != summset.end(); ++it)
- for (setResObject::constPtr::const_iterator resit = it->second.begin();
- resit != it->second.end(); ++resit)
- {
- ResObject::constPtr res(*resit);
-
- cout << "first << "\"";
- cout << " name=\"" << res->name() << "\"";
- cout << " edition=\"" << res->edition() << "\"";
- //! \todo cout << " edition-old=\"" << << "\"";
- cout << " arch=\"" << res->arch() << "\"";
- if (!res->summary().empty())
- cout << " summary=\"" << xml_encode(res->summary()) << "\"";
- if (!res->description().empty())
- cout << ">" << endl << xml_encode(res->description()) << "</solvable>" << endl;
- else
- cout << "/>" << endl;
- }
-
- xml_print_to_transact_tag(stype, true);
-
- return;
- }
-
- // normal install summary
- for (KindToResObjectSet::const_iterator it = summset.begin();
- it != summset.end(); ++it)
- {
- string title;
- switch (stype)
- {
- case TO_UPGRADE:
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is going to be upgraded:",
- "The following packages are going to be upgraded:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following patch is going to be upgraded:",
- "The following patches are going to be upgraded:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following pattern is going to be upgraded:",
- "The following patterns are going to be upgraded:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following product is going to be upgraded:",
- "The following products are going to be upgraded:",
- it->second.size());
- break;
- case TO_DOWNGRADE:
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is going to be downgraded:",
- "The following packages are going to be downgraded:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following patch is going to be downgraded:",
- "The following patches are going to be downgraded:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following pattern is going to be downgraded:",
- "The following patterns are going to be downgraded:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following product is going to be downgraded:",
- "The following products are going to be downgraded:",
- it->second.size());
- break;
- case TO_INSTALL:
- if (it->first == ResKind::package)
- title = _PL(
- "The following NEW package is going to be installed:",
- "The following NEW packages are going to be installed:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following NEW patch is going to be installed:",
- "The following NEW patches are going to be installed:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following NEW pattern is going to be installed:",
- "The following NEW patterns are going to be installed:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following NEW product is going to be installed:",
- "The following NEW products are going to be installed:",
- it->second.size());
- else if (it->first == ResKind::srcpackage)
- title = _PL(
- "The following source package is going to be installed:",
- "The following source packages are going to be installed:",
- it->second.size());
- break;
- case TO_REINSTALL:
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is going to be reinstalled:",
- "The following packages are going to be reinstalled:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following patch is going to be reinstalled:",
- "The following patches are going to be reinstalled:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following pattern is going to be reinstalled:",
- "The following patterns are going to be reinstalled:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following product is going to be reinstalled:",
- "The following products are going to be reinstalled:",
- it->second.size());
- break;
- case TO_REMOVE:
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is going to be REMOVED:",
- "The following packages are going to be REMOVED:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following patch is going to be REMOVED:",
- "The following patches are going to be REMOVED:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following pattern is going to be REMOVED:",
- "The following patterns are going to be REMOVED:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following product is going to be REMOVED:",
- "The following products are going to be REMOVED:",
- it->second.size());
- break;
- case TO_CHANGE_ARCH:
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is going to change architecture:",
- "The following packages are going to change architecture:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following patch is going to change architecture:",
- "The following patches are going to change architecture:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following pattern is going to change architecture:",
- "The following patterns are going to change architecture:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following product is going to change architecture:",
- "The following products are going to change architecture:",
- it->second.size());
- break;
- case TO_CHANGE_VENDOR:
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is going to change vendor:",
- "The following packages are going to change vendor:",
- it->second.size());
- else if (it->first == ResKind::patch)
- title = _PL(
- "The following patch is going to change vendor:",
- "The following patches are going to change vendor:",
- it->second.size());
- else if (it->first == ResKind::pattern)
- title = _PL(
- "The following pattern is going to change vendor:",
- "The following patterns are going to change vendor:",
- it->second.size());
- else if (it->first == ResKind::product)
- title = _PL(
- "The following product is going to change vendor:",
- "The following products are going to change vendor:",
- it->second.size());
- break;
- case UNSUPPORTED:
- // we only look vendor support in packages
- if (it->first == ResKind::package)
- title = _PL(
- "The following package is not supported by its vendor:",
- "The following packages are not supported by their vendor:",
- it->second.size());
- break;
- }
-
- show_summary_resolvable_list(title, it, zypper.out());
- }
-}
enum
{
@@ -553,51 +210,27 @@ enum
*/
static int summary(Zypper & zypper)
{
- int retv = SUMMARY_NOTHING_TO_DO;
+ Summary::ViewOptions options = Summary::DEFAULT;
- MIL << "Pool contains " << God->pool().size() << " items." << std::endl;
- DBG << "Install summary:" << endl;
-
- KindToResObjectSet to_be_installed;
- KindToResObjectSet to_be_removed;
+ // if running on SUSE Linux Enterprise, report unsupported packages
+ Product::constPtr platform = God->target()->baseProduct();
+ if (platform && platform->name().find("SUSE_SLE") != string::npos)
+ options = (Summary::ViewOptions) (options | Summary::SHOW_UNSUPPORTED);
- // collect resolvables to be installed/removed and set the return status
- for ( ResPool::const_iterator it = God->pool().begin(); it != God->pool().end(); ++it )
- {
- ResObject::constPtr res = it->resolvable();
- if ( it->status().isToBeInstalled() || it->status().isToBeUninstalled() )
- {
- if (it->resolvable()->kind() == ResKind::patch)
- {
- Patch::constPtr patch = asKind<Patch>(it->resolvable());
-
- // set return value to 'reboot needed'
- if (patch->rebootSuggested())
- zypper.setExitCode(ZYPPER_EXIT_INF_REBOOT_NEEDED);
- // set return value to 'restart needed' (restart of package manager)
- // however, 'reboot needed' takes precedence
- else if (zypper.exitCode() != ZYPPER_EXIT_INF_REBOOT_NEEDED && patch->restartSuggested())
- zypper.setExitCode(ZYPPER_EXIT_INF_RESTART_NEEDED);
- }
+ Summary summary(God->pool(), options);
- if ( it->status().isToBeInstalled() )
- {
- DBG << "<install> ";
- to_be_installed[it->resolvable()->kind()].insert(it->resolvable());
- }
- if ( it->status().isToBeUninstalled() )
- {
- DBG << "<uninstall> ";
- to_be_removed[it->resolvable()->kind()].insert(it->resolvable());
- }
- DBG << *res << endl;
- }
- }
+ // set return value to 'reboot needed'
+ if (summary.needMachineReboot())
+ zypper.setExitCode(ZYPPER_EXIT_INF_REBOOT_NEEDED);
+ // set return value to 'restart needed' (restart of package manager)
+ // however, 'reboot needed' takes precedence
+ else if (zypper.exitCode() != ZYPPER_EXIT_INF_REBOOT_NEEDED && summary.needPkgMgrRestart())
+ zypper.setExitCode(ZYPPER_EXIT_INF_RESTART_NEEDED);
- if (!to_be_removed.empty() || !to_be_installed.empty())
+ int retv = SUMMARY_NOTHING_TO_DO;
+ if (summary.packagesToGetAndInstall() || summary.packagesToRemove())
retv = SUMMARY_OK;
-
- if (retv == SUMMARY_NOTHING_TO_DO && zypper.runtimeData().srcpkgs_to_install.empty())
+ else
{
if (zypper.command() == ZypperCommand::VERIFY)
zypper.out().info(_("Dependencies of all installed packages are satisfied."));
@@ -610,180 +243,23 @@ static int summary(Zypper & zypper)
zypper.out().info(_("Some of the dependencies of installed packages are broken."
" In order to fix these dependencies, the following actions need to be taken:"));
- // total packages to download&install.
- zypper.runtimeData().commit_pkgs_total;
- for (KindToResObjectSet::const_iterator it = to_be_installed.begin();
- it != to_be_installed.end(); ++it)
- zypper.runtimeData().commit_pkgs_total += it->second.size();
+ // total packages to download & install. To be used to write overall progress.
+ zypper.runtimeData().commit_pkgs_total = summary.packagesToGetAndInstall();
zypper.runtimeData().commit_pkg_current = 0;
- KindToResObjectSet toinstall;
- KindToResObjectSet toupgrade;
- KindToResObjectSet todowngrade;
- KindToResObjectSet toreinstall;
- KindToResObjectSet toremove;
- KindToResObjectSet tochangearch;
- KindToResObjectSet tochangevendor;
- // objects from previous lists that
- // are not supported
- KindToResObjectSet tounsupported;
-
- // iterate the to_be_installed to find installs/upgrades/downgrades + size info
- ByteCount download_size, new_installed_size;
-
- for (KindToResObjectSet::const_iterator it = to_be_installed.begin();
- it != to_be_installed.end(); ++it)
- {
- for (setResObject::constPtr::const_iterator resit = it->second.begin();
- resit != it->second.end(); ++resit)
- {
- ResObject::constPtr res(*resit);
-
- // FIXME asKind not working?
- Package::constPtr pkg = asKind<Package>(res);
- if ( pkg )
- {
- // FIXME refactor with libzypp Package::vendorSupportAvailable()
-
- if ( pkg->maybeUnsupported() )
- tounsupported[res->kind()].insert(res);
- }
-
- // find in to_be_removed:
- bool upgrade_downgrade = false;
- for (setResObject::constPtr::iterator rmit = to_be_removed[res->kind()].begin();
- rmit != to_be_removed[res->kind()].end(); ++rmit)
- {
- if (res->name() == (*rmit)->name())
- {
- // upgrade
- if (res->edition() > (*rmit)->edition())
- {
- toupgrade[res->kind()].insert(res);
- if (res->arch() != (*rmit)->arch())
- tochangearch[res->kind()].insert(res);
- if (res->vendor() != (*rmit)->vendor())
- tochangevendor[res->kind()].insert(res);
- }
- // reinstall
- else if (res->edition() == (*rmit)->edition())
- {
- toreinstall[res->kind()].insert(res);
- if (res->arch() != (*rmit)->arch())
- tochangearch[res->kind()].insert(res);
- if (res->vendor() != (*rmit)->vendor())
- tochangevendor[res->kind()].insert(res);
- }
- // downgrade
- else
- {
- todowngrade[res->kind()].insert(res);
- if (res->arch() != (*rmit)->arch())
- tochangearch[res->kind()].insert(res);
- if (res->vendor() != (*rmit)->vendor())
- tochangevendor[res->kind()].insert(res);
- }
-
- new_installed_size += res->installSize() - (*rmit)->installSize();
-
- to_be_removed[res->kind()].erase(*rmit);
- upgrade_downgrade = true;
- break;
- }
- }
-
- if (!upgrade_downgrade)
- {
- toinstall[res->kind()].insert(res);
- new_installed_size += res->installSize();
- }
-
- download_size += res->downloadSize();
- }
- }
-
- bool toremove_by_solver = false;
- for (KindToResObjectSet::const_iterator it = to_be_removed.begin();
- it != to_be_removed.end(); ++it)
- for (setResObject::constPtr::const_iterator resit = it->second.begin();
- resit != it->second.end(); ++resit)
- {
- /** \todo this does not work
- if (!toremove_by_solver)
- {
- PoolItem pi(*resit);
- if (pi.status() == ResStatus::SOLVER)
- toremove_by_solver = true;
- }*/
- toremove[it->first].insert(*resit);
- new_installed_size -= (*resit)->installSize();
- }
-
- for (listSrcPackage::constPtr::const_iterator it = zypper.runtimeData().srcpkgs_to_install.begin();
- it != zypper.runtimeData().srcpkgs_to_install.end(); ++it)
- toinstall[ResKind::srcpackage].insert(*it);
-
- if (!toremove.empty() && (
+ if (summary.packagesToRemove() && (
zypper.command() == ZypperCommand::INSTALL ||
zypper.command() == ZypperCommand::UPDATE))
retv = SUMMARY_INSTALL_DOES_REMOVE;
- else if ((!toinstall.empty() || toremove_by_solver)
+ else if (summary.packagesToGetAndInstall()
&& zypper.command() == ZypperCommand::REMOVE)
retv = SUMMARY_REMOVE_DOES_INSTALL;
- // "</install-summary>"
+ // show the summary
if (zypper.out().type() == Out::TYPE_XML)
- {
- cout << "" << endl;
- }
-
- // show summary
- show_summary_of_type(zypper, TO_UPGRADE, toupgrade);
- show_summary_of_type(zypper, TO_DOWNGRADE, todowngrade);
- show_summary_of_type(zypper, TO_INSTALL, toinstall);
- show_summary_of_type(zypper, TO_REINSTALL, toreinstall);
- show_summary_of_type(zypper, TO_REMOVE, toremove);
- show_summary_of_type(zypper, TO_CHANGE_ARCH, tochangearch);
- show_summary_of_type(zypper, TO_CHANGE_VENDOR, tochangevendor);
- // if running on SUSE Linux Enterprise, report unsupported packages
- Product::constPtr platform = God->target()->baseProduct();
- if (platform && platform->name().find("SUSE_SLE") != string::npos)
- show_summary_of_type(zypper, UNSUPPORTED, tounsupported);
-
- // "</install-summary>"
- if (zypper.out().type() == Out::TYPE_XML)
- cout << "</install-summary>" << endl;
-
- zypper.out().info("", Out::NORMAL, Out::TYPE_NORMAL); // visual separator
-
- // count and download size info
- ostringstream s;
- if (download_size > 0)
- {
- s << format(_("Overall download size: %s.")) % download_size;
- s << " ";
- }
- if (new_installed_size > 0)
- // TrasnlatorExplanation %s will be substituted by a byte count e.g. 212 K
- s << format(_("After the operation, additional %s will be used."))
- % new_installed_size.asString(0,1,1);
- else if (new_installed_size == 0)
- s << _("No additional space will be used or freed after the operation.");
+ summary.dumpAsXmlTo(cout);
else
- {
- // get the absolute size
- ByteCount abs;
- abs = (-new_installed_size);
- // TrasnlatorExplanation %s will be substituted by a byte count e.g. 212 K
- s << format(_("After the operation, %s will be freed."))
- % abs.asString(0,1,1);
- }
- zypper.out().info(s.str());
-
- MIL << "DONE" << endl;
+ summary.dumpTo(cout);
return retv;
}
diff --git a/src/utils/Summary.cc b/src/utils/Summary.cc
new file mode 100644
index 0000000..99ea39a
--- /dev/null
+++ b/src/utils/Summary.cc
@@ -0,0 +1,697 @@
+/*---------------------------------------------------------------------------*\
+ ____ _ _ __ _ __ ___ _ _
+ |_ / || | '_ \ '_ \/ -_) '_|
+ /__|\_, | .__/ .__/\___|_|
+ |__/|_| |_|
+\*---------------------------------------------------------------------------*/
+
+#include
+#include <iostream>
+#include <sstream>
+#include
+
+#include "zypp/base/Logger.h"
+#include "zypp/ResPool.h"
+#include "zypp/Patch.h"
+#include "zypp/Package.h"
+
+#include "main.h"
+#include "utils/text.h"
+#include "utils/misc.h"
+
+#include "utils/Summary.h"
+
+using namespace std;
+using namespace zypp;
+using boost::format;
+
+// --------------------------------------------------------------------------
+
+bool Summary::ResPairNameCompare::operator()(
+ const ResPair & p1, const ResPair & p2) const
+{
+ return ::strcoll(p1.second->name().c_str(), p2.second->name().c_str()) < 0;
+}
+
+// --------------------------------------------------------------------------
+
+Summary::Summary(const zypp::ResPool & pool, const ViewOptions options)
+ : _pool(pool), _viewop(options), _wrap_width(80)
+{
+ MIL << "Pool contains " << _pool.size() << " items." << std::endl;
+ readPool();
+}
+
+// --------------------------------------------------------------------------
+
+struct ResNameCompare
+{
+ bool operator()(
+ zypp::ResObject::constPtr r1, zypp::ResObject::constPtr r2) const
+ {
+ return ::strcoll(r1->name().c_str(), r2->name().c_str()) < 0;
+ }
+};
+
+typedef std::map<
+ zypp::Resolvable::Kind,
+ std::set > KindToResObjectSet;
+
+// --------------------------------------------------------------------------
+
+void Summary::readPool()
+{
+ // reset stats
+ _need_reboot = false;
+ _need_restart = false;
+ _inst_pkg_total = 0;
+
+ _todownload = ByteCount();
+ _inst_size_change = ByteCount();
+
+ // collect resolvables to be installed/removed
+
+ KindToResObjectSet to_be_installed;
+ KindToResObjectSet to_be_removed;
+
+ DBG << "Install summary:" << endl;
+
+ for (ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it)
+ {
+ if (it->status().isToBeInstalled() || it->status().isToBeUninstalled())
+ {
+ if (it->resolvable()->kind() == ResKind::patch)
+ {
+ Patch::constPtr patch = asKind<Patch>(it->resolvable());
+
+ // set the 'need reboot' flag
+ if (patch->rebootSuggested())
+ _need_reboot = true;
+ else if (patch->restartSuggested())
+ _need_restart = true;
+ }
+
+ if (it->status().isToBeInstalled())
+ {
+ DBG << "<install> ";
+ to_be_installed[it->resolvable()->kind()].insert(it->resolvable());
+ }
+ if (it->status().isToBeUninstalled())
+ {
+ DBG << "<uninstall> ";
+ to_be_removed[it->resolvable()->kind()].insert(it->resolvable());
+ }
+ DBG << *it << endl;
+ }
+ }
+
+ // total packages to download & install
+ // (packages & srcpackages only - patches, patterns, and products are virtual)
+ _inst_pkg_total =
+ to_be_installed[ResKind::package].size() +
+ to_be_installed[ResKind::srcpackage].size();
+
+/* This will work again after commit refactoring: all the srcpackages will be in the pool
+
+ for (listSrcPackage::constPtr::const_iterator it = zypper.runtimeData().srcpkgs_to_install.begin();
+ it != zypper.runtimeData().srcpkgs_to_install.end(); ++it)
+ toinstall[ResKind::srcpackage].insert(*it);
+*/
+
+ // iterate the to_be_installed to find installs/upgrades/downgrades + size info
+
+ ResObject::constPtr nullres;
+
+ for (KindToResObjectSet::const_iterator it = to_be_installed.begin();
+ it != to_be_installed.end(); ++it)
+ {
+ for (setResObject::constPtr::const_iterator resit = it->second.begin();
+ resit != it->second.end(); ++resit)
+ {
+ ResObject::constPtr res(*resit);
+
+ // FIXME asKind not working?
+ Package::constPtr pkg = asKind<Package>(res);
+ if (pkg)
+ {
+ // FIXME refactor with libzypp Package::vendorSupportAvailable()
+ if (pkg->maybeUnsupported())
+ unsupported[res->kind()].insert(ResPair(nullres, res));
+ }
+
+ // find in to_be_removed:
+ bool upgrade_downgrade = false;
+ for (setResObject::constPtr::iterator rmit = to_be_removed[res->kind()].begin();
+ rmit != to_be_removed[res->kind()].end(); ++rmit)
+ {
+ if (res->name() == (*rmit)->name())
+ {
+ ResPair rp(*rmit, res);
+
+ // upgrade
+ if (res->edition() > (*rmit)->edition())
+ {
+ toupgrade[res->kind()].insert(rp);
+ if (res->arch() != (*rmit)->arch())
+ tochangearch[res->kind()].insert(rp);
+ if (res->vendor() != (*rmit)->vendor())
+ tochangevendor[res->kind()].insert(rp);
+ }
+ // reinstall
+ else if (res->edition() == (*rmit)->edition())
+ {
+ toreinstall[res->kind()].insert(rp);
+ if (res->arch() != (*rmit)->arch())
+ tochangearch[res->kind()].insert(rp);
+ if (res->vendor() != (*rmit)->vendor())
+ tochangevendor[res->kind()].insert(rp);
+ }
+ // downgrade
+ else
+ {
+ todowngrade[res->kind()].insert(rp);
+ if (res->arch() != (*rmit)->arch())
+ tochangearch[res->kind()].insert(rp);
+ if (res->vendor() != (*rmit)->vendor())
+ tochangevendor[res->kind()].insert(rp);
+ }
+
+ _inst_size_change += res->installSize() - (*rmit)->installSize();
+
+ // this turned out to be an upgrade/downgrade
+ to_be_removed[res->kind()].erase(*rmit);
+ upgrade_downgrade = true;
+ break;
+ }
+ }
+
+ if (!upgrade_downgrade)
+ {
+ toinstall[res->kind()].insert(ResPair(NULL, res));
+ _inst_size_change += res->installSize();
+ }
+
+ _todownload += res->downloadSize();
+ }
+ }
+
+ //bool toremove_by_solver = false;
+ for (KindToResObjectSet::const_iterator it = to_be_removed.begin();
+ it != to_be_removed.end(); ++it)
+ for (setResObject::constPtr::const_iterator resit = it->second.begin();
+ resit != it->second.end(); ++resit)
+ {
+ /** \todo this does not work
+ if (!toremove_by_solver)
+ {
+ PoolItem pi(*resit);
+ if (pi.status() == ResStatus::SOLVER)
+ toremove_by_solver = true;
+ }*/
+ toremove[it->first].insert(ResPair(nullres, *resit));
+ _inst_size_change -= (*resit)->installSize();
+ }
+}
+
+// --------------------------------------------------------------------------
+
+unsigned Summary::packagesToRemove() const
+{
+ // total packages to remove (packages only - patches, patterns, and products
+ // are virtual; srcpackages do not get removed by zypper)
+ KindToResPairSet::const_iterator it = toremove.find(ResKind::package);
+ if (it != toremove.end())
+ return it->second.size();
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeResolvableList(ostream & out, const ResPairSet & resolvables)
+{
+ if (_viewop == DEFAULT)
+ {
+ ostringstream s;
+ for (ResPairSet::const_iterator resit = resolvables.begin();
+ resit != resolvables.end(); ++resit)
+ s << resit->second->name() << " ";
+ wrap_text(out, s.str(), 2, _wrap_width);
+ out << endl;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+// plus edition and architecture for verbose output
+/*
+if (out.verbosity() > Out::NORMAL)
+{
+ s << "-" << res->edition() << "." << res->arch();
+
+ const string & reponame = res->repoInfo().name();
+ if (!res->vendor().empty() || !reponame.empty())
+ {
+ s << " (";
+ // plus repo providing this package
+ if (!reponame.empty())
+ s << reponame;
+ // plus package vendor
+ if (!res->vendor().empty())
+ s << (reponame.empty() ? "" : ", ") << res->vendor();
+ s << ")";
+ }
+ // new line after each package in the verbose mode
+ s << endl;
+}
+*/
+
+// --------------------------------------------------------------------------
+
+void Summary::writeNewlyInstalled(ostream & out)
+{
+ for_(it, toinstall.begin(), toinstall.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following NEW package is going to be installed:",
+ "The following NEW packages are going to be installed:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following NEW patch is going to be installed:",
+ "The following NEW patches are going to be installed:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following NEW pattern is going to be installed:",
+ "The following NEW patterns are going to be installed:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following NEW product is going to be installed:",
+ "The following NEW products are going to be installed:",
+ it->second.size());
+ else if (it->first == ResKind::srcpackage)
+ label = _PL(
+ "The following source package is going to be installed:",
+ "The following source packages are going to be installed:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeRemoved(ostream & out)
+{
+ for_(it, toupgrade.begin(), toupgrade.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is going to be REMOVED:",
+ "The following packages are going to be REMOVED:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following patch is going to be REMOVED:",
+ "The following patches are going to be REMOVED:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following pattern is going to be REMOVED:",
+ "The following patterns are going to be REMOVED:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following product is going to be REMOVED:",
+ "The following products are going to be REMOVED:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeUpgraded(ostream & out)
+{
+ for_(it, toupgrade.begin(), toupgrade.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is going to be upgraded:",
+ "The following packages are going to be upgraded:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following patch is going to be upgraded:",
+ "The following patches are going to be upgraded:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following pattern is going to be upgraded:",
+ "The following patterns are going to be upgraded:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following product is going to be upgraded:",
+ "The following products are going to be upgraded:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeDowngraded(ostream & out)
+{
+ for_(it, todowngrade.begin(), todowngrade.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is going to be downgraded:",
+ "The following packages are going to be downgraded:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following patch is going to be downgraded:",
+ "The following patches are going to be downgraded:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following pattern is going to be downgraded:",
+ "The following patterns are going to be downgraded:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following product is going to be downgraded:",
+ "The following products are going to be downgraded:",
+ it->second.size());
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeReinstalled(ostream & out)
+{
+ for_(it, toreinstall.begin(), toreinstall.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is going to be reinstalled:",
+ "The following packages are going to be reinstalled:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following patch is going to be reinstalled:",
+ "The following patches are going to be reinstalled:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following pattern is going to be reinstalled:",
+ "The following patterns are going to be reinstalled:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following product is going to be reinstalled:",
+ "The following products are going to be reinstalled:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeRecommended(ostream & out)
+{/*
+ for_(it, recommended.begin(), recommended.end())
+ {
+ string label;
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }*/
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeSuggested(ostream & out)
+{/*
+ for_(it, suggested.begin(), suggested.end())
+ {
+ string label;
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }*/
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeChangedArch(ostream & out)
+{
+ for_(it, tochangearch.begin(), tochangearch.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is going to change architecture:",
+ "The following packages are going to change architecture:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following patch is going to change architecture:",
+ "The following patches are going to change architecture:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following pattern is going to change architecture:",
+ "The following patterns are going to change architecture:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following product is going to change architecture:",
+ "The following products are going to change architecture:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeChangedVendor(ostream & out)
+{
+ for_(it, tochangevendor.begin(), tochangevendor.end())
+ {
+ string label;
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is going to change vendor:",
+ "The following packages are going to change vendor:",
+ it->second.size());
+ else if (it->first == ResKind::patch)
+ label = _PL(
+ "The following patch is going to change vendor:",
+ "The following patches are going to change vendor:",
+ it->second.size());
+ else if (it->first == ResKind::pattern)
+ label = _PL(
+ "The following pattern is going to change vendor:",
+ "The following patterns are going to change vendor:",
+ it->second.size());
+ else if (it->first == ResKind::product)
+ label = _PL(
+ "The following product is going to change vendor:",
+ "The following products are going to change vendor:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeUnsupported(ostream & out)
+{
+ for_(it, unsupported.begin(), unsupported.end())
+ {
+ string label;
+ // we only look vendor support in packages
+ if (it->first == ResKind::package)
+ label = _PL(
+ "The following package is not supported by its vendor:",
+ "The following packages are not supported by their vendor:",
+ it->second.size());
+ out << endl << label << endl;
+
+ writeResolvableList(out, it->second);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeDownloadAndInstalledSizeSummary(ostream & out)
+{
+ // download size info
+ ostringstream s;
+ if (_todownload > 0)
+ s << format(_("Overall download size: %s.")) % _todownload << " ";
+
+ // installed size change info
+ if (_inst_size_change > 0)
+ // TrasnlatorExplanation %s will be substituted by a byte count e.g. 212 K
+ s << format(_("After the operation, additional %s will be used."))
+ % _inst_size_change.asString(0,1,1);
+ else if (_inst_size_change == 0)
+ s << _("No additional space will be used or freed after the operation.");
+ else
+ {
+ // get the absolute size
+ ByteCount abs;
+ abs = (-_inst_size_change);
+ // TrasnlatorExplanation %s will be substituted by a byte count e.g. 212 K
+ s << format(_("After the operation, %s will be freed.")) % abs.asString(0,1,1);
+ }
+
+ wrap_text(out, s.str(), 0, _wrap_width);
+ out << endl;
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::dumpTo(ostream & out)
+{
+ _wrap_width = get_screen_width();
+
+ writeNewlyInstalled(out);
+ writeRemoved(out);
+ writeUpgraded(out);
+ writeDowngraded(out);
+ writeReinstalled(out);
+ if (_viewop & SHOW_RECOMMENDED)
+ writeRecommended(out);
+ if (_viewop & SHOW_SUGGESTED)
+ writeSuggested(out);
+ writeChangedArch(out);
+ writeChangedVendor(out);
+ if (_viewop & SHOW_UNSUPPORTED)
+ writeUnsupported(out);
+ //! \todo write package counts
+ writeDownloadAndInstalledSizeSummary(out);
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::writeXmlResolvableList(ostream & out, const KindToResPairSet & resolvables)
+{
+ for_(it, resolvables.begin(), resolvables.end())
+ {
+ for_(pairit, it->second.begin(), it->second.end())
+ {
+ ResObject::constPtr res(pairit->second);
+ ResObject::constPtr rold(pairit->first);
+
+ out << "kind() << "\"";
+ out << " name=\"" << res->name() << "\"";
+ out << " edition=\"" << res->edition() << "\"";
+ out << " arch=\"" << res->arch() << "\"";
+ if (rold)
+ {
+ out << " edition-old=\"" << rold->edition() << "\"";
+ out << " arch-old=\"" << rold->edition() << "\"";
+ }
+ if (!res->summary().empty())
+ out << " summary=\"" << xml_encode(res->summary()) << "\"";
+ if (!res->description().empty())
+ out << ">" << endl << xml_encode(res->description()) << "</solvable>" << endl;
+ else
+ out << "/>" << endl;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void Summary::dumpAsXmlTo(ostream & out)
+{
+ out << "" << endl;
+
+ if (!toupgrade.empty())
+ {
+ out << "<to-upgrade>" << endl;
+ writeXmlResolvableList(out, toupgrade);
+ out << "</to-upgrade>" << endl;
+ }
+
+ if (!todowngrade.empty())
+ {
+ out << "<to-downgrade>" << endl;
+ writeXmlResolvableList(out, todowngrade);
+ out << "</to-downgrade>" << endl;
+ }
+
+ if (!toinstall.empty())
+ {
+ out << "<to-install>" << endl;
+ writeXmlResolvableList(out, toinstall);
+ out << "</to-install>" << endl;
+ }
+
+ if (!toreinstall.empty())
+ {
+ out << "<to-reinstall>" << endl;
+ writeXmlResolvableList(out, toreinstall);
+ out << "</to-reinstall>" << endl;
+ }
+
+ if (!toremove.empty())
+ {
+ out << "<to-remove>" << endl;
+ writeXmlResolvableList(out, toremove);
+ out << "</to-remove>" << endl;
+ }
+
+ if (!tochangearch.empty())
+ {
+ out << "<to-change-arch>" << endl;
+ writeXmlResolvableList(out, tochangearch);
+ out << "</to-change-arch>" << endl;
+ }
+
+ if (!tochangevendor.empty())
+ {
+ out << "<to-change-vendor>" << endl;
+ writeXmlResolvableList(out, tochangevendor);
+ out << "</to-change-vendor>" << endl;
+ }
+
+ if (_viewop & SHOW_UNSUPPORTED && !unsupported.empty())
+ {
+ out << "<unsupported>" << endl;
+ writeXmlResolvableList(out, unsupported);
+ out << "</unsupported>" << endl;
+ }
+
+ out << "</install-summary>" << endl;
+}
diff --git a/src/utils/Summary.h b/src/utils/Summary.h
new file mode 100644
index 0000000..cb08462
--- /dev/null
+++ b/src/utils/Summary.h
@@ -0,0 +1,117 @@
+/*---------------------------------------------------------------------------*\
+ ____ _ _ __ _ __ ___ _ _
+ |_ / || | '_ \ '_ \/ -_) '_|
+ /__|\_, | .__/ .__/\___|_|
+ |__/|_| |_|
+\*---------------------------------------------------------------------------*/
+
+#ifndef ZYPPER_UTILS_SUMMARY_H_
+#define ZYPPER_UTILS_SUMMARY_H_
+
+#include <set>
+#include <map>
+#include <iosfwd>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/ByteCount.h"
+#include "zypp/ResObject.h"
+#include "zypp/ResPool.h"
+
+
+class Summary : private zypp::base::NonCopyable
+{
+public:
+ typedef std::pair ResPair;
+ struct ResPairNameCompare
+ {
+ inline bool operator()(const ResPair & p1, const ResPair & p2) const;
+ };
+ typedef std::set ResPairSet;
+ typedef std::map KindToResPairSet;
+
+ enum _view_options
+ {
+ DEFAULT = 0x0300,
+ DETAILS = 0xfbff,
+
+ SHOW_VERSION = 0x0001,
+ SHOW_ARCH = 0x0002,
+ SHOW_REPO = 0x0004,
+ SHOW_VENDOR = 0x0008,
+
+ SHOW_SUGGESTED = 0x0100,
+ SHOW_RECOMMENDED = 0x0200,
+ SHOW_UNSUPPORTED = 0x0400,
+
+ SHOW_ALL = 0xffff
+ };
+
+ typedef enum _view_options ViewOptions;
+
+public:
+ Summary(const zypp::ResPool & pool, const ViewOptions options = DEFAULT);
+ ~Summary() {}
+
+ void readPool();
+
+ void writeNewlyInstalled(std::ostream & out);
+ void writeRemoved(std::ostream & out);
+ void writeUpgraded(std::ostream & out);
+ void writeDowngraded(std::ostream & out);
+ void writeReinstalled(std::ostream & out);
+ void writeRecommended(std::ostream & out);
+ void writeSuggested(std::ostream & out);
+ void writeChangedArch(std::ostream & out);
+ void writeChangedVendor(std::ostream & out);
+ void writeUnsupported(std::ostream & out);
+ void writeDownloadAndInstalledSizeSummary(std::ostream & out);
+
+ unsigned packagesToGetAndInstall() const
+ { return _inst_pkg_total; }
+ unsigned packagesToRemove() const;
+ const zypp::ByteCount & toDownload() const
+ { return _todownload; }
+ const zypp::ByteCount & installedSizeChange() const
+ { return _inst_size_change; }
+
+ bool needMachineReboot() const
+ { return _need_reboot; }
+
+ bool needPkgMgrRestart() const
+ { return _need_restart; }
+
+
+ void dumpTo(std::ostream & out);
+ void dumpAsXmlTo(std::ostream & out);
+
+private:
+ void writeResolvableList(std::ostream & out, const ResPairSet & resolvables);
+ void writeXmlResolvableList(std::ostream & out, const KindToResPairSet & resolvables);
+
+private:
+ zypp::ResPool _pool;
+ ViewOptions _viewop;
+ mutable unsigned _wrap_width;
+
+ bool _need_reboot;
+ bool _need_restart;
+
+ zypp::ByteCount _todownload;
+ zypp::ByteCount _inst_size_change;
+
+ // STATS
+
+ unsigned _inst_pkg_total;
+
+ KindToResPairSet toinstall;
+ KindToResPairSet toupgrade;
+ KindToResPairSet todowngrade;
+ KindToResPairSet toreinstall;
+ KindToResPairSet toremove;
+ KindToResPairSet tochangearch;
+ KindToResPairSet tochangevendor;
+ /** objects from previous lists that are not supported */
+ KindToResPairSet unsupported;
+};
+
+#endif /* ZYPPER_UTILS_SUMMARY_H_ */
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org