- split misc into install, update, and solve-commit.cc
authorJan Kupec <jkupec@suse.cz>
Tue, 8 Jul 2008 13:02:04 +0000 (13:02 +0000)
committerJan Kupec <jkupec@suse.cz>
Tue, 8 Jul 2008 13:02:04 +0000 (13:02 +0000)
14 files changed:
doc/TODO
src/CMakeLists.txt
src/Zypper.cc
src/install.cc [new file with mode: 0755]
src/install.h [new file with mode: 0755]
src/misc.cc
src/misc.h
src/repos.cc
src/solve-commit.cc [new file with mode: 0755]
src/solve-commit.h [new file with mode: 0755]
src/update.cc [new file with mode: 0755]
src/update.h [new file with mode: 0755]
src/utils/pager.cc [new file with mode: 0755]
src/utils/pager.h [new file with mode: 0755]

index 9c77a73..d59ceca 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -6,10 +6,7 @@
 - zypper [help] rug
 - add help texts for prompts
 - code reorganization
-  - remove zypper- prefix from sources
-  - split misc.cc into common/commit(solver dialog, summary, commit)/update/install-srcinstall-remove code
   - clean up/split utils.cc
-- drop xu command
 - show recommended and suggested in the summary
 - report licenses of installed software
 
@@ -17,7 +14,7 @@
 NOT SCHEDULED
 -------------
 
-- - we want it
++ - we want it
 ? - idea
 
 General
