From 2ae3dfcad9058bd6798390a914621eb8461f4751 Mon Sep 17 00:00:00 2001 From: Klaus Kaempf Date: Thu, 26 Jul 2007 15:15:18 +0000 Subject: [PATCH] implement "--best-effort" for "upgrade" - pick up libzypp 3.12.0 fix for resolvePool() to not remove extra dependencies on start (have_extra_deps parameter to solve_and_commit() and resolve()) - rename 'uninstalled' to 'best' in LookForArchUpdate to match semantics - add findInstalledItem callback to find the installed resolvable matching an upgrade candidate in kind and name - on 'best-effort', dont mark explicit uninstalled resolvables for installation but inject "installed-name > installed-version" requirements into the solver if there are one or more update candidates for 'installed' --- src/zypper-misc.cc | 91 ++++++++++++++++++++++++++++++++++++++++++++++-------- src/zypper-misc.h | 4 +-- src/zypper.cc | 2 +- 3 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/zypper-misc.cc b/src/zypper-misc.cc index a93f28a..9308335 100644 --- a/src/zypper-misc.cc +++ b/src/zypper-misc.cc @@ -9,6 +9,9 @@ #include #include #include + +#include + #include #include "zypper.h" @@ -499,10 +502,13 @@ void establish () dump_pool (); } -bool resolve() +bool resolve( bool have_extra_deps ) { establish (); cerr_v << _("Resolving dependencies...") << endl; + if (have_extra_deps) + return God->resolver()->resolvePool( true, true ); + return God->resolver()->resolvePool(); } @@ -709,11 +715,14 @@ void list_patch_updates( const string &repo_alias, bool best_effort ) // ---------------------------------------------------------------------------- -// collect items, select best edition. +// 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_Ref uninstalled; + PoolItem_Ref best; string _repo_alias; LookForArchUpdate( const string &repo_alias = "" ) @@ -724,13 +733,13 @@ public: bool operator()( PoolItem_Ref provider ) { if (!provider.status().isLocked() // is not locked (taboo) - && (!uninstalled // first match + && (!best // first match // or a better edition than candidate - || uninstalled->edition().compare( provider->edition() ) < 0) + || best->edition().compare( provider->edition() ) < 0) && (_repo_alias.empty() || provider->repository().info().alias() == _repo_alias) ) { - uninstalled = provider; // store + best = provider; // store } return true; // keep going } @@ -760,8 +769,8 @@ findArchUpdateItem( const ResPool & pool, PoolItem_Ref item, const string &repo_ resfilter::byEdition >( item->edition() )), functor::functorRef (info) ); - _XDEBUG("findArchUpdateItem(" << item << ") => " << info.uninstalled); - return info.uninstalled; + _XDEBUG("findArchUpdateItem(" << item << ") => " << info.best); + return info.best; } // ---------------------------------------------------------------------------- @@ -826,7 +835,7 @@ void list_updates( const ResObject::Kind &kind, const string &repo_alias, bool b unsigned int cols = th.cols(); Candidates candidates; - find_updates( kind, repo_alias, candidates ); // best_effort could be passed here ... + find_updates( kind, repo_alias, candidates ); Candidates::iterator cb = candidates.begin (), ce = candidates.end (), ci; for (ci = cb; ci != ce; ++ci) { @@ -868,6 +877,59 @@ bool mark_item_install (const PoolItem& pi) { 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. + +PoolItem_Ref +findInstalledItem( PoolItem_Ref item ) +{ + const zypp::ResPool& pool = God->pool(); + LookForArchUpdate info; + + invokeOnEach( pool.byNameBegin( item->name() ), + pool.byNameEnd( item->name() ), + // get installed, equal kind + functor::chain ( + resfilter::ByInstalled (), + resfilter::ByKind( item->kind() ) ), + functor::functorRef (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 +bool require_item_update (const PoolItem& pi) { + Resolver_Ptr resolver = zypp::getZYpp()->resolver(); + + PoolItem_Ref installed = findInstalledItem( pi ); + + // require anything greater than the installed version + try { + Capability cap; + cap = CapFactory().parse( installed->kind(), installed->name(), Rel::GT, installed->edition() ); + resolver->addRequire( cap ); + } + catch (const Exception& e) { + ZYPP_CAUGHT(e); + cerr << "Cannot parse '" << installed->name() << " < " << installed->edition() << "'" << endl; + } + + return true; +} + // ---------------------------------------------------------------------------- void xml_list_updates() @@ -950,8 +1012,11 @@ void mark_updates( const ResObject::Kind &kind, const std::string &repo_alias, b } else { Candidates candidates; - find_updates (kind, repo_alias, candidates); // best_effort could be passed here ... - invokeOnEach (candidates.begin(), candidates.end(), mark_item_install); + find_updates (kind, repo_alias, candidates); + if (best_effort) + invokeOnEach (candidates.begin(), candidates.end(), require_item_update); + else + invokeOnEach (candidates.begin(), candidates.end(), mark_item_install); } } @@ -963,9 +1028,9 @@ void mark_updates( const ResObject::Kind &kind, const std::string &repo_alias, b * 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 */ -int solve_and_commit (bool non_interactive) { +int solve_and_commit (bool non_interactive, bool have_extra_deps ) { while (true) { - bool success = resolve(); + bool success = resolve( have_extra_deps ); if (success) break; diff --git a/src/zypper-misc.h b/src/zypper-misc.h index eb9358d..fd15c15 100644 --- a/src/zypper-misc.h +++ b/src/zypper-misc.h @@ -46,7 +46,7 @@ void load_target_resolvables(); void load_repo_resolvables(); void establish (); -bool resolve(); +bool resolve( bool have_extra_deps = false ); void dump_pool (); void show_patches(); void xml_list_patches(); @@ -67,7 +67,7 @@ void patch_check(); void list_updates( const zypp::ResObject::Kind &kind, const std::string &repo_alias, bool best_effort ); void mark_updates( const zypp::ResObject::Kind &kind, const std::string &repo_alias, bool skip_interactive, bool best_effort ); void usage(int argc, char **argv); -int solve_and_commit (bool non_interactive = false); +int solve_and_commit (bool non_interactive = false, bool have_extra_deps = false ); bool confirm_licenses(bool non_interactive = false); // copied from yast2-pkg-bindings:PkgModuleFunctions::DoProvideNameKind diff --git a/src/zypper.cc b/src/zypper.cc index b4991b0..3bd50cb 100644 --- a/src/zypper.cc +++ b/src/zypper.cc @@ -1178,7 +1178,7 @@ int one_command(const ZypperCommand & command, int argc, char **argv) // commit // returns ZYPPER_EXIT_OK, ZYPPER_EXIT_ERR_ZYPP, // ZYPPER_EXIT_INF_REBOOT_NEEDED, or ZYPPER_EXIT_INF_RESTART_NEEDED - return solve_and_commit (copts.count("no-confirm") || gSettings.non_interactive); + return solve_and_commit( copts.count("no-confirm") || gSettings.non_interactive, best_effort ); } // -----------------------------( info )------------------------------------ -- 2.7.4