index 709eafd..744f1c7 100644 (file)
@@ -19,6 +19,9 @@ SET (zypper_HEADERS
   richtext.h
   Table.h
   locks.h
+  install.h
+  update.h
+  solve-commit.h
   callbacks/keyring.h
   callbacks/media.h
   callbacks/rpm.h
@@ -39,6 +42,9 @@ SET( zypper_SRCS
   prompt.cc
   richtext.cc
   locks.cc
+  install.cc
+  update.cc
+  solve-commit.cc
   ${zypper_HEADERS}
 )
 
@@ -57,7 +63,16 @@ SET( zypper_out_SRCS
   ${zypper_out_HEADERS}
 )
 
-ADD_EXECUTABLE( zypper ${zypper_SRCS} ${zypper_out_SRCS} )
+SET( zypper_utils_HEADERS
+  utils/pager.h
+)
+
+SET( zypper_utils_SRCS
+  utils/pager.cc
+  ${zypper_utils_HEADERS}
+)
+
+ADD_EXECUTABLE( zypper ${zypper_SRCS} ${zypper_out_SRCS} ${zypper_utils_SRCS} )
 TARGET_LINK_LIBRARIES( zypper ${ZYPP_LIBRARY} ${READLINE_LIBRARY} )
 
 INSTALL(
index 8d0d116..226cd09 100644 (file)
 
 #include "main.h"
 #include "Zypper.h"
+#include "Command.h"
+
+#include "Table.h"
+#include "utils.h"
+#include "getopt.h"
+
 #include "repos.h"
+#include "install.h"
+#include "update.h"
+#include "solve-commit.h"
 #include "misc.h"
 #include "locks.h"
-
-#include "Table.h"
 #include "search.h"
 #include "info.h"
-#include "getopt.h"
-#include "Command.h"
-#include "utils.h"
 
 #include "output/OutNormal.h"
 #include "output/OutXML.h"
diff --git a/src/install.cc b/src/install.cc
new file mode 100755 (executable)
index 0000000..1874214
--- /dev/null
@@ -0,0 +1,625 @@
+#include <boost/format.hpp>
+
+#include "zypp/base/Logger.h"
+#include "zypp/ZYppFactory.h"
+#include "zypp/base/Algorithm.h"
+#include "zypp/PoolQuery.h"
+
+#include "utils.h"
+
+#include "install.h"
+
+using namespace std;
+using namespace zypp;
+using namespace boost;
+
+extern ZYpp::Ptr God;
+
+// copied from yast2-pkg-bindings:PkgModuleFunctions::DoProvideNameKind
+bool ProvideProcess::operator()( const PoolItem& provider )
+{
+  DBG << "Considering " << provider << endl;
+  // 1. compatible arch
+  // 2. best arch
+  // 3. best edition
+
+  // check the repository alias if it's specified
+  if (!_repo.empty() && _repo != provider->repository().info().alias())
+  {
+    DBG << format ("Skipping repository %s (requested: %s)")
+      % provider->repository().info().alias() % _repo << endl;
+    return true;
+  }
+
+  bool is_installed;
+  if (provider->isKind(ResKind::package))
+    is_installed = provider.status().isInstalled();
+  else
+    is_installed = provider.isSatisfied();
+
+  if (!is_installed)
+  {
+    // deselect the item if it's already selected,
+    // only one item should be selected
+    if (provider.status().isToBeInstalled()) {
+      DBG << "  Deselecting" << endl;
+      provider.status().resetTransact(whoWantsIt);
+    }
+
+    // regarding items which are installable only
+    if (!provider->arch().compatibleWith( _architecture )) {
+      DBG << format ("provider %s has incompatible arch '%s'")
+        % provider->name() % provider->arch().asString() << endl;
+    }
+    else if (!item) {
+      DBG << "  First match" << endl;
+      item = provider;
+    }
+    else if (item->arch().compare( provider->arch() ) < 0) {
+      DBG << "  Better arch" << endl;
+      item = provider;
+    }
+    else if (item->edition().compare( provider->edition() ) < 0) {
+      DBG << "  Better edition" << endl;
+      item = provider;
+    }
+  }
+  else {
+    // store encountered target item (installed)
+    installed_item = provider;
+    if (!item) item = provider;
+  }
+
+  return true;
+}
+
+// ----------------------------------------------------------------------------
+
+// this does only resolvables with this _name_.
+// we could also act on _provides_
+// TODO edition, arch
+static void mark_for_install(Zypper & zypper,
+                      const ResObject::Kind &kind,
+                      const std::string &name,
+                      const std::string & repo = "")
+{
+  // name and kind match:
+  ProvideProcess installer (ZConfig::instance().systemArchitecture(), repo);
+  DBG << "Iterating over [" << kind << "]" << name << endl;
+  invokeOnEach(
+      God->pool().byIdentBegin(kind, name),
+      God->pool().byIdentEnd(kind, name),
+      zypp::functor::functorRef<bool,const zypp::PoolItem&> (installer));
+
+  DBG << "... done" << endl;
+  if (!installer.item)
+  {
+    zypper.out().error(
+      // translators: meaning a package %s or provider of capability %s
+      str::form(_("'%s' not found"), name.c_str()));
+    WAR << str::form("'%s' not found", name.c_str()) << endl;
+    zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
+    return;
+  }
+
+  if (installer.installed_item &&
+      installer.installed_item.resolvable()->edition() == installer.item.resolvable()->edition() &&
+      installer.installed_item.resolvable()->arch() == installer.item.resolvable()->arch() &&
+      ( ! copts.count("force") ) )
+  {
+    // if it is broken install anyway, even if it is installed
+    if ( installer.item.isBroken() )
+    {
+      installer.item.status().setTransact( true, zypp::ResStatus::USER );
+    }
+
+    zypper.out().info(boost::str(format(
+      // translators: e.g. skipping package 'zypper' (the newest version already installed)  
+      _("skipping %s '%s' (the newest version already installed)"))
+      % kind_to_string_localized(kind,1) % name));
+  }
+  else {
+
+    //! \todo don't use setToBeInstalled for this purpose but higher level solver API
+    bool result = installer.item.status().setToBeInstalled( zypp::ResStatus::USER );
+    if (!result)
+    {
+      // this is because the resolvable is installed and we are forcing.
+      installer.item.status().setTransact( true, zypp::ResStatus::USER );
+      if (!copts.count("force"))
+      {
+        zypper.out().error(boost::str(
+          format(_("Failed to add '%s' to the list of packages to be installed."))
+          % name));
+        ERR << "Could not set " << name << " as to-be-installed" << endl;
+      }
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+struct DeleteProcess
+{
+  bool found;
+  DeleteProcess ()
+    : found(false)
+  { }
+
+  bool operator() ( const PoolItem& provider )
+  {
+    found = true;
+    DBG << "Marking for deletion: " << provider << endl;
+    bool result = provider.status().setToBeUninstalled( zypp::ResStatus::USER );
+    if (!result) {
+      Zypper::instance()->out().error(boost::str(format(
+          _("Failed to add '%s' to the list of packages to be removed."))
+          % provider.resolvable()->name()));
+      ERR << "Could not set " << provider.resolvable()->name()
+          << " as to-be-uninstalled" << endl;
+    }
+    return true;                // get all of them
+  }
+};
+
+// ----------------------------------------------------------------------------
+
+// mark all matches
+static void mark_for_uninstall(Zypper & zypper,
+                        const ResObject::Kind &kind,
+                        const std::string &name)
+{
+  const ResPool &pool = God->pool();
+  // name and kind match:
+
+  DeleteProcess deleter;
+  DBG << "Iterating over " << name << endl;
+  invokeOnEach( pool.byIdentBegin( kind, name ),
+                pool.byIdentEnd( kind, name ),
+                resfilter::ByInstalled(),
+                zypp::functor::functorRef<bool,const zypp::PoolItem&> (deleter)
+                );
+  DBG << "... done" << endl;
+  if (!deleter.found) {
+    zypper.out().error(
+      // translators: meaning a package %s or provider of capability %s
+      str::form(_("'%s' not found"), name.c_str()));
+    WAR << str::form("'%s' not found", name.c_str()) << endl;
+    zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
+    return;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+static void
+mark_by_name (Zypper & zypper,
+              bool install_not_remove,
+              const ResObject::Kind &kind,
+              const string &name,
+              const string & repo = "")
+{
+  if (install_not_remove)
+    mark_for_install(zypper, kind, name, repo);
+  else
+    mark_for_uninstall(zypper, kind, name);
+}
+
+
+// don't try NAME-EDITION yet, could be confused by
+// dbus-1-x11, java-1_4_2-gcj-compat, ...
+/*
+bool mark_by_name_edition (...)
+  static const regex rx_name_edition("(.*?)-([0-9].*)");
+
+  smatch m;
+  if (! is_cap && regex_match (capstr, m, rx_name_edition)) {
+    capstr = m.str(1) + " = " + m.str(2);
+    is_cap = true;
+  }
+*/
+
+// ----------------------------------------------------------------------------
+
+static void
+mark_by_capability (Zypper & zypper,
+                    bool install_not_remove,
+                    const ResKind & kind,
+                    const Capability & cap)
+{
+  if (!cap.empty()) {
+    DBG << "Capability: " << cap << endl;
+
+    Resolver_Ptr resolver = zypp::getZYpp()->resolver();
+    if (install_not_remove) {
+      DBG << "Adding requirement " << cap << endl;
+      resolver->addRequire (cap);
+    }
+    else {
+      DBG << "Adding conflict " << cap << endl;
+      resolver->addConflict (cap);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+// join arguments at comparison operators ('=', '>=', and the like)
+static void
+install_remove_preprocess_args(const Zypper::ArgList & args,
+                               Zypper::ArgList & argsnew)
+{
+  Zypper::ArgList::size_type argc = args.size();
+  argsnew.reserve(argc);
+  string tmp;
+  // preprocess the arguments
+  for(Zypper::ArgList::size_type i = 0, lastnew = 0; i < argc; ++i)
+  {
+    tmp = args[i];
+    if (i
+        && (tmp == "=" || tmp == "==" || tmp == "<"
+            || tmp == ">" || tmp == "<=" || tmp == ">=")
+        && i < argc - 1)
+    {
+      argsnew[lastnew-1] += tmp + args[++i];
+      continue;
+    }
+    else if (tmp.find_last_of("=<>") == tmp.size() - 1 && i < argc - 1)
+    {
+      argsnew.push_back(tmp + args[++i]);
+      ++lastnew;
+    }
+    else if (i && tmp.find_first_of("=<>") == 0)
+    {
+      argsnew[lastnew-1] += tmp;
+      ++i;
+    }
+    else
+    {
+      argsnew.push_back(tmp);
+      ++lastnew;
+    }
+  }
+
+  DBG << "old: ";
+  copy(args.begin(), args.end(), ostream_iterator<string>(DBG, " "));
+  DBG << endl << "new: ";
+  copy(argsnew.begin(), argsnew.end(), ostream_iterator<string>(DBG, " "));
+  DBG << endl;
+}
+
+// ----------------------------------------------------------------------------
+
+static void
+mark_selectable(Zypper & zypper,
+                ui::Selectable & s,
+                bool install_not_remove,
+                bool force,
+                const string & repo = "",
+                const string & arch = "")
+{
+  PoolItem theone = s.theObj();
+  //! \todo handle multiple installed case
+  bool theoneinstalled; // is the One installed ?
+  if (s.kind() == ResKind::package)
+    theoneinstalled = !s.installedEmpty() && theone &&
+      equalNVRA(*s.installedObj().resolvable(), *theone.resolvable());
+  else if (s.kind() == ResKind::patch)
+    theoneinstalled = theone.isRelevant() && theone.isSatisfied();
+  else
+    theoneinstalled = theone.isSatisfied();
+
+  bool anyinstalled = theoneinstalled;
+  PoolItem installed;
+  if (theoneinstalled)
+    installed = theone;
+  else
+  {
+    if (s.kind() == ResKind::package)
+    {
+      anyinstalled = s.hasInstalledObj();
+      installed = s.installedObj();
+    }
+    else if (s.kind() == ResKind::patch)
+    {
+      for_(it, s.availableBegin(), s.availableEnd())
+      {
+        if (it->isRelevant() && it->isSatisfied())
+        {
+          if (installed)
+          {
+            if (it->resolvable()->edition() > installed->edition())
+              installed = *it;
+          }
+          else
+          {
+            installed = *it;
+            anyinstalled = true;
+          }
+        }
+      }
+    }
+    else
+    {
+      for_(it, s.availableBegin(), s.availableEnd())
+      {
+        if (it->status().isSatisfied())
+        {
+          if (installed)
+          {
+            if (it->resolvable()->edition() > installed->edition())
+              installed = *it;
+          }
+          else
+          {
+            installed = *it;
+            anyinstalled = true;
+          }
+        }
+      }
+    }
+  }
+
+  if (install_not_remove)
+  {
+    if (theoneinstalled && !force)
+    {
+      DBG << "the One (" << theone << ") is installed, skipping." << endl;
+      zypper.out().info(str::form(
+          _("'%s' is already installed."), s.name().c_str()));
+      return;
+    }
+
+    if (theoneinstalled && force)
+    {
+      s.setStatus(ui::S_Install);
+      DBG << s << " install: forcing reinstall" << endl;
+    }
+    else
+    {
+      Capability c;
+
+      // require version greater than the installed. The solver should pick up
+      // the latest installable in this case, which is what we want for all
+      // kinds (and for patches having the latest installed should automatically
+      // satisfy all older version, or make them irrelevant)
+
+      //! could be a problem for patches if there would a greater version
+      //! of a patch appear that would be irrelevant at the same time. Should
+      //! happen probably.
+      if (anyinstalled)
+        c = Capability(s.name(), Rel::GT, installed->edition(), s.kind());
+      // require any version
+      else
+        c = Capability(s.name(), s.kind());
+
+      God->resolver()->addRequire(c);
+      DBG << s << " install: adding requirement " << c << endl;
+    }
+  }
+  // removing is simpler, as usually
+  //! \todo but not that simple - simply adding a conflict with a pattern
+  //! or patch does not make the packages it requires to be removed.
+  //! we still need to define what response of zypper -t foo bar should be for PPP
+  else
+  {
+    if (!anyinstalled)
+    {
+      zypper.out().info(str::form(
+          _("'%s' is not installed."), s.name().c_str()));
+      DBG << s << " remove: not installed, skipping." << endl;
+      return;
+    }
+
+    Capability c(s.name(), s.kind());
+    God->resolver()->addConflict(c);
+    DBG << s << " remove: adding conflict " << c << endl;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+void install_remove(Zypper & zypper,
+                    const Zypper::ArgList & args,
+                    bool install_not_remove,
+                    const ResKind & kind)
+{
+  if (args.empty())
+    return;
+  
+  bool force_by_capability = zypper.cOpts().count("capability");
+  bool force_by_name = zypper.cOpts().count("name");
+  bool force = zypper.cOpts().count("force");
+  if (force)
+    force_by_name = true;
+
+  if (force_by_capability && force_by_name)
+  {
+    zypper.out().error(boost::str(
+      format(_("%s contradicts %s")) % "--capability" % (force? "--force" : "--name")));
+    
+    zypper.setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
+    ZYPP_THROW(ExitRequestException());
+  }
+
+  if (install_not_remove && force_by_capability && force)
+  {
+    // translators: meaning --force with --capability
+    zypper.out().error(boost::str(format(_("%s cannot currently be used with %s"))
+      % "--force" % "--capability"));
+    zypper.setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
+    ZYPP_THROW(ExitRequestException());
+  }
+
+  Zypper::ArgList argsnew;
+  install_remove_preprocess_args(args, argsnew);
+
+  string str, arch, repo;
+  bool by_capability;
+  const ResPool & pool = God->pool();
+  for_(it, argsnew.begin(), argsnew.end())
+  {
+    str = *it; arch.clear(); repo.clear();
+    by_capability = false;
+
+    // install remove modifiers
+    if (str[0] == '+' || str[0] == '~')
+    {
+      install_not_remove = true;
+      str.erase(0, 1);
+    }
+    else if (str[0] == '-' || str[0] == '!')
+    {
+      install_not_remove = false;
+      str.erase(0, 1);
+    }
+
+    string::size_type pos;
+
+    if ((pos = str.rfind(':')) != string::npos)
+    {
+      repo = str.substr(0, pos);
+      str = str.substr(pos + 1);
+      force_by_name = true; // until there is a solver API for this
+    }
+
+    //! \todo force arch with '.' or '@'???
+    if ((pos = str.find('.')) != string::npos)
+    { }
+
+    // mark by name by force
+    if (force_by_name)
+    {
+      mark_by_name (zypper, install_not_remove, kind, str, repo);
+      continue;
+    }
+
+    // recognize missplaced command line options given as packages
+    // bnc#391644
+    if ( str[0] == '-' )
+    {
+      // FIXME show a message here, after string freeze
+      //zypper.out().error(boost::str(format(_("%s is not a valid package or capability name.") % str));
+      zypper.out().error(_("No valid arguments specified."));
+      zypper.setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
+      ZYPP_THROW(ExitRequestException());
+    }
+    
+
+    // is version specified?
+    by_capability = str.find_first_of("=<>") != string::npos;
+
+    // try to find foo-bar-1.2.3-2
+    if (!by_capability && str.find('-') != string::npos)
+    {
+      // try to find the original string first as name
+      // search by name, not in whatprovides, since there can be provider even
+      // for cracklib-dict=small
+      // continue only if nothing has been found this way
+      if (pool.byIdentBegin(kind, str) == pool.byIdentEnd(kind, str))
+      {
+        // try to replace '-' for '=' from right to the left and check
+        // whether there is something providing such capability
+        string::size_type pos = string::npos;
+        while ((pos = str.rfind('-', pos)) != string::npos)
+        {
+          string trythis = str;
+          trythis.replace(pos, 1, 1, '=');
+          string tryver = str.substr(pos + 1, str.size() - 1);
+
+          DBG << "trying: " << trythis << " edition: " << tryver << endl;
+
+          Capability cap = safe_parse_cap (zypper, trythis, kind);
+          sat::WhatProvides q(cap);
+          for_(sit, q.begin(), q.end())
+          {
+            if (sit->edition().match(tryver) == 0)
+            {
+              str = trythis;
+              by_capability = true;
+              DBG << str << "might be what we wanted" << endl;
+              break;
+            }
+          }
+          if (by_capability)
+            break;
+          --pos;
+        }
+      }
+    }
+
+    // try to find by name + wildcards first
+    if (!by_capability)
+    {
+      PoolQuery q;
+      q.addKind(kind);
+      q.addAttribute(sat::SolvAttr::name, str);
+      q.setMatchGlob();
+      bool found = false;
+      for_(s, q.selectableBegin(), q.selectableEnd())
+      {
+        mark_selectable(zypper, **s, install_not_remove, force);
+        found = true;
+      }
+      // done with this requirement, skip to next argument
+      if (found)
+        continue;
+    }
+
+    // try by capability
+
+    Capability cap = safe_parse_cap (zypper, str, kind);
+    sat::WhatProvides q(cap);
+
+    // is there a provider for the requested capability?
+    if (q.empty())
+    {
+      // translators: meaning a package %s or provider of capability %s
+      zypper.out().error(str::form(_("'%s' not found."), str.c_str()));
+      WAR << str::form("'%s' not found", str.c_str()) << endl;
+      zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
+      continue;
+    }
+
+    // is the provider already installed?
+    bool installed = false;
+    string provider; 
+    for_(solvit, q.poolItemBegin(), q.poolItemEnd())
+    {
+      if (solvit->resolvable()->isKind(ResKind::package))
+        installed = solvit->status().isInstalled();
+      else
+        installed = solvit->isSatisfied();
+      if (installed)
+      {
+        provider = solvit->resolvable()->name(); 
+        break;
+      }
+    }
+    // already installed, nothing to do
+    if (installed && install_not_remove)
+    {
+      if (provider == str)
+        zypper.out().info(str::form(
+            _("'%s' is already installed."), str.c_str()));
+      else
+        zypper.out().info(str::form(
+            // translators: %s are package names
+            _("'%s' providing '%s' is already installed."),
+            provider.c_str(), str.c_str()));
+
+      MIL << str::form("skipping '%s': already installed", str.c_str()) << endl;
+      continue;
+    }
+    // not installed, nothing to do
+    else if (!installed && !install_not_remove)
+    {
+      // translators: meaning a package %s or provider of capability %s
+      zypper.out().info(str::form(_("'%s' is not installed."), str.c_str()));
+      MIL << str::form("skipping '%s': not installed", str.c_str()) << endl;
+      continue;
+    }
+
+    mark_by_capability (zypper, install_not_remove, kind, cap);
+  }
+}
diff --git a/src/install.h b/src/install.h
new file mode 100755 (executable)
index 0000000..f357639
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef INSTALL_H_
+#define INSTALL_H_
+
+#include "zypp/PoolItem.h"
+
+#include "Zypper.h"
+
+
+void install_remove(Zypper & zypper,
+                    const Zypper::ArgList & args,
+                    bool install_not_remove,
+                    const zypp::ResKind & kind);
+
+// copied from yast2-pkg-bindings:PkgModuleFunctions::DoProvideNameKind
+struct ProvideProcess
+{
+  zypp::PoolItem item;
+  zypp::PoolItem installed_item;
+  zypp::ResStatus::TransactByValue whoWantsIt;
+  std::string _repo;
+  zypp::Arch _architecture;
+
+  ProvideProcess(zypp::Arch arch, const std::string & repo)
+    : whoWantsIt(zypp::ResStatus::USER)
+    , _repo(repo)
+    , _architecture( arch )
+    { }
+
+  bool operator()( const zypp::PoolItem& provider );
+};
+
+#endif /*INSTALL_H_*/
index 56250f0..c8ef5bf 100644 (file)
@@ -1,54 +1,35 @@
-#include <iostream>
-#include <fstream>
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+
 #include <sstream>
-#include <ctype.h>
 #include <boost/format.hpp>
-#include <sys/wait.h> //for wait()
 
 #include "zypp/ZYppFactory.h"
 #include "zypp/base/Logger.h"
-#include "zypp/base/Algorithm.h"
 
-#include "zypp/Edition.h"
-#include "zypp/Patch.h"
-#include "zypp/Package.h"
 #include "zypp/SrcPackage.h"
 #include "zypp/Capabilities.h"
-#include "zypp/PoolQuery.h"
-#include "zypp/TmpPath.h"
-
-
-#include "zypp/media/MediaException.h"
-#include "zypp/FileChecker.h"
 
 #include "zypp/RepoInfo.h"
 
-#include "Zypper.h"
 #include "main.h"
 #include "utils.h"
 #include "getopt.h"
 #include "richtext.h"
 #include "prompt.h"
-#include "output/prompt.h"
 
 #include "misc.h"
+#include "utils/pager.h"
 
 using namespace std;
 using namespace zypp;
 using namespace boost;
 
 extern ZYpp::Ptr God;
-extern RuntimeData gData;
-
-
-/**
- * Loops through resolvables, checking if there is license to confirm. When
- * run interactively, it displays a dialog, otherwise it answers automatically
- * according to --auto-agree-with-licenses present or not present.
- * 
- * \returns true if all licenses have been confirmed, false otherwise.  
- */
-static bool confirm_licenses(Zypper & zypper);
 
 // converts a user-supplied kind to a zypp kind object
 // returns an empty one if not recognized
@@ -78,672 +59,6 @@ ResKind string_to_kind (const string &skind)
   return empty;
 }
 
-// copied from yast2-pkg-bindings:PkgModuleFunctions::DoProvideNameKind
-bool ProvideProcess::operator()( const PoolItem& provider )
-{
-  DBG << "Considering " << provider << endl;
-  // 1. compatible arch
-  // 2. best arch
-  // 3. best edition
-
-  // check the repository alias if it's specified
-  if (!_repo.empty() && _repo != provider->repository().info().alias())
-  {
-    DBG << format ("Skipping repository %s (requested: %s)")
-      % provider->repository().info().alias() % _repo << endl;
-    return true;
-  }
-
-  bool is_installed;
-  if (provider->isKind(ResKind::package))
-    is_installed = provider.status().isInstalled();
-  else
-    is_installed = provider.isSatisfied();
-
-  if (!is_installed)
-  {
-    // deselect the item if it's already selected,
-    // only one item should be selected
-    if (provider.status().isToBeInstalled()) {
-      DBG << "  Deselecting" << endl;
-      provider.status().resetTransact(whoWantsIt);
-    }
-
-    // regarding items which are installable only
-    if (!provider->arch().compatibleWith( _architecture )) {
-      DBG << format ("provider %s has incompatible arch '%s'")
-        % provider->name() % provider->arch().asString() << endl;
-    }
-    else if (!item) {
-      DBG << "  First match" << endl;
-      item = provider;
-    }
-    else if (item->arch().compare( provider->arch() ) < 0) {
-      DBG << "  Better arch" << endl;
-      item = provider;
-    }
-    else if (item->edition().compare( provider->edition() ) < 0) {
-      DBG << "  Better edition" << endl;
-      item = provider;
-    }
-  }
-  else {
-    // store encountered target item (installed)
-    installed_item = provider;
-    if (!item) item = provider;
-  }
-
-  return true;
-}
-
-string pager_help_exit(const string &pager)
-{
-  string endfour = pager.substr(pager.size()-4,4);
-  if (endfour == "less")
-  {
-    return str::form(_("Press '%c' to exit the pager."), 'q');
-  }
-  return string();
-}
-
-string pager_help_navigation(const string &pager)
-{
-  string endfour = pager.substr(pager.size()-4,4);
-  if (endfour == "less")
-  {
-    return _("Use arrows or pgUp/pgDown keys to scroll the text by lines or pages.");
-  }
-  else if (endfour == "more")
-  {
-    return _("Use the Enter or Space key to scroll the text by lines or pages.");
-  }
-  return string();
-}
-
-//gets true if successfully display in pager
-bool show_in_pager(const string& text)
-{
-  const char* envpager = getenv("PAGER");
-  if (!envpager)
-    envpager="more"; //basic posix default, must be in PATH
-  string pager(envpager);
-  filesystem::TmpFile tfile;
-  string tpath = tfile.path().absolutename().c_str();
-  ofstream os(tpath.c_str());
-
-  string help = pager_help_navigation(pager);
-  if (!help.empty())
-    os << "(" << help << ")" << endl << endl;
-  os << text;
-
-  help = pager_help_exit(pager);
-  if (!help.empty())
-    os << endl << endl << "(" << help << ")";
-  os.close();
-
-  ostringstream cmdline;
-  cmdline << pager <<" "<<tpath;
-
-  switch(fork())
-  {
-  case -1:
-    WAR << "fork failed" << endl;
-    return false;
-
-  case 0:
-    execlp("sh","sh","-c",cmdline.str().c_str(),(char *)0);
-    WAR << "exec failed with " << strerror(errno) << endl;
-    exit(1); // cannot return false here, because here is another process
-             // so only kill myself
-             //! \todo FIXME proper exit code, message?
-
-  default: 
-    wait(0); //wait until pager end to disallow possibly terminal collision
-  }
-
-  return true;
-}
-
-// this does only resolvables with this _name_.
-// we could also act on _provides_
-// TODO edition, arch
-static void mark_for_install(Zypper & zypper,
-                      const ResObject::Kind &kind,
-                     const std::string &name,
-                     const std::string & repo = "")
-{
-  // name and kind match:
-  ProvideProcess installer (ZConfig::instance().systemArchitecture(), repo);
-  DBG << "Iterating over [" << kind << "]" << name << endl;
-  invokeOnEach(
-      God->pool().byIdentBegin(kind, name),
-      God->pool().byIdentEnd(kind, name),
-      zypp::functor::functorRef<bool,const zypp::PoolItem&> (installer));
-
-  DBG << "... done" << endl;
-  if (!installer.item)
-  {
-    zypper.out().error(
-      // translators: meaning a package %s or provider of capability %s
-      str::form(_("'%s' not found"), name.c_str()));
-    WAR << str::form("'%s' not found", name.c_str()) << endl;
-    zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
-    return;
-  }
-
-  if (installer.installed_item &&
-      installer.installed_item.resolvable()->edition() == installer.item.resolvable()->edition() &&
-      installer.installed_item.resolvable()->arch() == installer.item.resolvable()->arch() &&
-      ( ! copts.count("force") ) )
-  {
-    // if it is broken install anyway, even if it is installed
-    if ( installer.item.isBroken() )
-    {
-      installer.item.status().setTransact( true, zypp::ResStatus::USER );
-    }
-
-    zypper.out().info(boost::str(format(
-      // translators: e.g. skipping package 'zypper' (the newest version already installed)  
-      _("skipping %s '%s' (the newest version already installed)"))
-      % kind_to_string_localized(kind,1) % name));
-  }
-  else {
-
-    //! \todo don't use setToBeInstalled for this purpose but higher level solver API
-    bool result = installer.item.status().setToBeInstalled( zypp::ResStatus::USER );
-    if (!result)
-    {
-      // this is because the resolvable is installed and we are forcing.
-      installer.item.status().setTransact( true, zypp::ResStatus::USER );
-      if (!copts.count("force"))
-      {
-        zypper.out().error(boost::str(
-          format(_("Failed to add '%s' to the list of packages to be installed."))
-          % name));
-        ERR << "Could not set " << name << " as to-be-installed" << endl;
-      }
-    }
-  }
-}
-
-struct DeleteProcess
-{
-  bool found;
-  DeleteProcess ()
-    : found(false)
-  { }
-
-  bool operator() ( const PoolItem& provider )
-  {
-    found = true;
-    DBG << "Marking for deletion: " << provider << endl;
-    bool result = provider.status().setToBeUninstalled( zypp::ResStatus::USER );
-    if (!result) {
-      Zypper::instance()->out().error(boost::str(format(
-          _("Failed to add '%s' to the list of packages to be removed."))
-          % provider.resolvable()->name()));
-      ERR << "Could not set " << provider.resolvable()->name()
-          << " as to-be-uninstalled" << endl;
-    }
-    return true;               // get all of them
-  }
-};
-
-// mark all matches
-static void mark_for_uninstall(Zypper & zypper,
-                        const ResObject::Kind &kind,
-                       const std::string &name)
-{
-  const ResPool &pool = God->pool();
-  // name and kind match:
-
-  DeleteProcess deleter;
-  DBG << "Iterating over " << name << endl;
-  invokeOnEach( pool.byIdentBegin( kind, name ),
-               pool.byIdentEnd( kind, name ),
-               resfilter::ByInstalled(),
-               zypp::functor::functorRef<bool,const zypp::PoolItem&> (deleter)
-               );
-  DBG << "... done" << endl;
-  if (!deleter.found) {
-    zypper.out().error(
-      // translators: meaning a package %s or provider of capability %s
-      str::form(_("'%s' not found"), name.c_str()));
-    WAR << str::form("'%s' not found", name.c_str()) << endl;
-    zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
-    return;
-  }
-}
-
-
-static void
-mark_by_name (Zypper & zypper,
-              bool install_not_remove,
-              const ResObject::Kind &kind,
-              const string &name,
-              const string & repo = "")
-{
-  if (install_not_remove)
-    mark_for_install(zypper, kind, name, repo);
-  else
-    mark_for_uninstall(zypper, kind, name);
-}
-
-
-// don't try NAME-EDITION yet, could be confused by
-// dbus-1-x11, java-1_4_2-gcj-compat, ...
-/*
-bool mark_by_name_edition (...)
-  static const regex rx_name_edition("(.*?)-([0-9].*)");
-
-  smatch m;
-  if (! is_cap && regex_match (capstr, m, rx_name_edition)) {
-    capstr = m.str(1) + " = " + m.str(2);
-    is_cap = true;
-  }
-*/
-
-static void
-mark_by_capability (Zypper & zypper,
-                    bool install_not_remove,
-                    const ResKind & kind,
-                    const Capability & cap)
-{
-  if (!cap.empty()) {
-    DBG << "Capability: " << cap << endl;
-
-    Resolver_Ptr resolver = zypp::getZYpp()->resolver();
-    if (install_not_remove) {
-      DBG << "Adding requirement " << cap << endl;
-      resolver->addRequire (cap);
-    }
-    else {
-      DBG << "Adding conflict " << cap << endl;
-      resolver->addConflict (cap);
-    }
-  }
-}
-
-// ----------------------------------------------------------------------------
-
-// join arguments at comparison operators ('=', '>=', and the like)
-static void
-install_remove_preprocess_args(const Zypper::ArgList & args,
-                               Zypper::ArgList & argsnew)
-{
-  Zypper::ArgList::size_type argc = args.size();
-  argsnew.reserve(argc);
-  string tmp;
-  // preprocess the arguments
-  for(Zypper::ArgList::size_type i = 0, lastnew = 0; i < argc; ++i)
-  {
-    tmp = args[i];
-    if (i
-        && (tmp == "=" || tmp == "==" || tmp == "<"
-            || tmp == ">" || tmp == "<=" || tmp == ">=")
-        && i < argc - 1)
-    {
-      argsnew[lastnew-1] += tmp + args[++i];
-      continue;
-    }
-    else if (tmp.find_last_of("=<>") == tmp.size() - 1 && i < argc - 1)
-    {
-      argsnew.push_back(tmp + args[++i]);
-      ++lastnew;
-    }
-    else if (i && tmp.find_first_of("=<>") == 0)
-    {
-      argsnew[lastnew-1] += tmp;
-      ++i;
-    }
-    else
-    {
-      argsnew.push_back(tmp);
-      ++lastnew;
-    }
-  }
-
-  DBG << "old: ";
-  copy(args.begin(), args.end(), ostream_iterator<string>(DBG, " "));
-  DBG << endl << "new: ";
-  copy(argsnew.begin(), argsnew.end(), ostream_iterator<string>(DBG, " "));
-  DBG << endl;
-}
-
-static void
-mark_selectable(Zypper & zypper,
-                ui::Selectable & s,
-                bool install_not_remove,
-                bool force,
-                const string & repo = "",
-                const string & arch = "")
-{
-  PoolItem theone = s.theObj();
-  //! \todo handle multiple installed case
-  bool theoneinstalled; // is the One installed ?
-  if (s.kind() == ResKind::package)
-    theoneinstalled = !s.installedEmpty() && theone &&
-      equalNVRA(*s.installedObj().resolvable(), *theone.resolvable());
-  else if (s.kind() == ResKind::patch)
-    theoneinstalled = theone.isRelevant() && theone.isSatisfied();
-  else
-    theoneinstalled = theone.isSatisfied();
-
-  bool anyinstalled = theoneinstalled;
-  PoolItem installed;
-  if (theoneinstalled)
-    installed = theone;
-  else
-  {
-    if (s.kind() == ResKind::package)
-    {
-      anyinstalled = s.hasInstalledObj();
-      installed = s.installedObj();
-    }
-    else if (s.kind() == ResKind::patch)
-    {
-      for_(it, s.availableBegin(), s.availableEnd())
-      {
-        if (it->isRelevant() && it->isSatisfied())
-        {
-          if (installed)
-          {
-            if (it->resolvable()->edition() > installed->edition())
-              installed = *it;
-          }
-          else
-          {
-            installed = *it;
-            anyinstalled = true;
-          }
-        }
-      }
-    }
-    else
-    {
-      for_(it, s.availableBegin(), s.availableEnd())
-      {
-        if (it->status().isSatisfied())
-        {
-          if (installed)
-          {
-            if (it->resolvable()->edition() > installed->edition())
-              installed = *it;
-          }
-          else
-          {
-            installed = *it;
-            anyinstalled = true;
-          }
-        }
-      }
-    }
-  }
-
-  if (install_not_remove)
-  {
-    if (theoneinstalled && !force)
-    {
-      DBG << "the One (" << theone << ") is installed, skipping." << endl;
-      zypper.out().info(str::form(
-          _("'%s' is already installed."), s.name().c_str()));
-      return;
-    }
-
-    if (theoneinstalled && force)
-    {
-      s.setStatus(ui::S_Install);
-      DBG << s << " install: forcing reinstall" << endl;
-    }
-    else
-    {
-      Capability c;
-
-      // require version greater than the installed. The solver should pick up
-      // the latest installable in this case, which is what we want for all
-      // kinds (and for patches having the latest installed should automatically
-      // satisfy all older version, or make them irrelevant)
-
-      //! could be a problem for patches if there would a greater version
-      //! of a patch appear that would be irrelevant at the same time. Should
-      //! happen probably.
-      if (anyinstalled)
-        c = Capability(s.name(), Rel::GT, installed->edition(), s.kind());
-      // require any version
-      else
-        c = Capability(s.name(), s.kind());
-
-      God->resolver()->addRequire(c);
-      DBG << s << " install: adding requirement " << c << endl;
-    }
-  }
-  // removing is simpler, as usually
-  //! \todo but not that simple - simply adding a conflict with a pattern
-  //! or patch does not make the packages it requires to be removed.
-  //! we still need to define what response of zypper -t foo bar should be for PPP
-  else
-  {
-    if (!anyinstalled)
-    {
-      zypper.out().info(str::form(
-          _("'%s' is not installed."), s.name().c_str()));
-      DBG << s << " remove: not installed, skipping." << endl;
-      return;
-    }
-
-    Capability c(s.name(), s.kind());
-    God->resolver()->addConflict(c);
-    DBG << s << " remove: adding conflict " << c << endl;
-  }
-}
-
-// ----------------------------------------------------------------------------
-
-void install_remove(Zypper & zypper,
-                    const Zypper::ArgList & args,
-                    bool install_not_remove,
-                    const ResKind & kind)
-{
-  if (args.empty())
-    return;
-  
-  bool force_by_capability = zypper.cOpts().count("capability");
-  bool force_by_name = zypper.cOpts().count("name");
-  bool force = zypper.cOpts().count("force");
-  if (force)
-    force_by_name = true;
-
-  if (force_by_capability && force_by_name)
-  {
-    zypper.out().error(boost::str(
-      format(_("%s contradicts %s")) % "--capability" % (force? "--force" : "--name")));
-    
-    zypper.setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
-    ZYPP_THROW(ExitRequestException());
-  }
-
-  if (install_not_remove && force_by_capability && force)
-  {
-    // translators: meaning --force with --capability
-    zypper.out().error(boost::str(format(_("%s cannot currently be used with %s"))
-      % "--force" % "--capability"));
-    zypper.setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
-    ZYPP_THROW(ExitRequestException());
-  }
-
-  Zypper::ArgList argsnew;
-  install_remove_preprocess_args(args, argsnew);
-
-  string str, arch, repo;
-  bool by_capability;
-  const ResPool & pool = God->pool();
-  for_(it, argsnew.begin(), argsnew.end())
-  {
-    str = *it; arch.clear(); repo.clear();
-    by_capability = false;
-
-    // install remove modifiers
-    if (str[0] == '+' || str[0] == '~')
-    {
-      install_not_remove = true;
-      str.erase(0, 1);
-    }
-    else if (str[0] == '-' || str[0] == '!')
-    {
-      install_not_remove = false;
-      str.erase(0, 1);
-    }
-
-    string::size_type pos;
-
-    if ((pos = str.rfind(':')) != string::npos)
-    {
-      repo = str.substr(0, pos);
-      str = str.substr(pos + 1);
-      force_by_name = true; // until there is a solver API for this
-    }
-
-    //! \todo force arch with '.' or '@'???
-    if ((pos = str.find('.')) != string::npos)
-    { }
-
-    // mark by name by force
-    if (force_by_name)
-    {
-      mark_by_name (zypper, install_not_remove, kind, str, repo);
-      continue;
-    }
-
-    // recognize missplaced command line options given as packages
-    // bnc#391644
-    if ( str[0] == '-' )
-    {
-      // FIXME show a message here, after string freeze
-      //zypper.out().error(boost::str(format(_("%s is not a valid package or capability name.") % str));
-      zypper.out().error(_("No valid arguments specified."));
-      zypper.setExitCode(ZYPPER_EXIT_ERR_INVALID_ARGS);
-      ZYPP_THROW(ExitRequestException());
-    }
-    
-
-    // is version specified?
-    by_capability = str.find_first_of("=<>") != string::npos;
-
-    // try to find foo-bar-1.2.3-2
-    if (!by_capability && str.find('-') != string::npos)
-    {
-      // try to find the original string first as name
-      // search by name, not in whatprovides, since there can be provider even
-      // for cracklib-dict=small
-      // continue only if nothing has been found this way
-      if (pool.byIdentBegin(kind, str) == pool.byIdentEnd(kind, str))
-      {
-        // try to replace '-' for '=' from right to the left and check
-        // whether there is something providing such capability
-        string::size_type pos = string::npos;
-        while ((pos = str.rfind('-', pos)) != string::npos)
-        {
-          string trythis = str;
-          trythis.replace(pos, 1, 1, '=');
-          string tryver = str.substr(pos + 1, str.size() - 1);
-
-          DBG << "trying: " << trythis << " edition: " << tryver << endl;
-
-          Capability cap = safe_parse_cap (zypper, trythis, kind);
-          sat::WhatProvides q(cap);
-          for_(sit, q.begin(), q.end())
-          {
-            if (sit->edition().match(tryver) == 0)
-            {
-              str = trythis;
-              by_capability = true;
-              DBG << str << "might be what we wanted" << endl;
-              break;
-            }
-          }
-          if (by_capability)
-            break;
-          --pos;
-        }
-      }
-    }
-
-    // try to find by name + wildcards first
-    if (!by_capability)
-    {
-      PoolQuery q;
-      q.addKind(kind);
-      q.addAttribute(sat::SolvAttr::name, str);
-      q.setMatchGlob();
-      bool found = false;
-      for_(s, q.selectableBegin(), q.selectableEnd())
-      {
-        mark_selectable(zypper, **s, install_not_remove, force);
-        found = true;
-      }
-      // done with this requirement, skip to next argument
-      if (found)
-        continue;
-    }
-
-    // try by capability
-
-    Capability cap = safe_parse_cap (zypper, str, kind);
-    sat::WhatProvides q(cap);
-
-    // is there a provider for the requested capability?
-    if (q.empty())
-    {
-      // translators: meaning a package %s or provider of capability %s
-      zypper.out().error(str::form(_("'%s' not found."), str.c_str()));
-      WAR << str::form("'%s' not found", str.c_str()) << endl;
-      zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
-      continue;
-    }
-
-    // is the provider already installed?
-    bool installed = false;
-    string provider; 
-    for_(solvit, q.poolItemBegin(), q.poolItemEnd())
-    {
-      if (solvit->resolvable()->isKind(ResKind::package))
-        installed = solvit->status().isInstalled();
-      else
-        installed = solvit->isSatisfied();
-      if (installed)
-      {
-        provider = solvit->resolvable()->name(); 
-        break;
-      }
-    }
-    // already installed, nothing to do
-    if (installed && install_not_remove)
-    {
-      if (provider == str)
-        zypper.out().info(str::form(
-            _("'%s' is already installed."), str.c_str()));
-      else
-        zypper.out().info(str::form(
-            // translators: %s are package names
-            _("'%s' providing '%s' is already installed."),
-            provider.c_str(), str.c_str()));
-
-      MIL << str::form("skipping '%s': already installed", str.c_str()) << endl;
-      continue;
-    }
-    // not installed, nothing to do
-    else if (!installed && !install_not_remove)
-    {
-      // translators: meaning a package %s or provider of capability %s
-      zypper.out().info(str::form(_("'%s' is not installed."), str.c_str()));
-      MIL << str::form("skipping '%s': not installed", str.c_str()) << endl;
-      continue;
-    }
-
-    mark_by_capability (zypper, install_not_remove, kind, cap);
-  }
-}
-
 // ----------------------------------------------------------------------------
 
 void remove_selections(Zypper & zypper)
@@ -803,1820 +118,12 @@ ostream& operator << (ostream & stm, ios::iostate state)
 }
 */
 
-//! @return true to retry solving now, false to cancel, indeterminate to continue
-static tribool show_problem (Zypper & zypper,
-                      const ResolverProblem & prob,
-                      ProblemSolutionList & todo)
-{
-  ostringstream desc_stm;
-  string tmp;
-  // translators: meaning 'dependency problem' found during solving
-  desc_stm << _("Problem: ") << prob.description () << endl;
-  tmp = prob.details ();
-  if (!tmp.empty ())
-    desc_stm << "  " << tmp << endl;
-
-  int n;
-  ProblemSolutionList solutions = prob.solutions ();
-  ProblemSolutionList::iterator
-    bb = solutions.begin (),
-    ee = solutions.end (),
-    ii;
-  for (n = 1, ii = bb; ii != ee; ++n, ++ii) {
-    // TranslatorExplanation %d is the solution number
-    desc_stm << format (_(" Solution %d: ")) % n << (*ii)->description () << endl;
-    tmp = (*ii)->details ();
-    if (!tmp.empty ())
-      desc_stm << indent(tmp, 2) << endl;
-  }
-
-  unsigned int problem_count = God->resolver()->problems().size();
-  unsigned int solution_count = solutions.size(); 
-
-  // without solutions, its useless to prompt
-  if (solutions.empty())
-  {
-    zypper.out().error(desc_stm.str());
-    return false;
-  }
-
-  string prompt_text;
-  if (problem_count > 1)
-    prompt_text = _PL(
-      "Choose the above solution using '1' or skip, retry or cancel",
-      "Choose from above solutions by number or skip, retry or cancel",
-      solution_count);
-  else
-    prompt_text = _PL(
-      // translators: translate 'c' to whatever you translated the 'c' in
-      // "c" and "s/r/c" strings
-      "Choose the above solution using '1' or cancel using 'c'",
-      "Choose from above solutions by number or cancel",
-      solution_count);
-
-  PromptOptions popts;
-  unsigned int default_reply;
-  ostringstream numbers;
-  for (unsigned int i = 1; i <= solution_count; i++)
-    numbers << i << "/";
-
-  if (problem_count > 1)
-  {
-    default_reply = solution_count + 2;
-    // translators: answers for dependency problem solution input prompt:
-    // "Choose from above solutions by number or skip, retry or cancel"
-    // Translate the letters to whatever is suitable for your language.
-    // The anserws must be separated by slash characters '/' and must
-    // correspond to skip/retry/cancel in that order.
-    // The answers should be lower case letters.
-    popts.setOptions(numbers.str() + _("s/r/c"), default_reply);
-  }
-  else
-  {
-    default_reply = solution_count;
-    // translators: answers for dependency problem solution input prompt:
-    // "Choose from above solutions by number or cancel"
-    // Translate the letter 'c' to whatever is suitable for your language
-    // and to the same as you translated it in the "s/r/c" string
-    // See the "s/r/c" comment for other details.
-    // One letter string  for translation can be tricky, so in case of problems,
-    // please report a bug against zypper at bugzilla.novell.com, we'll try to solve it.
-    popts.setOptions(numbers.str() + _("c"), default_reply);
-  }
-
-  zypper.out().prompt(PROMPT_DEP_RESOLVE, prompt_text, popts, desc_stm.str());
-  unsigned int reply =
-    get_prompt_reply(zypper, PROMPT_DEP_RESOLVE, popts);
-
-  // retry
-  if (problem_count > 1 && reply == solution_count + 1)
-    return true;
-  // cancel (one problem)
-  if (problem_count == 1 && reply == solution_count)
-    return false;
-  // cancel (more problems)
-  if (problem_count > 1 && reply == solution_count + 2)
-    return false;
-  // skip
-  if (problem_count > 1 && reply == solution_count)
-    return indeterminate; // continue with next problem
-
-  zypper.out().info(boost::str(format (_("Applying solution %s")) % (reply + 1)), Out::HIGH);
-  ProblemSolutionList::iterator reply_i = solutions.begin ();
-  advance (reply_i, reply);
-  todo.push_back (*reply_i);
-
-  tribool go_on = indeterminate; // continue with next problem
-  return go_on;
-}
-
-// return true to retry solving, false to cancel transaction
-static bool show_problems(Zypper & zypper)
-{
-  bool retry = true;
-  Resolver_Ptr resolver = zypp::getZYpp()->resolver();
-  ResolverProblemList rproblems = resolver->problems ();
-  ResolverProblemList::iterator
-    b = rproblems.begin (),
-    e = rproblems.end (),
-    i;
-  ProblemSolutionList todo;
-
-  // display the number of problems
-  if (rproblems.size() > 1)
-    zypper.out().info(boost::str(format(
-      _PL("%d Problem:", "%d Problems:", rproblems.size())) % rproblems.size()));
-  else if (rproblems.empty())
-  {
-    // should not happen! If solve() failed at least one problem must be set!
-    zypper.out().error(_("Specified capability not found"));
-    zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
-    return false;
-  }
-
-  // for many problems, list them shortly first
-  //! \todo handle resolver problems caused by --capability mode arguments specially to give proper output (bnc #337007)
-  if (rproblems.size() > 1)
-  {
-    for (i = b; i != e; ++i)
-      zypper.out().info(boost::str(
-        format(_("Problem: %s")) % (*i)->description()));
-  }
-  // now list all problems with solution proposals
-  for (i = b; i != e; ++i)
-  {
-    zypper.out().info("", Out::NORMAL, Out::TYPE_NORMAL); // visual separator
-    tribool stopnow = show_problem(zypper, *(*i), todo);
-    if (! indeterminate (stopnow)) {
-      retry = stopnow == true;
-      break;
-    }
-  }
-
-  if (retry)
-  {
-    zypper.out().info(_("Resolving dependencies..."));
-    resolver->applySolutions (todo);
-  }
-  return retry;
-}
-
-typedef map<Resolvable::Kind,set<ResObject::constPtr> > 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 (set<ResObject::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
-} 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;
-  }
-}
-
-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 (set<ResObject::constPtr>::const_iterator resit = it->second.begin();
-          resit != it->second.end(); ++resit)
-      {
-        ResObject::constPtr res(*resit);
-
-        cout << "<solvable";
-        cout << " type=\"" << it->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;
-    }
-
-    show_summary_resolvable_list(title, it, zypper.out());
-  }
-}
-
-enum
-{
-  SUMMARY_OK = 0,
-  SUMMARY_NOTHING_TO_DO,
-  SUMMARY_INSTALL_DOES_REMOVE,
-  SUMMARY_REMOVE_DOES_INSTALL
-};
-
-/**
- * sets zypper exit code to:
- *  ZYPPER_EXIT_INF_REBOOT_NEEDED - if one of patches to be installed needs machine reboot,
- *  ZYPPER_EXIT_INF_RESTART_NEEDED - if one of patches to be installed needs package manager restart
- * 
- * @return SUMMARY_*
- */
-static int summary(Zypper & zypper)
-{
-  int retv = SUMMARY_NOTHING_TO_DO;
-
-  MIL << "Pool contains " << God->pool().size() << " items." << std::endl;
-  DBG << "Install summary:" << endl;
-
-
-  KindToResObjectSet to_be_installed;
-  KindToResObjectSet to_be_removed;
-
-  // 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() == ResTraits<Patch>::kind)
-      {
-        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);
-      }
-
-      if ( it->status().isToBeInstalled()
-          && it->resolvable()->kind() != ResTraits<Atom>::kind )
-      {
-        DBG << "<install>   ";
-        to_be_installed[it->resolvable()->kind()].insert(it->resolvable());
-      }
-      if ( it->status().isToBeUninstalled()
-          && it->resolvable()->kind() != ResTraits<Atom>::kind )
-      {
-        DBG << "<uninstall> ";
-        to_be_removed[it->resolvable()->kind()].insert(it->resolvable());
-      }
-      DBG << *res << endl;
-    }
-  }
-
-  if (!to_be_removed.empty() || !to_be_installed.empty())
-    retv = SUMMARY_OK;
-
-  if (retv == SUMMARY_NOTHING_TO_DO && zypper.runtimeData().srcpkgs_to_install.empty())
-  {
-    if (zypper.command() == ZypperCommand::VERIFY)
-      zypper.out().info(_("Dependencies of all installed packages are satisfied."));
-    else
-      zypper.out().info(_("Nothing to do."));
-    return retv;
-  }
-
-  if (zypper.command() == ZypperCommand::VERIFY)
-    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();
-  zypper.runtimeData().commit_pkg_current = 0;
-
-  KindToResObjectSet toinstall;
-  KindToResObjectSet toupgrade;
-  KindToResObjectSet todowngrade;
-  KindToResObjectSet toreinstall;
-  KindToResObjectSet toremove;
-  KindToResObjectSet tochangearch;
-  KindToResObjectSet tochangevendor;
-
-  // 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 (set<ResObject::constPtr>::const_iterator resit = it->second.begin();
-        resit != it->second.end(); ++resit)
-    {
-      ResObject::constPtr res(*resit);
-
-      // find in to_be_removed:
-      bool upgrade_downgrade = false;
-      for (set<ResObject::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 (set<ResObject::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 (list<SrcPackage::constPtr>::const_iterator it = zypper.runtimeData().srcpkgs_to_install.begin();
-      it != zypper.runtimeData().srcpkgs_to_install.end(); ++it)
-    toinstall[ResTraits<SrcPackage>::kind].insert(*it);
-
-  if (!toremove.empty() && (
-      zypper.command() == ZypperCommand::INSTALL ||
-      zypper.command() == ZypperCommand::UPDATE))
-    retv = SUMMARY_INSTALL_DOES_REMOVE;
-  else if ((!toinstall.empty() || toremove_by_solver)
-      && zypper.command() == ZypperCommand::REMOVE)
-    retv = SUMMARY_REMOVE_DOES_INSTALL;
-
-  // "</install-summary>"
-  if (zypper.out().type() == Out::TYPE_XML)
-  {
-    cout << "<install-summary";
-    cout << " download-size=\"" << ((ByteCount::SizeType) download_size) << "\"";
-    cout << " space-usage-diff=\"" << ((ByteCount::SizeType) new_installed_size) << "\"";
-    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);
-
-  // "</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.");
-  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());
-
-  return retv;
-}
-
-/*
-std::string calculate_token()
-{
-  SourceManager_Ptr manager;
-  manager = SourceManager::sourceManager();
-
-  std::string token;
-  stringstream token_stream;
-  for ( std::list<Source_Ref>::iterator it = gData.sources.begin(); it !=  gData.sources.end(); ++it )
-  {
-    Source_Ref src = *it;
-
-//     if ( gSettings.disable_system_sources == SourcesFromSystem )
-//     {
-//       if ( gSettings.output_type == OutputTypeNice )
-//         cout << "Refreshing source " <<  src.alias() << endl;
-//       src.refresh();
-//     }
-
-    token_stream << "[" << src.alias() << "| " << src.url() << src.timestamp() << "]";
-    MIL << "Source: " << src.alias() << " from " << src.timestamp() << std::endl;
-  }
-
-  token_stream << "[" << "target" << "| " << God->target()->timestamp() << "]";
-
-  //static std::string digest(const std::string& name, std::istream& is
-  token = Digest::digest("sha1", token_stream);
-
-  //if ( gSettings.output_type == OutputTypeSimple )
-  //  cout << token;
-
-  MIL << "new token [" << token << "]" << " previous: [" << gSettings.previous_token << "] previous code: " << gSettings.previous_code << std::endl;
-
-  return token;
-}
-*/
-
-static void dump_pool ()
-{
-  int count = 1;
-  static bool full_pool_shown = false;
-
-  _XDEBUG( "---------------------------------------" );
-  for (ResPool::const_iterator it =   God->pool().begin(); it != God->pool().end(); ++it, ++count) {
-
-    if (!full_pool_shown                                    // show item if not shown all before
-        || it->status().transacts()                         // or transacts
-        || !it->isBroken())                                 // or broken status
-    {
-      _XDEBUG( count << ": " << *it );
-    }
-  }
-  _XDEBUG( "---------------------------------------" );
-  full_pool_shown = true;
-}
-
-
-static void set_force_resolution(Zypper & zypper)
-{
-  // --force-resolution command line parameter value
-  TriBool force_resolution = zypper.runtimeData().force_resolution;
-
-  if (zypper.cOpts().count("force-resolution"))
-    force_resolution = true;
-  if (zypper.cOpts().count("no-force-resolution"))
-  {
-    if (force_resolution)
-      zypper.out().warning(str::form(
-        // translators: meaning --force-resolution and --no-force-resolution
-        _("%s conflicts with %s, will use the less aggressive %s"),
-          "--force-resolution", "--no-force-resolution", "--no-force-resolution"));
-    force_resolution = false;
-  }
-
-  // if --force-resolution was not specified on the command line, force
-  // the resolution by default for the install and remove commands and the
-  // rug_compatible mode. Don't force resolution in non-interactive mode
-  // and for update and dist-upgrade command (complex solver request).
-  // bnc #369980
-  if (indeterminate(force_resolution))
-  {
-    if (!zypper.globalOpts().non_interactive &&
-        (zypper.globalOpts().is_rug_compatible ||
-         zypper.command() == ZypperCommand::INSTALL ||
-         zypper.command() == ZypperCommand::REMOVE))
-      force_resolution = true;
-    else
-      force_resolution = false;
-  }
-
-  // save the setting
-  zypper.runtimeData().force_resolution = force_resolution; 
-
-  DBG << "force resolution: " << force_resolution << endl;
-  ostringstream s;
-  s << _("Force resolution:") << " " << (force_resolution ? _("Yes") : _("No"));
-  zypper.out().info(s.str(), Out::HIGH);
-
-  God->resolver()->setForceResolve(force_resolution);
-}
-
-static void set_no_recommends(Zypper & zypper)
-{
-  bool no_recommends = false;
-  if (zypper.command() == ZypperCommand::REMOVE)
-    // never install recommends when removing packages
-    no_recommends = true;
-  else
-    // install also recommended packages unless --no-recommends is specified
-    no_recommends = zypper.cOpts().count("no-recommends");
-  DBG << "no recommends (only requires): " << no_recommends << endl;
-  God->resolver()->setOnlyRequires(no_recommends);
-}
-
-
-static void set_ignore_recommends_of_installed(Zypper & zypper)
-{
-  bool ignore = true;
-  if (zypper.command() == ZypperCommand::DIST_UPGRADE ||
-      zypper.command() == ZypperCommand::INSTALL_NEW_RECOMMENDS)
-    ignore = false;
-  DBG << "ignore recommends of already installed packages: " << ignore << endl;
-  God->resolver()->setIgnoreAlreadyRecommended(ignore);
-}
-
-
-/**
- * Run the solver.
- * 
- * \return <tt>true</tt> if a solution has been found, <tt>false</tt> otherwise 
- */
-bool resolve(Zypper & zypper)
-{
-  dump_pool(); // debug
-  set_force_resolution(zypper);
-  set_no_recommends(zypper);
-  set_ignore_recommends_of_installed(zypper);
-  zypper.out().info(_("Resolving dependencies..."), Out::HIGH);
-  DBG << "Calling the solver..." << endl;
-  return God->resolver()->resolvePool();
-}
-
-static bool verify(Zypper & zypper)
-{
-  dump_pool();
-  zypper.out().info(_("Verifying dependencies..."), Out::HIGH);
-  // don't force aggressive solutions
-  God->resolver()->setForceResolve(false); //! \todo move to set_force_resolution()
-  set_no_recommends(zypper);
-  set_ignore_recommends_of_installed(zypper);
-  DBG << "Calling the solver to verify system..." << endl;
-  return God->resolver()->verifySystem();
-}
-
-static void make_solver_test_case(Zypper & zypper)
-{
-  set_force_resolution(zypper);
-  set_no_recommends(zypper);
-  set_ignore_recommends_of_installed(zypper);
-
-  string testcase_dir("/var/log/zypper.solverTestCase");
-
-  zypper.out().info(_("Generating solver test case..."));
-  if (God->resolver()->createSolverTestcase(testcase_dir))
-    zypper.out().info(boost::str(
-      format(_("Solver test case generated successfully at %s."))
-        % testcase_dir));
-  else
-  {
-    zypper.out().error(_("Error creating the solver test case."));
-    zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
-  }
-}
-
-// ----------------------------------------------------------------------------
-//
-// Updates
-//
-// The following scenarios are handled distinctly:
-// * -t patch (default), no arguments
-// * -t package, no arguments
-//   - uses Resolver::doUpdate()
-// * -t {other}, no arguments
-// * -t patch foo
-// * -t package foo
-//   - addRequires(>installed-version) if available
-// * -t {other} foo
-//   - addRequires(>installed-version) if available
-//
-// update summary must correspond to list-updates and patch-check
-// ----------------------------------------------------------------------------
-
-void patch_check ()
-{
-  Out & out = Zypper::instance()->out();
-
-  DBG << "patch check" << endl;
-  gData.patches_count = gData.security_patches_count = 0;
-
-  ResPool::byKind_iterator
-    it = God->pool().byKindBegin(ResKind::patch),
-    e = God->pool().byKindEnd(ResKind::patch);
-  for (; it != e; ++it )
-  {
-    ResObject::constPtr res = it->resolvable();
-    Patch::constPtr patch = asKind<Patch>(res);
-
-    if (it->isRelevant() && !it->isSatisfied())
-    {
-      gData.patches_count++;
-      if (patch->category() == "security")
-        gData.security_patches_count++;
-    }
-  }
-
-  ostringstream s;
-  // translators: %d is the number of needed patches
-  s << format(_PL("%d patch needed", "%d patches needed", gData.patches_count))
-      % gData.patches_count
-    << " ("
-    // translators: %d is the number of security patches
-    << format(_PL("%d security patch", "%d security patches", gData.security_patches_count))
-      % gData.security_patches_count
-    << ")";
-  out.info(s.str(), Out::QUIET);
-}
-
-// ----------------------------------------------------------------------------
-
-// returns true if restartSuggested() patches are availble
-bool xml_list_patches ()
-{
-  const zypp::ResPool& pool = God->pool();
-
-  unsigned int patchcount=0;
-  bool pkg_mgr_available = false;
-  Patch::constPtr patch;
-
-  ResPool::byKind_iterator
-    it = pool.byKindBegin(ResKind::patch),
-    e  = pool.byKindEnd(ResKind::patch);
-
-  // check whether there are packages affecting the update stack
-  for (; it != e; ++it)
-  {
-    patch = asKind<Patch>(it->resolvable());
-    if (it->isRelevant() && !it->isSatisfied() && patch->restartSuggested())
-    {
-      pkg_mgr_available = true;
-      break;
-    }
-  }
-
-  it = pool.byKindBegin(ResKind::patch);
-  for (; it != e; ++it, ++patchcount)
-  {
-    if (it->isRelevant() && !it->isSatisfied())
-    {
-      ResObject::constPtr res = it->resolvable();
-      Patch::constPtr patch = asKind<Patch>(res);
-
-      // if updates stack patches are available, show only those
-      if ((pkg_mgr_available && patch->restartSuggested()) || !pkg_mgr_available)
-      {
-        cout << " <update ";
-        cout << "name=\"" << res->name () << "\" ";
-        cout << "edition=\""  << res->edition ().asString() << "\" ";
-        cout << "category=\"" <<  patch->category() << "\" ";
-        cout << "pkgmanager=\"" << (patch->restartSuggested() ? "true" : "false") << "\" ";
-        cout << "restart=\"" << (patch->rebootSuggested() ? "true" : "false") << "\" ";
-        cout << "interactive=\"" << (patch->interactive() ? "true" : "false") << "\" ";
-        cout << "kind=\"patch\"";
-        cout << ">" << endl;
-        cout << "  <summary>" << xml_encode(patch->summary()) << "  </summary>" << endl;
-        cout << "  <description>" << xml_encode(patch->description()) << "</description>" << endl;
-        cout << "  <license>" << xml_encode(patch->licenseToConfirm()) << "</license>" << endl;
-
-        if ( !patch->repoInfo().alias().empty() )
-        {
-          cout << "  <source url=\"" << xml_encode(patch->repoInfo().baseUrlsBegin()->asString());
-          cout << "\" alias=\"" << xml_encode(patch->repoInfo().alias()) << "\"/>" << endl;
-        }
-
-        cout << " </update>" << endl;
-      }
-    }
-  }
-
-  if (patchcount == 0)
-    cout << "<appletinfo status=\"no-update-repositories\"/>" << endl;
-
-  return pkg_mgr_available;
-}
-
-// ----------------------------------------------------------------------------
-
-static void list_patch_updates(Zypper & zypper)
-{
-  Table tbl;
-  Table pm_tbl;        // only those that affect packagemanager (restartSuggested()), they have priority
-  TableHeader th;
-  unsigned cols;
-
-  th << (zypper.globalOpts().is_rug_compatible ? _("Catalog") : _("Repository"))
-     << _("Name") << _("Version") << _("Category") << _("Status");
-  cols = 5;
-  tbl << th;
-  pm_tbl << th;
-
-  const zypp::ResPool& pool = God->pool();
-  ResPool::byKind_iterator
-    it = pool.byKindBegin(ResKind::patch),
-    e  = pool.byKindEnd(ResKind::patch);
-  for (; it != e; ++it )
-  {
-    ResObject::constPtr res = it->resolvable();
-
-    if ( it->isRelevant() && ! it->isSatisfied() )
-    {
-      Patch::constPtr patch = asKind<Patch>(res);
-
-      {
-        TableRow tr (cols);
-        tr << patch->repoInfo().name();
-        tr << res->name () << res->edition ().asString();
-        tr << patch->category();
-        tr <<  _("Needed");        
-
-        if (patch->restartSuggested ())
-          pm_tbl << tr;
-        else
-          tbl << tr;
-      }
-    }
-  }
-
-  // those that affect the package manager go first
-  // (TODO: user option for this?)
-  if (!pm_tbl.empty ())
-  {
-    if (!tbl.empty ())
-      zypper.out().warning(
-        _("These are only the updates affecting the updater itself.\n"
-          "Other updates are available too.\n"));
-    tbl = pm_tbl;
-  }
-
-  tbl.sort (1);                // Name
-
-  if (tbl.empty())
-    zypper.out().info(_("No updates found."));
-  else
-    cout << tbl;
-}
-
-// ----------------------------------------------------------------------------
-
-// collect items, select best edition
-//   this is used to find best available or installed.
-// The name of the class is a bit misleading though ...
-
-class LookForArchUpdate : public zypp::resfilter::PoolItemFilterFunctor
-{
-public:
-  PoolItem best;
-
-  bool operator()( PoolItem provider )
-    {
-      if (!provider.status().isLocked()        // is not locked (taboo)
-         && (!best                     // first match
-             // or a better edition than candidate
-             || best->edition().compare( provider->edition() ) < 0))
-      {
-       best = provider;        // store
-      }
-      return true;             // keep going
-    }
-};
-
-// ----------------------------------------------------------------------------
-
-// Find best (according to edition) uninstalled item
-// with same kind/name/arch as item.
-// Similar to zypp::solver::detail::Helper::findUpdateItem
-// but that allows changing the arch (#222140).
-static
-PoolItem
-findArchUpdateItem( const ResPool & pool, PoolItem item )
-{
-  LookForArchUpdate info;
-
-  invokeOnEach( pool.byIdentBegin( item->kind(), item->name() ),
-                pool.byIdentEnd( item->kind(), item->name() ),
-                // get uninstalled, equal kind and arch, better edition
-                functor::chain (
-                  functor::chain (
-                    resfilter::ByUninstalled (),
-                    resfilter::byArch<CompareByEQ<Arch> >( item->arch() ) ),
-                  resfilter::byEdition<CompareByGT<Edition> >( item->edition() )),
-                functor::functorRef<bool,PoolItem> (info) );
-
-  _XDEBUG("findArchUpdateItem(" << item << ") => " << info.best);
-  return info.best;
-}
-
-// ----------------------------------------------------------------------------
-
-typedef set<PoolItem> Candidates;
-
-/**
- * Find all available updates of given kind.
- */
-static void
-find_updates( const ResKind & kind, Candidates & candidates )
-{
-  const zypp::ResPool& pool = God->pool();
-  ResPool::byKind_iterator
-    it = pool.byKindBegin (kind),
-    e  = pool.byKindEnd (kind);
-  DBG << "Looking for update candidates of kind " << kind << endl;
-  for (; it != e; ++it)
-  {
-    if (it->status().isUninstalled())
-      continue;
-    // (actually similar to ProvideProcess?)
-    PoolItem candidate = findArchUpdateItem( pool, *it );
-    if (!candidate.resolvable())
-      continue;
-
-    DBG << "item " << *it << endl;
-    DBG << "cand " << candidate << endl;
-    candidates.insert (candidate);
-  }
-}
-
-// ----------------------------------------------------------------------------
-
-/**
- * Find all available updates of given kinds.
- */
-static void
-find_updates( const ResKindSet & kinds, Candidates & candidates )
-{
-  for (ResKindSet::const_iterator kit = kinds.begin(); kit != kinds.end(); ++kit)
-    find_updates(*kit, candidates);
-
-  if (kinds.empty())
-    WAR << "called with empty kinds set" << endl;
-}
-
-// ----------------------------------------------------------------------------
-
-string i18n_kind_updates(const ResKind & kind)
-{
-  if (kind == ResTraits<Package>::kind)
-    return _("Package updates");
-  else if (kind == ResTraits<Patch>::kind)
-    return _("Patches");
-  else if (kind == ResTraits<Pattern>::kind)
-    return _("Pattern updates");
-  else if (kind == ResTraits<Product>::kind)
-    return _("Product updates");
-
-  return boost::str(format("%s updates") % kind);
-}
-
-// ----------------------------------------------------------------------------
-
-void list_updates(Zypper & zypper, const ResKindSet & kinds, bool best_effort)
-{
-  if (zypper.out().type() == Out::TYPE_XML)
-  {
-    cout << "<update-status version=\"0.6\">" << endl;
-    cout << "<update-list>" << endl;
-  }
-  bool not_affects_pkgmgr = false;
-
-  unsigned kind_size = kinds.size();
-  ResKindSet localkinds = kinds;
-  ResKindSet::iterator it;
-
-  // patch updates
-  it = localkinds.find(ResKind::patch);
-  if(it != localkinds.end())
-  {
-    if (zypper.out().type() == Out::TYPE_XML)
-      not_affects_pkgmgr = !xml_list_patches();
-    else
-    {
-      zypper.out().info(i18n_kind_updates(*it), Out::QUIET, Out::TYPE_NORMAL);
-      zypper.out().info("", Out::QUIET, Out::TYPE_NORMAL); // visual separator
-      list_patch_updates(zypper);
-    }
-    localkinds.erase(it);
-  }
-
-  // other kinds
-  //! \todo list package updates according to Resolver::doUpdate()
-  if (zypper.out().type() == Out::TYPE_XML)
-  {
-    if (not_affects_pkgmgr)
-      xml_list_updates(localkinds);
-    cout << "</update-list>" << endl;
-    cout << "</update-status>" << endl;
-    return;
-  }
-
-  for (it = localkinds.begin(); it != localkinds.end(); ++it)
-  {
-    Table tbl;
-
-    // show repo only if not best effort or --from-repo set
-    // on best_effort, the solver will determine the repo if we don't limit it to a specific one
-    bool hide_repo = best_effort || copts.count("repo");
-
-    // header
-    TableHeader th;
-    unsigned int name_col;
-    // TranslatorExplanation S stands for Status
-    th << _("S");
-    if (!hide_repo) {
-      th << (zypper.globalOpts().is_rug_compatible ? _("Catalog") : _("Repository"));
-    }
-    if (zypper.globalOpts().is_rug_compatible) {
-      th << _("Bundle");
-    }
-    name_col = th.cols();
-    th << _("Name");
-    if (!best_effort) {                // best_effort does not know version or arch yet
-      th << _("Version") << _("Arch");
-    }
-    tbl << th;
-
-    unsigned int cols = th.cols();
-
-    Candidates candidates;
-    find_updates( *it, candidates );
-
-    Candidates::iterator cb = candidates.begin (), ce = candidates.end (), ci;
-    for (ci = cb; ci != ce; ++ci) {
-//      ResStatus& candstat = ci->status();
-//      candstat.setToBeInstalled (ResStatus::USER);
-      ResObject::constPtr res = ci->resolvable();
-      TableRow tr (cols);
-      tr << "v";
-      if (!hide_repo) {
-       tr << res->repoInfo().name();
-      }
-      if (zypper.globalOpts().is_rug_compatible)
-       tr << "";               // Bundle
-      tr << res->name ();
-
-      // strictly speaking, we could show version and arch even in best_effort
-      //  iff there is only one candidate. But we don't know the number of candidates here.
-      if (!best_effort) {
-        tr << res->edition ().asString ()
-           << res->arch ().asString ();
-      }
-      tbl << tr;
-    }
-    tbl.sort( name_col );
-
-    if (kind_size > 1)
-    {
-      zypper.out().info("", Out::QUIET, Out::TYPE_NORMAL); // visual separator
-      zypper.out().info(i18n_kind_updates(*it), Out::QUIET, Out::TYPE_NORMAL);
-      zypper.out().info("", Out::QUIET, Out::TYPE_NORMAL); // visual separator
-    }
-
-    if (tbl.empty())
-      zypper.out().info(_("No updates found."));
-    else
-      cout << tbl;
-  }
-}
-
-// ----------------------------------------------------------------------------
-
-// may be useful as a functor
-static bool
-mark_item_install (const PoolItem & pi)
-{
-  bool result = pi.status().setToBeInstalled( zypp::ResStatus::USER );
-  if (!result)
-    ERR << "Marking " << pi << "for installation failed" << endl;
-  return result;
-}
-
-// ----------------------------------------------------------------------------
-// best-effort update
-// ----------------------------------------------------------------------------
-
-// find installed item matching passed one
-//   use LookForArchUpdate as callback handler in order to cope with
-//   multiple installed resolvables of the same name.
-//   LookForArchUpdate will return the one with the highest edition.
-
-static PoolItem
-findInstalledItem( PoolItem item )
-{
-  const zypp::ResPool& pool = God->pool();
-  LookForArchUpdate info;
-
-  invokeOnEach( pool.byIdentBegin( item->kind(), item->name() ),
-                pool.byIdentEnd( item->kind(), item->name() ),
-                resfilter::ByInstalled (),
-                functor::functorRef<bool,PoolItem> (info) );
-
-  _XDEBUG("findInstalledItem(" << item << ") => " << info.best);
-  return info.best;
-}
-
-// ----------------------------------------------------------------------------
-
-// require update of installed item
-//   The PoolItem passed to require_item_update() is the installed resolvable
-//   to which an update candidate is guaranteed to exist.
-//
-// may be useful as a functor
-
-static bool require_item_update (const PoolItem& pi) {
-  Resolver_Ptr resolver = zypp::getZYpp()->resolver();
-
-  PoolItem installed = findInstalledItem( pi );
-
-  // require anything greater than the installed version
-  try {
-    Capability  cap( installed->name(), Rel::GT, installed->edition(), installed->kind() );
-    resolver->addRequire( cap );
-  }
-  catch (const Exception& e) {
-    ZYPP_CAUGHT(e);
-    Zypper::instance()->out().error(boost::str(format(
-      _("Cannot parse '%s < %s'")) % installed->name() % installed->edition()));
-  }
-
-  return true;
-}
-
-// ----------------------------------------------------------------------------
-
-void xml_list_updates(const ResKindSet & kinds)
-{
-  Candidates candidates;
-  find_updates (kinds, candidates);
-
-  Candidates::iterator cb = candidates.begin (), ce = candidates.end (), ci;
-  for (ci = cb; ci != ce; ++ci) {
-    ResObject::constPtr res = ci->resolvable();
-
-    cout << " <update ";
-    cout << "name=\"" << res->name () << "\" " ;
-    cout << "edition=\""  << res->edition ().asString() << "\" ";
-    cout << "kind=\"" << res->kind() << "\" ";
-    cout << ">" << endl;
-    cout << "  <summary>" << xml_encode(res->summary()) << "  </summary>" << endl;
-    cout << "  <description>" << xml_encode(res->description()) << "</description>" << endl;
-    cout << "  <license>" << xml_encode(res->licenseToConfirm()) << "</license>" << endl;
-
-    if ( !res->repoInfo().alias().empty() )
-    {
-       cout << "  <source url=\"" << xml_encode(res->repoInfo().baseUrlsBegin()->asString());
-       cout << "\" alias=\"" << xml_encode(res->repoInfo().alias()) << "\"/>" << endl;
-    }
-
-    cout << " </update>" << endl;
-  }
-}
-
-// ----------------------------------------------------------------------------
-
-static bool
-mark_patch_update(const PoolItem & pi, bool skip_interactive, bool ignore_affects_pm)
-{
-  Patch::constPtr patch = asKind<Patch>(pi.resolvable());
-  if (pi.isRelevant() && !pi.isSatisfied())
-  {
-    DBG << "patch " << patch->name() << " " << ignore_affects_pm << ", "
-      << patch->restartSuggested() << endl;
-    if (ignore_affects_pm || patch->restartSuggested())
-    {
-      // #221476
-      if (skip_interactive
-          && (patch->interactive() || !patch->licenseToConfirm().empty()))
-      {
-        // Skipping a patch because it is marked as interactive or has
-        // license to confirm and --skip-interactive is requested.
-        Zypper::instance()->out().warning(str::form(
-          // translators: %s is the name of a patch
-          _("'%s' is interactive, skipping."), patch->name().c_str()));
-        return false;
-      }
-      else
-      {
-        mark_item_install(pi);
-        return true;
-      }
-    }
-  }
-
-  return false;
-}
-
-// ----------------------------------------------------------------------------
-
-static void
-mark_patch_updates( Zypper & zypper, bool skip_interactive )
-{
-  DBG << "going to mark patches to install" << endl;
-
-  // search twice: if there are none with restartSuggested(), retry on all
-  bool any_marked = false;
-  for(unsigned ignore_affects_pm = 0;
-      !any_marked && ignore_affects_pm < 2; ++ignore_affects_pm)
-  {
-    if (zypper.arguments().empty() || zypper.globalOpts().is_rug_compatible)
-    {
-      DBG << "marking all needed patches" << endl;
-
-      for_(it, God->pool().byKindBegin(ResKind::patch), 
-               God->pool().byKindEnd  (ResKind::patch))
-      {
-        if (mark_patch_update(*it, skip_interactive, ignore_affects_pm))
-          any_marked = true;
-      }
-    }
-    else if (!zypper.arguments().empty())
-    {
-      for_(it, zypper.arguments().begin(), zypper.arguments().end())
-      {
-        // look for patches matching specified pattern
-        PoolQuery q;
-        q.addKind(ResKind::patch);
-        q.addAttribute(sat::SolvAttr::name, *it);
-        //! \todo should we look for patches requiring packages with matching name instead? 
-        //q.addAttribute(sat::SolvAttr::require, *it);
-        q.setMatchGlob();
-
-        if (q.empty())
-        {
-          if (ignore_affects_pm) // avoid displaying this twice
-            continue;
-          if (it->find_first_of("?*") != string::npos) // wildcards used
-            zypper.out().info(str::form(
-                _("No patches matching '%s' found."), it->c_str()));
-          else
-            zypper.out().info(str::form(
-                _("Patch '%s' not found."), it->c_str()));
-          zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
-        }
-        else
-        {
-          for_(pit, q.poolItemBegin(), q.poolItemEnd())
-          {
-            any_marked = mark_patch_update(*pit, skip_interactive, ignore_affects_pm);
-          }
-        }
-      }
-    }
-  }
-}
-
-// ----------------------------------------------------------------------------
-
-void mark_updates(Zypper & zypper, const ResKindSet & kinds, bool skip_interactive, bool best_effort )
-{
-  ResKindSet localkinds = kinds;
-
-  if (zypper.arguments().empty() || zypper.globalOpts().is_rug_compatible)
-  {
-    for_(kindit, localkinds.begin(), localkinds.end())
-    {
-      if (*kindit == ResKind::package)
-      {
-        // this will do a complete pacakge update as far as possible
-        God->resolver()->doUpdate();
-        // no need to call Resolver::resolvePool() afterwards
-        zypper.runtimeData().solve_before_commit = false;
-      }
-      else if (*kindit == ResKind::patch)
-      {
-        mark_patch_updates(zypper, skip_interactive);
-      }
-      else
-      {
-        Candidates candidates;
-        find_updates (localkinds, candidates);
-        if (best_effort)
-          invokeOnEach (candidates.begin(), candidates.end(), require_item_update);
-        else
-          invokeOnEach (candidates.begin(), candidates.end(), mark_item_install);
-      } 
-    }
-  }
-  // treat arguments as package names (+allow wildcards)
-  else if (!zypper.arguments().empty())
-  {
-    for_(kindit, localkinds.begin(), localkinds.end())
-    {
-      Resolver_Ptr solver = God->resolver();
-      for_(it, zypper.arguments().begin(), zypper.arguments().end())
-      {
-        PoolQuery q;
-        q.addKind(*kindit);
-        q.addAttribute(sat::SolvAttr::name, *it);
-        q.setMatchGlob();
-        q.setInstalledOnly();
-  
-        if (q.empty())
-        {
-          if (it->find_first_of("?*") != string::npos) // wildcards used
-            zypper.out().info(str::form(
-                _("No packages matching '%s' are installed."), it->c_str()));
-          else
-            zypper.out().info(str::form(
-                _("Package '%s' is not installed."), it->c_str()));
-          zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
-        }
-        else
-          for_(solvit, q.selectableBegin(), q.selectableEnd())
-          {
-            ui::Selectable::Ptr s = *solvit;
-            PoolItem theone = s->theObj();
-            if (equalNVRA(*s->installedObj().resolvable(), *theone.resolvable()))
-            {
-              DBG << "the One (" << theone << ") is installed, skipping." << endl;
-              zypper.out().info(str::form(
-                  _("No update candidate for '%s'."), s->name().c_str()));
-            }
-            else
-            {
-              //s->setCandidate(theone); ?
-              //s->setStatus(ui::S_Update); ?
-              Capability c(s->name(), Rel::GT, s->installedObj()->edition(), s->kind());
-              solver->addRequire(c);
-              DBG << *s << " update: adding requirement " << c << endl;
-            }
-          }
-      }
-    }
-  }
-}
-
-// ----------------------------------------------------------------------------
-// commit
-// ----------------------------------------------------------------------------
-
-/**
- * @return ZYPPER_EXIT_OK - successful commit,
- *  ZYPPER_EXIT_ERR_ZYPP - if ZYppCommitResult contains resolvables with errors,
- *  ZYPPER_EXIT_INF_REBOOT_NEEDED - if one of patches to be installed needs machine reboot,
- *  ZYPPER_EXIT_INF_RESTART_NEEDED - if one of patches to be installed needs package manager restart
- */
-void solve_and_commit (Zypper & zypper)
-{
-  if (zypper.cOpts().count("debug-solver"))
-  {
-    make_solver_test_case(zypper);
-    return;
-  }
-
-  bool show_forced_problems = true;
-  bool commit_done = false;
-  do
-  {
-    if (zypper.runtimeData().solve_before_commit) // doUpdate was called, no need for solving
-    {
-      MIL << "solving..." << endl;
-
-      while (true)
-      {
-        bool success;
-        if (zypper.command() == ZypperCommand::VERIFY)
-          success = verify(zypper);
-        else if (zypper.command() == ZypperCommand::DIST_UPGRADE)
-        {
-          zypp::UpgradeStatistics opt_stats;
-          //! \todo set success to doUpgrade return value if there are problems
-          success = false;
-          God->resolver()->doUpgrade(opt_stats);
-          //! \todo remove this hack once the doUpgrade returns bool
-          if (God->resolver()->problems().empty())
-            break;
-        }
-        else
-          success = resolve(zypper);
-        if (success)
-          break;
-
-        success = show_problems(zypper);
-        if (! success) {
-          // TODO cancel transaction?
-          zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP); // #242736
-          return;
-        }
-      }
-    }
-
-    MIL << "got solution, showing summary" << endl;
-
-    // returns SUMMARY_*
-    int retv = summary(zypper);
-    if (retv != SUMMARY_NOTHING_TO_DO || !zypper.runtimeData().srcpkgs_to_install.empty())
-    {
-      // check root user
-      if (zypper.command() == ZypperCommand::VERIFY && geteuid() != 0
-        && !zypper.globalOpts().changedRoot)
-      {
-        zypper.out().error(
-          _("Root privileges are required to fix broken package dependencies."));
-        zypper.setExitCode(ZYPPER_EXIT_ERR_PRIVILEGES);
-        return;
-      }
-  
-      bool do_commit = false;
-      if (zypper.runtimeData().force_resolution &&
-          (retv == SUMMARY_INSTALL_DOES_REMOVE || retv == SUMMARY_REMOVE_DOES_INSTALL))
-      {
-        PromptOptions popts;
-        // translators: Yes / No / show Problems. This prompt will appear
-        // after install/update command summary if there will be any package
-        // to-be-removed automatically to show why, if asked.
-        popts.setOptions(_("y/n/p"), 0);
-        // translators: help text for 'y' option in the y/n/p prompt
-        popts.setOptionHelp(0, _("Accept the summary and proceed with installation/removal of packages."));
-        // translators: help text for 'n' option in the y/n/p prompt
-        popts.setOptionHelp(1, _("Cancel the operation."));
-        // translators: help text for 'p' option in the y/n/p prompt
-        popts.setOptionHelp(2, _("Restart solver in no-force-resolution mode in order to show dependency problems."));
-        string prompt_text = _("Continue?");
-        zypper.out().prompt(PROMPT_YN_INST_REMOVE_CONTINUE, prompt_text, popts);
-        unsigned int reply =
-          get_prompt_reply(zypper, PROMPT_YN_INST_REMOVE_CONTINUE, popts);
-
-        if (reply == 2)
-        {
-          // one more solver solver run with force-resoltion off
-          zypper.runtimeData().force_resolution = false;
-          // undo solver changes before retrying
-          God->resolver()->undo();
-          continue;
-        }
-        else if (reply == 1)
-          show_forced_problems = false;
-        else
-        {
-          do_commit = true;
-          show_forced_problems = false;
-        }
-      }
-      // no dependency problems
-      else
-      {
-        do_commit = read_bool_answer(PROMPT_YN_INST_REMOVE_CONTINUE, _("Continue?"), true);
-        show_forced_problems = false;
-      }
-
-      if (do_commit)
-      {
-        if (!confirm_licenses(zypper))
-          return;
-
-        if (retv >= 0)
-        {
-          try
-          {
-            gData.show_media_progress_hack = true;
-    
-            ostringstream s;
-            s << _("committing"); MIL << "committing...";
-    
-            ZYppCommitResult result;
-            if (copts.count("dry-run"))
-            {
-              s << " " << _("(dry run)") << endl; MIL << "(dry run)";
-              zypper.out().info(s.str(), Out::HIGH);
-    
-              result = God->commit(ZYppCommitPolicy().dryRun(true));
-            }
-            else
-            {
-              zypper.out().info(s.str(), Out::HIGH);
-    
-              result = God->commit(
-                ZYppCommitPolicy().syncPoolAfterCommit(zypper.runningShell()));
-    
-              commit_done = true;
-            }
-
-
-            MIL << endl << "DONE" << endl;
-
-            gData.show_media_progress_hack = false;
-
-            if (!result._errors.empty())
-              retv = ZYPPER_EXIT_ERR_ZYPP;
-    
-            s.clear(); s << result;
-            zypper.out().info(s.str(), Out::HIGH);
-          }
-          catch ( const media::MediaException & e ) {
-            ZYPP_CAUGHT(e);
-            zypper.out().error(e,
-                _("Problem downloading the package file from the repository:"),
-                _("Please see the above error message for a hint."));
-            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
-            return;
-          }
-          catch ( zypp::repo::RepoException & e ) {
-            ZYPP_CAUGHT(e);
-            
-            RepoManager manager(zypper.globalOpts().rm_options );
-  
-            bool refresh_needed = false;
-            for(RepoInfo::urls_const_iterator it = e.info().baseUrlsBegin();
-                      it != e.info().baseUrlsEnd(); ++it)
-              {
-                RepoManager::RefreshCheckStatus stat = manager.
-                              checkIfToRefreshMetadata(e.info(), *it,
-                              RepoManager::RefreshForced );
-                if ( stat == RepoManager::REFRESH_NEEDED )
-                {
-                  refresh_needed = true;
-                  break;
-                }
-              }
-            
-            std::string hint = _("Please see the above error message for a hint.");
-            if (refresh_needed)
-            {
-              hint = boost::str(format(
-                  // translators: the first %s is 'zypper refresh' and the second
-                  // is repo allias
-                  _("Repository '%s' is out of date. Running '%s' might help.")) %
-                  e.info().alias() % "zypper refresh" );
-            }
-            zypper.out().error(e,
-                _("Problem downloading the package file from the repository:"),
-                hint);
-            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
-            return;
-          }
-          catch ( const zypp::FileCheckException & e ) {
-            ZYPP_CAUGHT(e);
-            zypper.out().error(e,
-                _("The package integrity check failed. This may be a problem"
-                " with the repository or media. Try one of the following:\n"
-                "\n"
-                "- just retry previous command\n"
-                "- refresh the repositories using 'zypper refresh'\n"
-                "- use another installation medium (if e.g. damaged)\n"
-                "- use another repository"));
-            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
-            return;
-          }
-          catch ( const Exception & e ) {
-            ZYPP_CAUGHT(e);
-            zypper.out().error(e,
-                _("Problem occured during or after installation or removal of packages:"),
-                _("Please see the above error message for a hint."));
-            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
-          }
-        }
-        // install any pending source packages
-        if (!zypper.runtimeData().srcpkgs_to_install.empty())
-          install_src_pkgs(zypper);
-      }
-    }
-    // noting to do
-    else
-      break;
-  }
-  while (show_forced_problems);
-
-  if (commit_done)
-  {
-    if (zypper.exitCode() == ZYPPER_EXIT_INF_REBOOT_NEEDED)
-      zypper.out().warning(
-        _("One of installed patches requires reboot of"
-          " your machine. Reboot as soon as possible."), Out::QUIET);
-    else if (zypper.exitCode() == ZYPPER_EXIT_INF_RESTART_NEEDED)
-      zypper.out().warning(
-        _("One of installed patches affects the package"
-          " manager itself, thus it requires its restart before executing"
-          " any further operations."),
-        Out::QUIET, Out::TYPE_NORMAL); // don't show this to machines
-  }
-}
-
 // TODO confirm licenses
 // - make this more user-friendly e.g. show only license name and
 //  ask for [y/n/r] with 'r' for read the license text
 //  (opened throu more or less, etc...)
 // - after negative answer, call solve_and_commit() again
-static bool confirm_licenses(Zypper & zypper)
+bool confirm_licenses(Zypper & zypper)
 {
   bool confirmed = true;
 
index 1c9e071..fb7cc2b 100644 (file)
@@ -1,38 +1,28 @@
-/*-----------------------------------------------------------*- c++ -*-\
-|                          ____ _   __ __ ___                          |
-|                         |__  / \ / / . \ . \                         |
-|                           / / \ V /|  _/  _/                         |
-|                          / /__ | | | | | |                           |
-|                         /_____||_| |_| |_|                           |
-|                                                                      |
-\---------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
 
 #ifndef ZMART_MISC_H
 #define ZMART_MISC_H
 
 #include <string>
 
-#include "zypp/ResKind.h"
-#include "zypp/PoolItem.h"
-
 #include "Zypper.h"
-#include "Table.h"
-#include "utils.h"
-
 
-zypp::ResKind string_to_kind (const std::string & skind);
 
 /**
- * Run the solver.
+ * Loops through resolvables, checking if there is license to confirm. When
+ * run interactively, it displays a dialog, otherwise it answers automatically
+ * according to --auto-agree-with-licenses present or not present.
  * 
- * \return <tt>true</tt> if a solution has been found, <tt>false</tt> otherwise 
+ * \returns true if all licenses have been confirmed, false otherwise.  
  */
-bool resolve(Zypper & zypper);
+bool confirm_licenses(Zypper & zypper);
 
-void install_remove(Zypper & zypper,
-                    const Zypper::ArgList & args,
-                    bool install_not_remove,
-                    const zypp::ResKind & kind);
+zypp::ResKind string_to_kind (const std::string & skind);
 
 /**
  * Reset all selections made by mark_* methods. Needed in the shell to reset
@@ -40,68 +30,6 @@ void install_remove(Zypper & zypper,
  */
 void remove_selections(Zypper & zypper);
 
-/**
- * Are there applicable patches?
- */
-void patch_check();
-
-/**
- * Lists available updates of installed resolvables of specified \a kind.
- * if repo_alias != "", restrict updates to this repository.
- * if best_effort == true, any version greater than the installed one will do.
- * Prints the table of updates to stdout.
- * 
- * \param kind  resolvable type
- * \param best_effort
- */
-void list_updates(Zypper & zypper,
-                  const ResKindSet & kinds,
-                  bool best_effort);
-
-/** \todo remove from this header after xu is dropped */ 
-bool xml_list_patches();
-/** \todo remove from this header after xu is dropped */
-void xml_list_updates(const ResKindSet & kinds);
-
-/**
- * \param kind  resolvable type
- * \param skip_interactive whether to skip updates that need user interaction
- * \param best_effort
- */
-void mark_updates(Zypper & zypper,
-                  const ResKindSet & kinds,
-                  bool skip_interactive,
-                  bool best_effort);
-
-/**
- * Runs solver on the pool, asks to choose solution of eventual problems
- * (when run interactively) and commits the result.
- * 
- * \param have_extra_deps ?
- * \return ZYPPER_EXIT_INF_REBOOT_NEEDED, ZYPPER_EXIT_INF_RESTART_NEEDED,
- *         or ZYPPER_EXIT_OK or ZYPPER_EXIT_ERR_ZYPP on zypp erorr. 
- *  
- */
-void solve_and_commit(Zypper & zypper);
-
-
-// copied from yast2-pkg-bindings:PkgModuleFunctions::DoProvideNameKind
-struct ProvideProcess
-{
-  zypp::PoolItem item;
-  zypp::PoolItem installed_item;
-  zypp::ResStatus::TransactByValue whoWantsIt;
-  std::string _repo;
-  zypp::Arch _architecture;
-
-  ProvideProcess(zypp::Arch arch, const std::string & repo)
-    : whoWantsIt(zypp::ResStatus::USER)
-    , _repo(repo)
-    , _architecture( arch )
-    { }
-
-  bool operator()( const zypp::PoolItem& provider );
-};
 
 /**
  * Find source packages by names specified as arguments.
index 6e86952..85b4248 100644 (file)
@@ -1626,7 +1626,8 @@ void modify_repo(Zypper & zypper, const string & alias)
       repo.setKeepPackages(keepPackages);
     }
 
-    int prio = 0;
+    long long prio = 0;
+    cout << sizeof(prio) << endl;
     parsed_opts::const_iterator tmp1;
     if ((tmp1 = zypper.cOpts().find("priority")) != zypper.cOpts().end())
     {
diff --git a/src/solve-commit.cc b/src/solve-commit.cc
new file mode 100755 (executable)
index 0000000..aec44f1
--- /dev/null
@@ -0,0 +1,1137 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+
+#include <iostream>
+#include <sstream>
+#include <boost/format.hpp>
+
+#include "zypp/ZYppFactory.h"
+#include "zypp/base/Logger.h"
+#include "zypp/FileChecker.h"
+
+#include "zypp/Edition.h"
+#include "zypp/Patch.h"
+#include "zypp/Package.h"
+
+#include "zypp/media/MediaException.h"
+
+#include "misc.h"
+#include "prompt.h"
+#include "utils.h"
+#include "getopt.h"
+
+#include "solve-commit.h"
+
+using namespace std;
+using namespace zypp;
+using namespace boost;
+
+extern ZYpp::Ptr God;
+
+
+//! @return true to retry solving now, false to cancel, indeterminate to continue
+static TriBool show_problem (Zypper & zypper,
+                             const ResolverProblem & prob,
+                             ProblemSolutionList & todo)
+{
+  ostringstream desc_stm;
+  string tmp;
+  // translators: meaning 'dependency problem' found during solving
+  desc_stm << _("Problem: ") << prob.description () << endl;
+  tmp = prob.details ();
+  if (!tmp.empty ())
+    desc_stm << "  " << tmp << endl;
+
+  int n;
+  ProblemSolutionList solutions = prob.solutions ();
+  ProblemSolutionList::iterator
+    bb = solutions.begin (),
+    ee = solutions.end (),
+    ii;
+  for (n = 1, ii = bb; ii != ee; ++n, ++ii) {
+    // TranslatorExplanation %d is the solution number
+    desc_stm << format (_(" Solution %d: ")) % n << (*ii)->description () << endl;
+    tmp = (*ii)->details ();
+    if (!tmp.empty ())
+      desc_stm << indent(tmp, 2) << endl;
+  }
+
+  unsigned int problem_count = God->resolver()->problems().size();
+  unsigned int solution_count = solutions.size(); 
+
+  // without solutions, its useless to prompt
+  if (solutions.empty())
+  {
+    zypper.out().error(desc_stm.str());
+    return false;
+  }
+
+  string prompt_text;
+  if (problem_count > 1)
+    prompt_text = _PL(
+      "Choose the above solution using '1' or skip, retry or cancel",
+      "Choose from above solutions by number or skip, retry or cancel",
+      solution_count);
+  else
+    prompt_text = _PL(
+      // translators: translate 'c' to whatever you translated the 'c' in
+      // "c" and "s/r/c" strings
+      "Choose the above solution using '1' or cancel using 'c'",
+      "Choose from above solutions by number or cancel",
+      solution_count);
+
+  PromptOptions popts;
+  unsigned int default_reply;
+  ostringstream numbers;
+  for (unsigned int i = 1; i <= solution_count; i++)
+    numbers << i << "/";
+
+  if (problem_count > 1)
+  {
+    default_reply = solution_count + 2;
+    // translators: answers for dependency problem solution input prompt:
+    // "Choose from above solutions by number or skip, retry or cancel"
+    // Translate the letters to whatever is suitable for your language.
+    // The anserws must be separated by slash characters '/' and must
+    // correspond to skip/retry/cancel in that order.
+    // The answers should be lower case letters.
+    popts.setOptions(numbers.str() + _("s/r/c"), default_reply);
+  }
+  else
+  {
+    default_reply = solution_count;
+    // translators: answers for dependency problem solution input prompt:
+    // "Choose from above solutions by number or cancel"
+    // Translate the letter 'c' to whatever is suitable for your language
+    // and to the same as you translated it in the "s/r/c" string
+    // See the "s/r/c" comment for other details.
+    // One letter string  for translation can be tricky, so in case of problems,
+    // please report a bug against zypper at bugzilla.novell.com, we'll try to solve it.
+    popts.setOptions(numbers.str() + _("c"), default_reply);
+  }
+
+  zypper.out().prompt(PROMPT_DEP_RESOLVE, prompt_text, popts, desc_stm.str());
+  unsigned int reply =
+    get_prompt_reply(zypper, PROMPT_DEP_RESOLVE, popts);
+
+  // retry
+  if (problem_count > 1 && reply == solution_count + 1)
+    return true;
+  // cancel (one problem)
+  if (problem_count == 1 && reply == solution_count)
+    return false;
+  // cancel (more problems)
+  if (problem_count > 1 && reply == solution_count + 2)
+    return false;
+  // skip
+  if (problem_count > 1 && reply == solution_count)
+    return indeterminate; // continue with next problem
+
+  zypper.out().info(boost::str(format (_("Applying solution %s")) % (reply + 1)), Out::HIGH);
+  ProblemSolutionList::iterator reply_i = solutions.begin ();
+  advance (reply_i, reply);
+  todo.push_back (*reply_i);
+
+  tribool go_on = indeterminate; // continue with next problem
+  return go_on;
+}
+
+// return true to retry solving, false to cancel transaction
+static bool show_problems(Zypper & zypper)
+{
+  bool retry = true;
+  Resolver_Ptr resolver = zypp::getZYpp()->resolver();
+  ResolverProblemList rproblems = resolver->problems ();
+  ResolverProblemList::iterator
+    b = rproblems.begin (),
+    e = rproblems.end (),
+    i;
+  ProblemSolutionList todo;
+
+  // display the number of problems
+  if (rproblems.size() > 1)
+    zypper.out().info(boost::str(format(
+      _PL("%d Problem:", "%d Problems:", rproblems.size())) % rproblems.size()));
+  else if (rproblems.empty())
+  {
+    // should not happen! If solve() failed at least one problem must be set!
+    zypper.out().error(_("Specified capability not found"));
+    zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
+    return false;
+  }
+
+  // for many problems, list them shortly first
+  //! \todo handle resolver problems caused by --capability mode arguments specially to give proper output (bnc #337007)
+  if (rproblems.size() > 1)
+  {
+    for (i = b; i != e; ++i)
+      zypper.out().info(boost::str(
+        format(_("Problem: %s")) % (*i)->description()));
+  }
+  // now list all problems with solution proposals
+  for (i = b; i != e; ++i)
+  {
+    zypper.out().info("", Out::NORMAL, Out::TYPE_NORMAL); // visual separator
+    TriBool stopnow = show_problem(zypper, *(*i), todo);
+    if (! indeterminate (stopnow)) {
+      retry = stopnow == true;
+      break;
+    }
+  }
+
+  if (retry)
+  {
+    zypper.out().info(_("Resolving dependencies..."));
+    resolver->applySolutions (todo);
+  }
+  return retry;
+}
+
+typedef map<Resolvable::Kind,set<ResObject::constPtr> > 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 (set<ResObject::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
+} 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;
+  }
+}
+
+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 (set<ResObject::constPtr>::const_iterator resit = it->second.begin();
+          resit != it->second.end(); ++resit)
+      {
+        ResObject::constPtr res(*resit);
+
+        cout << "<solvable";
+        cout << " type=\"" << it->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;
+    }
+
+    show_summary_resolvable_list(title, it, zypper.out());
+  }
+}
+
+enum
+{
+  SUMMARY_OK = 0,
+  SUMMARY_NOTHING_TO_DO,
+  SUMMARY_INSTALL_DOES_REMOVE,
+  SUMMARY_REMOVE_DOES_INSTALL
+};
+
+/**
+ * sets zypper exit code to:
+ *  ZYPPER_EXIT_INF_REBOOT_NEEDED - if one of patches to be installed needs machine reboot,
+ *  ZYPPER_EXIT_INF_RESTART_NEEDED - if one of patches to be installed needs package manager restart
+ * 
+ * @return SUMMARY_*
+ */
+static int summary(Zypper & zypper)
+{
+  int retv = SUMMARY_NOTHING_TO_DO;
+
+  MIL << "Pool contains " << God->pool().size() << " items." << std::endl;
+  DBG << "Install summary:" << endl;
+
+
+  KindToResObjectSet to_be_installed;
+  KindToResObjectSet to_be_removed;
+
+  // 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() == ResTraits<Patch>::kind)
+      {
+        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);
+      }
+
+      if ( it->status().isToBeInstalled()
+           && it->resolvable()->kind() != ResTraits<Atom>::kind )
+      {
+        DBG << "<install>   ";
+        to_be_installed[it->resolvable()->kind()].insert(it->resolvable());
+      }
+      if ( it->status().isToBeUninstalled()
+           && it->resolvable()->kind() != ResTraits<Atom>::kind )
+      {
+        DBG << "<uninstall> ";
+        to_be_removed[it->resolvable()->kind()].insert(it->resolvable());
+      }
+      DBG << *res << endl;
+    }
+  }
+
+  if (!to_be_removed.empty() || !to_be_installed.empty())
+    retv = SUMMARY_OK;
+
+  if (retv == SUMMARY_NOTHING_TO_DO && zypper.runtimeData().srcpkgs_to_install.empty())
+  {
+    if (zypper.command() == ZypperCommand::VERIFY)
+      zypper.out().info(_("Dependencies of all installed packages are satisfied."));
+    else
+      zypper.out().info(_("Nothing to do."));
+    return retv;
+  }
+
+  if (zypper.command() == ZypperCommand::VERIFY)
+    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();
+  zypper.runtimeData().commit_pkg_current = 0;
+
+  KindToResObjectSet toinstall;
+  KindToResObjectSet toupgrade;
+  KindToResObjectSet todowngrade;
+  KindToResObjectSet toreinstall;
+  KindToResObjectSet toremove;
+  KindToResObjectSet tochangearch;
+  KindToResObjectSet tochangevendor;
+
+  // 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 (set<ResObject::constPtr>::const_iterator resit = it->second.begin();
+        resit != it->second.end(); ++resit)
+    {
+      ResObject::constPtr res(*resit);
+
+      // find in to_be_removed:
+      bool upgrade_downgrade = false;
+      for (set<ResObject::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 (set<ResObject::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 (list<SrcPackage::constPtr>::const_iterator it = zypper.runtimeData().srcpkgs_to_install.begin();
+      it != zypper.runtimeData().srcpkgs_to_install.end(); ++it)
+    toinstall[ResTraits<SrcPackage>::kind].insert(*it);
+
+  if (!toremove.empty() && (
+      zypper.command() == ZypperCommand::INSTALL ||
+      zypper.command() == ZypperCommand::UPDATE))
+    retv = SUMMARY_INSTALL_DOES_REMOVE;
+  else if ((!toinstall.empty() || toremove_by_solver)
+      && zypper.command() == ZypperCommand::REMOVE)
+    retv = SUMMARY_REMOVE_DOES_INSTALL;
+
+  // "</install-summary>"
+  if (zypper.out().type() == Out::TYPE_XML)
+  {
+    cout << "<install-summary";
+    cout << " download-size=\"" << ((ByteCount::SizeType) download_size) << "\"";
+    cout << " space-usage-diff=\"" << ((ByteCount::SizeType) new_installed_size) << "\"";
+    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);
+
+  // "</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.");
+  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());
+
+  return retv;
+}
+
+
+static void dump_pool ()
+{
+  int count = 1;
+  static bool full_pool_shown = false;
+
+  _XDEBUG( "---------------------------------------" );
+  for (ResPool::const_iterator it =   God->pool().begin(); it != God->pool().end(); ++it, ++count) {
+
+    if (!full_pool_shown                                    // show item if not shown all before
+        || it->status().transacts()                         // or transacts
+        || !it->isBroken())                                 // or broken status
+    {
+      _XDEBUG( count << ": " << *it );
+    }
+  }
+  _XDEBUG( "---------------------------------------" );
+  full_pool_shown = true;
+}
+
+
+static void set_force_resolution(Zypper & zypper)
+{
+  // --force-resolution command line parameter value
+  TriBool force_resolution = zypper.runtimeData().force_resolution;
+
+  if (zypper.cOpts().count("force-resolution"))
+    force_resolution = true;
+  if (zypper.cOpts().count("no-force-resolution"))
+  {
+    if (force_resolution)
+      zypper.out().warning(str::form(
+        // translators: meaning --force-resolution and --no-force-resolution
+        _("%s conflicts with %s, will use the less aggressive %s"),
+          "--force-resolution", "--no-force-resolution", "--no-force-resolution"));
+    force_resolution = false;
+  }
+
+  // if --force-resolution was not specified on the command line, force
+  // the resolution by default for the install and remove commands and the
+  // rug_compatible mode. Don't force resolution in non-interactive mode
+  // and for update and dist-upgrade command (complex solver request).
+  // bnc #369980
+  if (indeterminate(force_resolution))
+  {
+    if (!zypper.globalOpts().non_interactive &&
+        (zypper.globalOpts().is_rug_compatible ||
+         zypper.command() == ZypperCommand::INSTALL ||
+         zypper.command() == ZypperCommand::REMOVE))
+      force_resolution = true;
+    else
+      force_resolution = false;
+  }
+
+  // save the setting
+  zypper.runtimeData().force_resolution = force_resolution; 
+
+  DBG << "force resolution: " << force_resolution << endl;
+  ostringstream s;
+  s << _("Force resolution:") << " " << (force_resolution ? _("Yes") : _("No"));
+  zypper.out().info(s.str(), Out::HIGH);
+
+  God->resolver()->setForceResolve(force_resolution);
+}
+
+static void set_no_recommends(Zypper & zypper)
+{
+  bool no_recommends = false;
+  if (zypper.command() == ZypperCommand::REMOVE)
+    // never install recommends when removing packages
+    no_recommends = true;
+  else
+    // install also recommended packages unless --no-recommends is specified
+    no_recommends = zypper.cOpts().count("no-recommends");
+  DBG << "no recommends (only requires): " << no_recommends << endl;
+  God->resolver()->setOnlyRequires(no_recommends);
+}
+
+
+static void set_ignore_recommends_of_installed(Zypper & zypper)
+{
+  bool ignore = true;
+  if (zypper.command() == ZypperCommand::DIST_UPGRADE ||
+      zypper.command() == ZypperCommand::INSTALL_NEW_RECOMMENDS)
+    ignore = false;
+  DBG << "ignore recommends of already installed packages: " << ignore << endl;
+  God->resolver()->setIgnoreAlreadyRecommended(ignore);
+}
+
+
+/**
+ * Run the solver.
+ * 
+ * \return <tt>true</tt> if a solution has been found, <tt>false</tt> otherwise 
+ */
+bool resolve(Zypper & zypper)
+{
+  dump_pool(); // debug
+  set_force_resolution(zypper);
+  set_no_recommends(zypper);
+  set_ignore_recommends_of_installed(zypper);
+  zypper.out().info(_("Resolving dependencies..."), Out::HIGH);
+  DBG << "Calling the solver..." << endl;
+  return God->resolver()->resolvePool();
+}
+
+static bool verify(Zypper & zypper)
+{
+  dump_pool();
+  zypper.out().info(_("Verifying dependencies..."), Out::HIGH);
+  // don't force aggressive solutions
+  God->resolver()->setForceResolve(false); //! \todo move to set_force_resolution()
+  set_no_recommends(zypper);
+  set_ignore_recommends_of_installed(zypper);
+  DBG << "Calling the solver to verify system..." << endl;
+  return God->resolver()->verifySystem();
+}
+
+static void make_solver_test_case(Zypper & zypper)
+{
+  set_force_resolution(zypper);
+  set_no_recommends(zypper);
+  set_ignore_recommends_of_installed(zypper);
+
+  string testcase_dir("/var/log/zypper.solverTestCase");
+
+  zypper.out().info(_("Generating solver test case..."));
+  if (God->resolver()->createSolverTestcase(testcase_dir))
+    zypper.out().info(boost::str(
+      format(_("Solver test case generated successfully at %s."))
+        % testcase_dir));
+  else
+  {
+    zypper.out().error(_("Error creating the solver test case."));
+    zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+  }
+}
+
+// ----------------------------------------------------------------------------
+// commit
+// ----------------------------------------------------------------------------
+
+/**
+ * @return ZYPPER_EXIT_OK - successful commit,
+ *  ZYPPER_EXIT_ERR_ZYPP - if ZYppCommitResult contains resolvables with errors,
+ *  ZYPPER_EXIT_INF_REBOOT_NEEDED - if one of patches to be installed needs machine reboot,
+ *  ZYPPER_EXIT_INF_RESTART_NEEDED - if one of patches to be installed needs package manager restart
+ */
+void solve_and_commit (Zypper & zypper)
+{
+  if (zypper.cOpts().count("debug-solver"))
+  {
+    make_solver_test_case(zypper);
+    return;
+  }
+
+  bool show_forced_problems = true;
+  bool commit_done = false;
+  do
+  {
+    if (zypper.runtimeData().solve_before_commit) // doUpdate was called, no need for solving
+    {
+      MIL << "solving..." << endl;
+
+      while (true)
+      {
+        bool success;
+        if (zypper.command() == ZypperCommand::VERIFY)
+          success = verify(zypper);
+        else if (zypper.command() == ZypperCommand::DIST_UPGRADE)
+        {
+          zypp::UpgradeStatistics opt_stats;
+          //! \todo set success to doUpgrade return value if there are problems
+          success = false;
+          God->resolver()->doUpgrade(opt_stats);
+          //! \todo remove this hack once the doUpgrade returns bool
+          if (God->resolver()->problems().empty())
+            break;
+        }
+        else
+          success = resolve(zypper);
+        if (success)
+          break;
+
+        success = show_problems(zypper);
+        if (! success) {
+          // TODO cancel transaction?
+          zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP); // #242736
+          return;
+        }
+      }
+    }
+
+    MIL << "got solution, showing summary" << endl;
+
+    // returns SUMMARY_*
+    int retv = summary(zypper);
+    if (retv != SUMMARY_NOTHING_TO_DO || !zypper.runtimeData().srcpkgs_to_install.empty())
+    {
+      // check root user
+      if (zypper.command() == ZypperCommand::VERIFY && geteuid() != 0
+        && !zypper.globalOpts().changedRoot)
+      {
+        zypper.out().error(
+          _("Root privileges are required to fix broken package dependencies."));
+        zypper.setExitCode(ZYPPER_EXIT_ERR_PRIVILEGES);
+        return;
+      }
+  
+      bool do_commit = false;
+      if (zypper.runtimeData().force_resolution &&
+          (retv == SUMMARY_INSTALL_DOES_REMOVE || retv == SUMMARY_REMOVE_DOES_INSTALL))
+      {
+        PromptOptions popts;
+        // translators: Yes / No / show Problems. This prompt will appear
+        // after install/update command summary if there will be any package
+        // to-be-removed automatically to show why, if asked.
+        popts.setOptions(_("y/n/p"), 0);
+        // translators: help text for 'y' option in the y/n/p prompt
+        popts.setOptionHelp(0, _("Accept the summary and proceed with installation/removal of packages."));
+        // translators: help text for 'n' option in the y/n/p prompt
+        popts.setOptionHelp(1, _("Cancel the operation."));
+        // translators: help text for 'p' option in the y/n/p prompt
+        popts.setOptionHelp(2, _("Restart solver in no-force-resolution mode in order to show dependency problems."));
+        string prompt_text = _("Continue?");
+        zypper.out().prompt(PROMPT_YN_INST_REMOVE_CONTINUE, prompt_text, popts);
+        unsigned int reply =
+          get_prompt_reply(zypper, PROMPT_YN_INST_REMOVE_CONTINUE, popts);
+
+        if (reply == 2)
+        {
+          // one more solver solver run with force-resoltion off
+          zypper.runtimeData().force_resolution = false;
+          // undo solver changes before retrying
+          God->resolver()->undo();
+          continue;
+        }
+        else if (reply == 1)
+          show_forced_problems = false;
+        else
+        {
+          do_commit = true;
+          show_forced_problems = false;
+        }
+      }
+      // no dependency problems
+      else
+      {
+        do_commit = read_bool_answer(PROMPT_YN_INST_REMOVE_CONTINUE, _("Continue?"), true);
+        show_forced_problems = false;
+      }
+
+      if (do_commit)
+      {
+        if (!confirm_licenses(zypper))
+          return;
+
+        if (retv >= 0)
+        {
+          try
+          {
+            gData.show_media_progress_hack = true;
+    
+            ostringstream s;
+            s << _("committing"); MIL << "committing...";
+    
+            ZYppCommitResult result;
+            if (copts.count("dry-run"))
+            {
+              s << " " << _("(dry run)") << endl; MIL << "(dry run)";
+              zypper.out().info(s.str(), Out::HIGH);
+    
+              result = God->commit(ZYppCommitPolicy().dryRun(true));
+            }
+            else
+            {
+              zypper.out().info(s.str(), Out::HIGH);
+    
+              result = God->commit(
+                ZYppCommitPolicy().syncPoolAfterCommit(zypper.runningShell()));
+    
+              commit_done = true;
+            }
+
+
+            MIL << endl << "DONE" << endl;
+
+            gData.show_media_progress_hack = false;
+
+            if (!result._errors.empty())
+              retv = ZYPPER_EXIT_ERR_ZYPP;
+    
+            s.clear(); s << result;
+            zypper.out().info(s.str(), Out::HIGH);
+          }
+          catch ( const media::MediaException & e ) {
+            ZYPP_CAUGHT(e);
+            zypper.out().error(e,
+                _("Problem downloading the package file from the repository:"),
+                _("Please see the above error message for a hint."));
+            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+            return;
+          }
+          catch ( zypp::repo::RepoException & e ) {
+            ZYPP_CAUGHT(e);
+            
+            RepoManager manager(zypper.globalOpts().rm_options );
+  
+            bool refresh_needed = false;
+            for(RepoInfo::urls_const_iterator it = e.info().baseUrlsBegin();
+                      it != e.info().baseUrlsEnd(); ++it)
+              {
+                RepoManager::RefreshCheckStatus stat = manager.
+                              checkIfToRefreshMetadata(e.info(), *it,
+                              RepoManager::RefreshForced );
+                if ( stat == RepoManager::REFRESH_NEEDED )
+                {
+                  refresh_needed = true;
+                  break;
+                }
+              }
+            
+            std::string hint = _("Please see the above error message for a hint.");
+            if (refresh_needed)
+            {
+              hint = boost::str(format(
+                  // translators: the first %s is 'zypper refresh' and the second
+                  // is repo allias
+                  _("Repository '%s' is out of date. Running '%s' might help.")) %
+                  e.info().alias() % "zypper refresh" );
+            }
+            zypper.out().error(e,
+                _("Problem downloading the package file from the repository:"),
+                hint);
+            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+            return;
+          }
+          catch ( const zypp::FileCheckException & e ) {
+            ZYPP_CAUGHT(e);
+            zypper.out().error(e,
+                _("The package integrity check failed. This may be a problem"
+                " with the repository or media. Try one of the following:\n"
+                "\n"
+                "- just retry previous command\n"
+                "- refresh the repositories using 'zypper refresh'\n"
+                "- use another installation medium (if e.g. damaged)\n"
+                "- use another repository"));
+            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+            return;
+          }
+          catch ( const Exception & e ) {
+            ZYPP_CAUGHT(e);
+            zypper.out().error(e,
+                _("Problem occured during or after installation or removal of packages:"),
+                _("Please see the above error message for a hint."));
+            zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+          }
+        }
+        // install any pending source packages
+        if (!zypper.runtimeData().srcpkgs_to_install.empty())
+          install_src_pkgs(zypper);
+      }
+    }
+    // noting to do
+    else
+      break;
+  }
+  while (show_forced_problems);
+
+  if (commit_done)
+  {
+    if (zypper.exitCode() == ZYPPER_EXIT_INF_REBOOT_NEEDED)
+      zypper.out().warning(
+        _("One of installed patches requires reboot of"
+          " your machine. Reboot as soon as possible."), Out::QUIET);
+    else if (zypper.exitCode() == ZYPPER_EXIT_INF_RESTART_NEEDED)
+      zypper.out().warning(
+        _("One of installed patches affects the package"
+          " manager itself, thus it requires its restart before executing"
+          " any further operations."),
+        Out::QUIET, Out::TYPE_NORMAL); // don't show this to machines
+  }
+}
diff --git a/src/solve-commit.h b/src/solve-commit.h
new file mode 100755 (executable)
index 0000000..74301ba
--- /dev/null
@@ -0,0 +1,41 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+
+/**
+ * Solve and commit code.
+ *
+ * This part is responsible for calling the solver, feeding the result back
+ * to the user in form of dependency problem dialogue and installation summary,
+ * and calling commit to do actually do what has been written in the summary. 
+ */
+#ifndef SOLVE_COMMIT_H_
+#define SOLVE_COMMIT_H_
+
+#include "Zypper.h"
+
+
+/**
+ * Run the solver.
+ * 
+ * \return <tt>true</tt> if a solution has been found, <tt>false</tt> otherwise 
+ */
+bool resolve(Zypper & zypper);
+
+
+/**
+ * Runs solver on the pool, asks to choose solution of eventual problems
+ * (when run interactively) and commits the result.
+ * 
+ * \param have_extra_deps ?
+ * \return ZYPPER_EXIT_INF_REBOOT_NEEDED, ZYPPER_EXIT_INF_RESTART_NEEDED,
+ *         or ZYPPER_EXIT_OK or ZYPPER_EXIT_ERR_ZYPP on zypp erorr. 
+ *  
+ */
+void solve_and_commit(Zypper & zypper);
+
+
+#endif /*SOLVE_COMMIT_H_*/
diff --git a/src/update.cc b/src/update.cc
new file mode 100755 (executable)
index 0000000..e31b68c
--- /dev/null
@@ -0,0 +1,690 @@
+#include <iostream> // for xml and table output
+#include <sstream>
+#include <boost/format.hpp>
+
+#include "zypp/base/Logger.h"
+#include "zypp/ZYppFactory.h"
+#include "zypp/base/Algorithm.h"
+#include "zypp/PoolQuery.h"
+
+#include "zypp/Patch.h"
+
+//#include "utils.h"
+#include "Table.h"
+#include "update.h"
+
+using namespace std;
+using namespace zypp;
+using namespace boost;
+
+extern ZYpp::Ptr God;
+
+
+// ----------------------------------------------------------------------------
+//
+// Updates
+//
+// The following scenarios are handled distinctly:
+// * -t patch (default), no arguments
+// * -t package, no arguments
+//   - uses Resolver::doUpdate()
+// * -t {other}, no arguments
+// * -t patch foo
+// * -t package foo
+//   - addRequires(>installed-version) if available
+// * -t {other} foo
+//   - addRequires(>installed-version) if available
+//
+// update summary must correspond to list-updates and patch-check
+// ----------------------------------------------------------------------------
+
+void patch_check ()
+{
+  Out & out = Zypper::instance()->out();
+
+  DBG << "patch check" << endl;
+  gData.patches_count = gData.security_patches_count = 0;
+
+  ResPool::byKind_iterator
+    it = God->pool().byKindBegin(ResKind::patch),
+    e = God->pool().byKindEnd(ResKind::patch);
+  for (; it != e; ++it )
+  {
+    ResObject::constPtr res = it->resolvable();
+    Patch::constPtr patch = asKind<Patch>(res);
+
+    if (it->isRelevant() && !it->isSatisfied())
+    {
+      gData.patches_count++;
+      if (patch->category() == "security")
+        gData.security_patches_count++;
+    }
+  }
+
+  ostringstream s;
+  // translators: %d is the number of needed patches
+  s << format(_PL("%d patch needed", "%d patches needed", gData.patches_count))
+      % gData.patches_count
+    << " ("
+    // translators: %d is the number of security patches
+    << format(_PL("%d security patch", "%d security patches", gData.security_patches_count))
+      % gData.security_patches_count
+    << ")";
+  out.info(s.str(), Out::QUIET);
+}
+
+// ----------------------------------------------------------------------------
+
+// returns true if restartSuggested() patches are availble
+bool xml_list_patches ()
+{
+  const zypp::ResPool& pool = God->pool();
+
+  unsigned int patchcount=0;
+  bool pkg_mgr_available = false;
+  Patch::constPtr patch;
+
+  ResPool::byKind_iterator
+    it = pool.byKindBegin(ResKind::patch),
+    e  = pool.byKindEnd(ResKind::patch);
+
+  // check whether there are packages affecting the update stack
+  for (; it != e; ++it)
+  {
+    patch = asKind<Patch>(it->resolvable());
+    if (it->isRelevant() && !it->isSatisfied() && patch->restartSuggested())
+    {
+      pkg_mgr_available = true;
+      break;
+    }
+  }
+
+  it = pool.byKindBegin(ResKind::patch);
+  for (; it != e; ++it, ++patchcount)
+  {
+    if (it->isRelevant() && !it->isSatisfied())
+    {
+      ResObject::constPtr res = it->resolvable();
+      Patch::constPtr patch = asKind<Patch>(res);
+
+      // if updates stack patches are available, show only those
+      if ((pkg_mgr_available && patch->restartSuggested()) || !pkg_mgr_available)
+      {
+        cout << " <update ";
+        cout << "name=\"" << res->name () << "\" ";
+        cout << "edition=\""  << res->edition ().asString() << "\" ";
+        cout << "category=\"" <<  patch->category() << "\" ";
+        cout << "pkgmanager=\"" << (patch->restartSuggested() ? "true" : "false") << "\" ";
+        cout << "restart=\"" << (patch->rebootSuggested() ? "true" : "false") << "\" ";
+        cout << "interactive=\"" << (patch->interactive() ? "true" : "false") << "\" ";
+        cout << "kind=\"patch\"";
+        cout << ">" << endl;
+        cout << "  <summary>" << xml_encode(patch->summary()) << "  </summary>" << endl;
+        cout << "  <description>" << xml_encode(patch->description()) << "</description>" << endl;
+        cout << "  <license>" << xml_encode(patch->licenseToConfirm()) << "</license>" << endl;
+
+        if ( !patch->repoInfo().alias().empty() )
+        {
+          cout << "  <source url=\"" << xml_encode(patch->repoInfo().baseUrlsBegin()->asString());
+          cout << "\" alias=\"" << xml_encode(patch->repoInfo().alias()) << "\"/>" << endl;
+        }
+
+        cout << " </update>" << endl;
+      }
+    }
+  }
+
+  if (patchcount == 0)
+    cout << "<appletinfo status=\"no-update-repositories\"/>" << endl;
+
+  return pkg_mgr_available;
+}
+
+// ----------------------------------------------------------------------------
+
+static void list_patch_updates(Zypper & zypper)
+{
+  Table tbl;
+  Table pm_tbl; // only those that affect packagemanager (restartSuggested()), they have priority
+  TableHeader th;
+  unsigned cols;
+
+  th << (zypper.globalOpts().is_rug_compatible ? _("Catalog") : _("Repository"))
+     << _("Name") << _("Version") << _("Category") << _("Status");
+  cols = 5;
+  tbl << th;
+  pm_tbl << th;
+
+  const zypp::ResPool& pool = God->pool();
+  ResPool::byKind_iterator
+    it = pool.byKindBegin(ResKind::patch),
+    e  = pool.byKindEnd(ResKind::patch);
+  for (; it != e; ++it )
+  {
+    ResObject::constPtr res = it->resolvable();
+
+    if ( it->isRelevant() && ! it->isSatisfied() )
+    {
+      Patch::constPtr patch = asKind<Patch>(res);
+
+      {
+        TableRow tr (cols);
+        tr << patch->repoInfo().name();
+        tr << res->name () << res->edition ().asString();
+        tr << patch->category();
+        tr <<  _("Needed");        
+
+        if (patch->restartSuggested ())
+          pm_tbl << tr;
+        else
+          tbl << tr;
+      }
+    }
+  }
+
+  // those that affect the package manager go first
+  // (TODO: user option for this?)
+  if (!pm_tbl.empty ())
+  {
+    if (!tbl.empty ())
+      zypper.out().warning(
+        _("These are only the updates affecting the updater itself.\n"
+          "Other updates are available too.\n"));
+    tbl = pm_tbl;
+  }
+
+  tbl.sort (1);                 // Name
+
+  if (tbl.empty())
+    zypper.out().info(_("No updates found."));
+  else
+    cout << tbl;
+}
+
+// ----------------------------------------------------------------------------
+
+// collect items, select best edition
+//   this is used to find best available or installed.
+// The name of the class is a bit misleading though ...
+
+class LookForArchUpdate : public zypp::resfilter::PoolItemFilterFunctor
+{
+public:
+  PoolItem best;
+
+  bool operator()( PoolItem provider )
+    {
+      if (!provider.status().isLocked() // is not locked (taboo)
+          && (!best                     // first match
+              // or a better edition than candidate
+              || best->edition().compare( provider->edition() ) < 0))
+      {
+        best = provider;        // store
+      }
+      return true;              // keep going
+    }
+};
+
+// ----------------------------------------------------------------------------
+
+// Find best (according to edition) uninstalled item
+// with same kind/name/arch as item.
+// Similar to zypp::solver::detail::Helper::findUpdateItem
+// but that allows changing the arch (#222140).
+static
+PoolItem
+findArchUpdateItem( const ResPool & pool, PoolItem item )
+{
+  LookForArchUpdate info;
+
+  invokeOnEach( pool.byIdentBegin( item->kind(), item->name() ),
+                pool.byIdentEnd( item->kind(), item->name() ),
+                // get uninstalled, equal kind and arch, better edition
+                functor::chain (
+                  functor::chain (
+                    resfilter::ByUninstalled (),
+                    resfilter::byArch<CompareByEQ<Arch> >( item->arch() ) ),
+                  resfilter::byEdition<CompareByGT<Edition> >( item->edition() )),
+                functor::functorRef<bool,PoolItem> (info) );
+
+  _XDEBUG("findArchUpdateItem(" << item << ") => " << info.best);
+  return info.best;
+}
+
+// ----------------------------------------------------------------------------
+
+typedef set<PoolItem> Candidates;
+
+/**
+ * Find all available updates of given kind.
+ */
+static void
+find_updates( const ResKind & kind, Candidates & candidates )
+{
+  const zypp::ResPool& pool = God->pool();
+  ResPool::byKind_iterator
+    it = pool.byKindBegin (kind),
+    e  = pool.byKindEnd (kind);
+  DBG << "Looking for update candidates of kind " << kind << endl;
+  for (; it != e; ++it)
+  {
+    if (it->status().isUninstalled())
+      continue;
+    // (actually similar to ProvideProcess?)
+    PoolItem candidate = findArchUpdateItem( pool, *it );
+    if (!candidate.resolvable())
+      continue;
+
+    DBG << "item " << *it << endl;
+    DBG << "cand " << candidate << endl;
+    candidates.insert (candidate);
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Find all available updates of given kinds.
+ */
+static void
+find_updates( const ResKindSet & kinds, Candidates & candidates )
+{
+  for (ResKindSet::const_iterator kit = kinds.begin(); kit != kinds.end(); ++kit)
+    find_updates(*kit, candidates);
+
+  if (kinds.empty())
+    WAR << "called with empty kinds set" << endl;
+}
+
+// ----------------------------------------------------------------------------
+
+string i18n_kind_updates(const ResKind & kind)
+{
+  if (kind == ResTraits<Package>::kind)
+    return _("Package updates");
+  else if (kind == ResTraits<Patch>::kind)
+    return _("Patches");
+  else if (kind == ResTraits<Pattern>::kind)
+    return _("Pattern updates");
+  else if (kind == ResTraits<Product>::kind)
+    return _("Product updates");
+
+  return boost::str(format("%s updates") % kind);
+}
+
+// ----------------------------------------------------------------------------
+
+void list_updates(Zypper & zypper, const ResKindSet & kinds, bool best_effort)
+{
+  if (zypper.out().type() == Out::TYPE_XML)
+  {
+    cout << "<update-status version=\"0.6\">" << endl;
+    cout << "<update-list>" << endl;
+  }
+  bool not_affects_pkgmgr = false;
+
+  unsigned kind_size = kinds.size();
+  ResKindSet localkinds = kinds;
+  ResKindSet::iterator it;
+
+  // patch updates
+  it = localkinds.find(ResKind::patch);
+  if(it != localkinds.end())
+  {
+    if (zypper.out().type() == Out::TYPE_XML)
+      not_affects_pkgmgr = !xml_list_patches();
+    else
+    {
+      zypper.out().info(i18n_kind_updates(*it), Out::QUIET, Out::TYPE_NORMAL);
+      zypper.out().info("", Out::QUIET, Out::TYPE_NORMAL); // visual separator
+      list_patch_updates(zypper);
+    }
+    localkinds.erase(it);
+  }
+
+  // other kinds
+  //! \todo list package updates according to Resolver::doUpdate()
+  if (zypper.out().type() == Out::TYPE_XML)
+  {
+    if (not_affects_pkgmgr)
+      xml_list_updates(localkinds);
+    cout << "</update-list>" << endl;
+    cout << "</update-status>" << endl;
+    return;
+  }
+
+  for (it = localkinds.begin(); it != localkinds.end(); ++it)
+  {
+    Table tbl;
+
+    // show repo only if not best effort or --from-repo set
+    // on best_effort, the solver will determine the repo if we don't limit it to a specific one
+    bool hide_repo = best_effort || copts.count("repo");
+
+    // header
+    TableHeader th;
+    unsigned int name_col;
+    // TranslatorExplanation S stands for Status
+    th << _("S");
+    if (!hide_repo) {
+      th << (zypper.globalOpts().is_rug_compatible ? _("Catalog") : _("Repository"));
+    }
+    if (zypper.globalOpts().is_rug_compatible) {
+      th << _("Bundle");
+    }
+    name_col = th.cols();
+    th << _("Name");
+    if (!best_effort) {         // best_effort does not know version or arch yet
+      th << _("Version") << _("Arch");
+    }
+    tbl << th;
+
+    unsigned int cols = th.cols();
+
+    Candidates candidates;
+    find_updates( *it, candidates );
+
+    Candidates::iterator cb = candidates.begin (), ce = candidates.end (), ci;
+    for (ci = cb; ci != ce; ++ci) {
+//      ResStatus& candstat = ci->status();
+//      candstat.setToBeInstalled (ResStatus::USER);
+      ResObject::constPtr res = ci->resolvable();
+      TableRow tr (cols);
+      tr << "v";
+      if (!hide_repo) {
+        tr << res->repoInfo().name();
+      }
+      if (zypper.globalOpts().is_rug_compatible)
+        tr << "";               // Bundle
+      tr << res->name ();
+
+      // strictly speaking, we could show version and arch even in best_effort
+      //  iff there is only one candidate. But we don't know the number of candidates here.
+      if (!best_effort) {
+         tr << res->edition ().asString ()
+            << res->arch ().asString ();
+      }
+      tbl << tr;
+    }
+    tbl.sort( name_col );
+
+    if (kind_size > 1)
+    {
+      zypper.out().info("", Out::QUIET, Out::TYPE_NORMAL); // visual separator
+      zypper.out().info(i18n_kind_updates(*it), Out::QUIET, Out::TYPE_NORMAL);
+      zypper.out().info("", Out::QUIET, Out::TYPE_NORMAL); // visual separator
+    }
+
+    if (tbl.empty())
+      zypper.out().info(_("No updates found."));
+    else
+      cout << tbl;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+// may be useful as a functor
+static bool
+mark_item_install (const PoolItem & pi)
+{
+  bool result = pi.status().setToBeInstalled( zypp::ResStatus::USER );
+  if (!result)
+    ERR << "Marking " << pi << "for installation failed" << endl;
+  return result;
+}
+
+// ----------------------------------------------------------------------------
+// best-effort update
+// ----------------------------------------------------------------------------
+
+// find installed item matching passed one
+//   use LookForArchUpdate as callback handler in order to cope with
+//   multiple installed resolvables of the same name.
+//   LookForArchUpdate will return the one with the highest edition.
+
+static PoolItem
+findInstalledItem( PoolItem item )
+{
+  const zypp::ResPool& pool = God->pool();
+  LookForArchUpdate info;
+
+  invokeOnEach( pool.byIdentBegin( item->kind(), item->name() ),
+                pool.byIdentEnd( item->kind(), item->name() ),
+                resfilter::ByInstalled (),
+                functor::functorRef<bool,PoolItem> (info) );
+
+  _XDEBUG("findInstalledItem(" << item << ") => " << info.best);
+  return info.best;
+}
+
+// ----------------------------------------------------------------------------
+
+// require update of installed item
+//   The PoolItem passed to require_item_update() is the installed resolvable
+//   to which an update candidate is guaranteed to exist.
+//
+// may be useful as a functor
+
+static bool require_item_update (const PoolItem& pi) {
+  Resolver_Ptr resolver = zypp::getZYpp()->resolver();
+
+  PoolItem installed = findInstalledItem( pi );
+
+  // require anything greater than the installed version
+  try {
+    Capability  cap( installed->name(), Rel::GT, installed->edition(), installed->kind() );
+    resolver->addRequire( cap );
+  }
+  catch (const Exception& e) {
+    ZYPP_CAUGHT(e);
+    Zypper::instance()->out().error(boost::str(format(
+      _("Cannot parse '%s < %s'")) % installed->name() % installed->edition()));
+  }
+
+  return true;
+}
+
+// ----------------------------------------------------------------------------
+
+void xml_list_updates(const ResKindSet & kinds)
+{
+  Candidates candidates;
+  find_updates (kinds, candidates);
+
+  Candidates::iterator cb = candidates.begin (), ce = candidates.end (), ci;
+  for (ci = cb; ci != ce; ++ci) {
+    ResObject::constPtr res = ci->resolvable();
+
+    cout << " <update ";
+    cout << "name=\"" << res->name () << "\" " ;
+    cout << "edition=\""  << res->edition ().asString() << "\" ";
+    cout << "kind=\"" << res->kind() << "\" ";
+    cout << ">" << endl;
+    cout << "  <summary>" << xml_encode(res->summary()) << "  </summary>" << endl;
+    cout << "  <description>" << xml_encode(res->description()) << "</description>" << endl;
+    cout << "  <license>" << xml_encode(res->licenseToConfirm()) << "</license>" << endl;
+
+    if ( !res->repoInfo().alias().empty() )
+    {
+        cout << "  <source url=\"" << xml_encode(res->repoInfo().baseUrlsBegin()->asString());
+        cout << "\" alias=\"" << xml_encode(res->repoInfo().alias()) << "\"/>" << endl;
+    }
+
+    cout << " </update>" << endl;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+static bool
+mark_patch_update(const PoolItem & pi, bool skip_interactive, bool ignore_affects_pm)
+{
+  Patch::constPtr patch = asKind<Patch>(pi.resolvable());
+  if (pi.isRelevant() && !pi.isSatisfied())
+  {
+    DBG << "patch " << patch->name() << " " << ignore_affects_pm << ", "
+      << patch->restartSuggested() << endl;
+    if (ignore_affects_pm || patch->restartSuggested())
+    {
+      // #221476
+      if (skip_interactive
+          && (patch->interactive() || !patch->licenseToConfirm().empty()))
+      {
+        // Skipping a patch because it is marked as interactive or has
+        // license to confirm and --skip-interactive is requested.
+        Zypper::instance()->out().warning(str::form(
+          // translators: %s is the name of a patch
+          _("'%s' is interactive, skipping."), patch->name().c_str()));
+        return false;
+      }
+      else
+      {
+        mark_item_install(pi);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+// ----------------------------------------------------------------------------
+
+static void
+mark_patch_updates( Zypper & zypper, bool skip_interactive )
+{
+  DBG << "going to mark patches to install" << endl;
+
+  // search twice: if there are none with restartSuggested(), retry on all
+  bool any_marked = false;
+  for(unsigned ignore_affects_pm = 0;
+      !any_marked && ignore_affects_pm < 2; ++ignore_affects_pm)
+  {
+    if (zypper.arguments().empty() || zypper.globalOpts().is_rug_compatible)
+    {
+      DBG << "marking all needed patches" << endl;
+
+      for_(it, God->pool().byKindBegin(ResKind::patch), 
+               God->pool().byKindEnd  (ResKind::patch))
+      {
+        if (mark_patch_update(*it, skip_interactive, ignore_affects_pm))
+          any_marked = true;
+      }
+    }
+    else if (!zypper.arguments().empty())
+    {
+      for_(it, zypper.arguments().begin(), zypper.arguments().end())
+      {
+        // look for patches matching specified pattern
+        PoolQuery q;
+        q.addKind(ResKind::patch);
+        q.addAttribute(sat::SolvAttr::name, *it);
+        //! \todo should we look for patches requiring packages with matching name instead? 
+        //q.addAttribute(sat::SolvAttr::require, *it);
+        q.setMatchGlob();
+
+        if (q.empty())
+        {
+          if (ignore_affects_pm) // avoid displaying this twice
+            continue;
+          if (it->find_first_of("?*") != string::npos) // wildcards used
+            zypper.out().info(str::form(
+                _("No patches matching '%s' found."), it->c_str()));
+          else
+            zypper.out().info(str::form(
+                _("Patch '%s' not found."), it->c_str()));
+          zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
+        }
+        else
+        {
+          for_(pit, q.poolItemBegin(), q.poolItemEnd())
+          {
+            any_marked = mark_patch_update(*pit, skip_interactive, ignore_affects_pm);
+          }
+        }
+      }
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+void mark_updates(Zypper & zypper, const ResKindSet & kinds, bool skip_interactive, bool best_effort )
+{
+  ResKindSet localkinds = kinds;
+
+  if (zypper.arguments().empty() || zypper.globalOpts().is_rug_compatible)
+  {
+    for_(kindit, localkinds.begin(), localkinds.end())
+    {
+      if (*kindit == ResKind::package)
+      {
+        // this will do a complete pacakge update as far as possible
+        God->resolver()->doUpdate();
+        // no need to call Resolver::resolvePool() afterwards
+        zypper.runtimeData().solve_before_commit = false;
+      }
+      else if (*kindit == ResKind::patch)
+      {
+        mark_patch_updates(zypper, skip_interactive);
+      }
+      else
+      {
+        Candidates candidates;
+        find_updates (localkinds, candidates);
+        if (best_effort)
+          invokeOnEach (candidates.begin(), candidates.end(), require_item_update);
+        else
+          invokeOnEach (candidates.begin(), candidates.end(), mark_item_install);
+      } 
+    }
+  }
+  // treat arguments as package names (+allow wildcards)
+  else if (!zypper.arguments().empty())
+  {
+    for_(kindit, localkinds.begin(), localkinds.end())
+    {
+      Resolver_Ptr solver = God->resolver();
+      for_(it, zypper.arguments().begin(), zypper.arguments().end())
+      {
+        PoolQuery q;
+        q.addKind(*kindit);
+        q.addAttribute(sat::SolvAttr::name, *it);
+        q.setMatchGlob();
+        q.setInstalledOnly();
+  
+        if (q.empty())
+        {
+          if (it->find_first_of("?*") != string::npos) // wildcards used
+            zypper.out().info(str::form(
+                _("No packages matching '%s' are installed."), it->c_str()));
+          else
+            zypper.out().info(str::form(
+                _("Package '%s' is not installed."), it->c_str()));
+          zypper.setExitCode(ZYPPER_EXIT_INF_CAP_NOT_FOUND);
+        }
+        else
+          for_(solvit, q.selectableBegin(), q.selectableEnd())
+          {
+            ui::Selectable::Ptr s = *solvit;
+            PoolItem theone = s->theObj();
+            if (equalNVRA(*s->installedObj().resolvable(), *theone.resolvable()))
+            {
+              DBG << "the One (" << theone << ") is installed, skipping." << endl;
+              zypper.out().info(str::form(
+                  _("No update candidate for '%s'."), s->name().c_str()));
+            }
+            else
+            {
+              //s->setCandidate(theone); ?
+              //s->setStatus(ui::S_Update); ?
+              Capability c(s->name(), Rel::GT, s->installedObj()->edition(), s->kind());
+              solver->addRequire(c);
+              DBG << *s << " update: adding requirement " << c << endl;
+            }
+          }
+      }
+    }
+  }
+}
diff --git a/src/update.h b/src/update.h
new file mode 100755 (executable)
index 0000000..28948d6
--- /dev/null
@@ -0,0 +1,36 @@
+#include "Zypper.h"
+
+#include "utils.h"
+
+/**
+ * Are there applicable patches?
+ */
+void patch_check();
+
+/**
+ * Lists available updates of installed resolvables of specified \a kind.
+ * if repo_alias != "", restrict updates to this repository.
+ * if best_effort == true, any version greater than the installed one will do.
+ * Prints the table of updates to stdout.
+ * 
+ * \param kind  resolvable type
+ * \param best_effort
+ */
+void list_updates(Zypper & zypper,
+                  const ResKindSet & kinds,
+                  bool best_effort);
+
+/** \todo remove from this header after xu is dropped */ 
+bool xml_list_patches();
+/** \todo remove from this header after xu is dropped */
+void xml_list_updates(const ResKindSet & kinds);
+
+/**
+ * \param kind  resolvable type
+ * \param skip_interactive whether to skip updates that need user interaction
+ * \param best_effort
+ */
+void mark_updates(Zypper & zypper,
+                  const ResKindSet & kinds,
+                  bool skip_interactive,
+                  bool best_effort);
diff --git a/src/utils/pager.cc b/src/utils/pager.cc
new file mode 100755 (executable)
index 0000000..226b225
--- /dev/null
@@ -0,0 +1,91 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <errno.h>
+#include <sys/wait.h> //for wait()
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+#include "zypp/TmpPath.h"
+
+#include "../main.h"
+
+#include "pager.h"
+
+using namespace std;
+using namespace zypp;
+
+string pager_help_exit(const string & pager)
+{
+  string endfour = pager.substr(pager.size()-4,4);
+  if (endfour == "less")
+  {
+    return str::form(_("Press '%c' to exit the pager."), 'q');
+  }
+  return string();
+}
+
+string pager_help_navigation(const string & pager)
+{
+  string endfour = pager.substr(pager.size()-4,4);
+  if (endfour == "less")
+  {
+    return _("Use arrows or pgUp/pgDown keys to scroll the text by lines or pages.");
+  }
+  else if (endfour == "more")
+  {
+    return _("Use the Enter or Space key to scroll the text by lines or pages.");
+  }
+  return string();
+}
+
+//gets true if successfully display in pager
+bool show_in_pager(const string & text)
+{
+  const char* envpager = getenv("PAGER");
+  if (!envpager)
+    envpager="more"; //basic posix default, must be in PATH
+  string pager(envpager);
+  filesystem::TmpFile tfile;
+  string tpath = tfile.path().absolutename().c_str();
+  ofstream os(tpath.c_str());
+
+  string help = pager_help_navigation(pager);
+  if (!help.empty())
+    os << "(" << help << ")" << endl << endl;
+  os << text;
+
+  help = pager_help_exit(pager);
+  if (!help.empty())
+    os << endl << endl << "(" << help << ")";
+  os.close();
+
+  ostringstream cmdline;
+  cmdline << pager <<" "<<tpath;
+
+  switch(fork())
+  {
+  case -1:
+    WAR << "fork failed" << endl;
+    return false;
+
+  case 0:
+    execlp("sh","sh","-c",cmdline.str().c_str(),(char *)0);
+    WAR << "exec failed with " << strerror(errno) << endl;
+    exit(1); // cannot return false here, because here is another process
+             // so only kill myself
+             //! \todo FIXME proper exit code, message?
+
+  default: 
+    wait(0); //wait until pager end to disallow possibly terminal collision
+  }
+
+  return true;
+}
diff --git a/src/utils/pager.h b/src/utils/pager.h
new file mode 100755 (executable)
index 0000000..02895ba
--- /dev/null
@@ -0,0 +1,15 @@
+/*---------------------------------------------------------------------------*\
+                          ____  _ _ __ _ __  ___ _ _
+                         |_ / || | '_ \ '_ \/ -_) '_|
+                         /__|\_, | .__/ .__/\___|_|
+                             |__/|_|  |_|
+\*---------------------------------------------------------------------------*/
+
+#ifndef PAGER_H_
+#define PAGER_H_
+
+#include <string>
+
+bool show_in_pager(const std::string & text);
+
+#endif /*PAGER_H_*/