QueueItemRequire.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* QueueItemRequire.cc
00003  *
00004  * Copyright (C) 2000-2002 Ximian, Inc.
00005  * Copyright (C) 2005 SUSE Linux Products GmbH
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019  * 02111-1307, USA.
00020  */
00021 
00022 #include <sstream>
00023 
00024 #include "zypp/CapFactory.h"
00025 #include "zypp/CapMatch.h"
00026 #include "zypp/CapSet.h"
00027 #include "zypp/base/Logger.h"
00028 #include "zypp/base/String.h"
00029 #include "zypp/base/Gettext.h"
00030 
00031 #include "zypp/base/Algorithm.h"
00032 #include "zypp/ResPool.h"
00033 #include "zypp/ResFilters.h"
00034 #include "zypp/CapFilters.h"
00035 #include "zypp/ResStatus.h"
00036 
00037 #include "zypp/ZYppFactory.h"
00038 
00039 #include "zypp/solver/detail/QueueItemRequire.h"
00040 #include "zypp/solver/detail/QueueItemBranch.h"
00041 #include "zypp/solver/detail/QueueItemUninstall.h"
00042 #include "zypp/solver/detail/QueueItemInstall.h"
00043 #include "zypp/solver/detail/QueueItem.h"
00044 #include "zypp/solver/detail/ResolverContext.h"
00045 #include "zypp/solver/detail/ResolverInfoDependsOn.h"
00046 #include "zypp/solver/detail/ResolverInfoMisc.h"
00047 #include "zypp/solver/detail/ResolverInfoNeededBy.h"
00048 #include "zypp/solver/detail/Helper.h"
00049 
00051 namespace zypp
00052 { 
00053 
00054   namespace solver
00055   { 
00056 
00057     namespace detail
00058     { 
00059 
00060 using namespace std;
00061 
00062 IMPL_PTR_TYPE(QueueItemRequire);
00063 
00064 //---------------------------------------------------------------------------
00065 
00066 std::ostream &
00067 QueueItemRequire::dumpOn( std::ostream & os ) const
00068 {
00069     os << "[" << (_soft?"Soft":"") << "Require: ";
00070     os << _capability;
00071     if (_requiring_item) {
00072         os << ", Required by " << _requiring_item;
00073     }
00074     if (_upgraded_item) {
00075         os << ", Upgrades " << _upgraded_item;
00076     }
00077     if (_lost_item) {
00078         os << ", Lost " << _lost_item;
00079     }
00080     if (_remove_only) os << ", Remove Only";
00081     return os << "]";
00082 }
00083 
00084 //---------------------------------------------------------------------------
00085 
00086 QueueItemRequire::QueueItemRequire (const ResPool & pool, const Capability & cap, bool soft)
00087     : QueueItem (QUEUE_ITEM_TYPE_REQUIRE, pool)
00088     , _capability (cap)
00089     , _soft (soft)
00090     , _remove_only (false)
00091 {
00092     _XDEBUG("QueueItemRequire::QueueItemRequire(" << cap << (soft?", soft":"") << ")");
00093 }
00094 
00095 
00096 QueueItemRequire::~QueueItemRequire()
00097 {
00098 }
00099 
00100 //---------------------------------------------------------------------------
00101 
00102 void
00103 QueueItemRequire::addPoolItem (PoolItem_Ref item)
00104 {
00105     assert (!_requiring_item);
00106     _requiring_item = item;
00107 }
00108 
00109 
00110 //---------------------------------------------------------------------------
00111 struct UniqTable
00112 {
00114   struct Order
00115   {
00117     bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
00118     {
00119       int res = lhs->name().compare( rhs->name() );
00120       if ( res )
00121         return res == -1; // lhs < rhs ?
00122       // here: lhs == rhs, so compare edition:
00123       return lhs->edition() < rhs->edition();
00124     }
00125   };
00127   typedef std::set<PoolItem,Order> UTable;
00128 
00129 
00131   bool has( PoolItem_Ref item_r ) const
00132   { return _table.find( item_r ) != _table.end(); }
00133 
00137   void remember( PoolItem_Ref item_r )
00138   { _table.insert(  item_r ); }
00139 
00140 
00142   UTable _table;
00143 };
00144 //---------------------------------------------------------------------------
00145 
00146 struct RequireProcess
00147 {
00148     PoolItem_Ref _requirer;
00149     const Capability _capability;
00150     ResolverContext_Ptr _context;
00151     ResPool _pool;
00152 
00153     PoolItemList providers;             // the provider which matched
00154 
00155     // only keep 'best' candidate for a package name
00156     typedef map<string,PoolItem_Ref> UniqMap;
00157     UniqMap uniq;
00158 
00159     RequireProcess (PoolItem_Ref r, const Capability & c, ResolverContext_Ptr ctx, const ResPool & p)
00160         : _requirer (r)
00161         , _capability (c)
00162         , _context (ctx)
00163         , _pool (p)
00164     { }
00165 
00166     bool operator()( const CapAndItem & cai )
00167     {
00168         PoolItem provider = cai.item;
00169         Capability match = cai.cap;
00170 
00171         ResStatus status = _context->getStatus( provider );
00172         PoolItem_Ref upgrades = Helper::findInstalledItem (_pool, provider);
00173 
00174         XXX << "RequireProcessInfo (" << provider << " provides " << match << ", is " << status << ")" << endl;
00175 // ERR << "RequireProcessInfo(required: " << *capability << ")" << endl;
00176 // ERR << "require_process_cb(itemIsPossible -> " <<  context->itemIsPossible (*provider) << ")" << endl;
00177 
00178         /* capability is set for item set childern only. If it is set
00179            allow only exactly required version */
00180 
00181         if (_capability != Capability()
00182             && _capability != match) {          // exact match required
00183             return true;
00184         }
00185 
00186         if (!provider->arch().compatibleWith( _context->architecture() )) {
00187             MIL << "provider " << provider << " has incompatible arch '" << provider->arch() << "'" << endl;
00188             return true;
00189         }
00190 
00191         if ( upgrades
00192              && upgrades.resolvable()->arch() != provider->arch()
00193              && provider->kind() != ResTraits<Atom>::kind )             // if patch provides arch upgrade, allow it (#266178)
00194                                                                         // (because of #168840 and #170098, the patch parser grabs the 'best' atom
00195                                                                         //  and does not have knowledge about already installed atom with the same name.
00196                                                                         //  The problem #266178 shows is a previously installed patch (noarch) and atom (ppc)
00197                                                                         //  conflict with a later patch which offers an arch upgrade (ppc -> ppc64)
00198                                                                         //  This has no effect on the patch, since the patch is noarch. But is has effect
00199                                                                         //  on the atom, since it is installed as ppc and the upgrade is ppc64.
00200                                                                         //  Here, we look at arch changes only if they don't affect an atom. So atoms are
00201                                                                         //  allowed for arch upgrades.
00202                                                                         //  However, this only applies to atoms, not to packages. The package will stay
00203                                                                         //  at its architecture. Not doing arch upgrades was one of the requirements for Code10.)
00204         {
00205             MIL << "provider " << provider << " has OTHER arch '" << provider->arch() << "' than the updated item "
00206                 << upgrades << endl;
00207             PoolItemList ignore = _context->getIgnoreArchitectureItem();
00208             PoolItemList::iterator it;
00209             for (it = ignore.begin(); it != ignore.end(); ++it) {
00210                 if (provider == *it) break;
00211             }
00212             if (it != ignore.end()) {
00213                 MIL << " ---> will be ignored " << endl;
00214             } else {
00215                 return true;
00216             }
00217         }
00218 
00219         if (! (status.isToBeUninstalled() || status.isImpossible())
00220             && ! _context->isParallelInstall( provider )
00221             && _context->itemIsPossible( provider )
00222             && ! provider.status().isLocked()
00223             && ! (provider.status().isKept()
00224                   &&provider.status().isByUser())
00225             ) {
00226 
00227             // if we found a to-be-installed provider, choose this and drop all others
00228             if (status.isToBeInstalled()                        // scheduled for install
00229                 || (status.isUninstalled()
00230                     && provider.status().isToBeInstalled()))    // or will-be-scheduled 
00231             {
00232                 providers.clear();
00233                 providers.push_front( provider );
00234                 return false;
00235             }
00236 
00237 
00238             if (!_context->tryAllPossibilities()) {
00239                 // if we already have same name
00240                 //   check for better architecture, then edition
00241                 //   see yast2-pkg-bindings, Package.cc, ProvideProcess
00242 
00243                 UniqMap::iterator upos = uniq.find( provider->name() );
00244 
00245                 if (upos != uniq.end()) {
00246                     if ((upos->second->arch().compare( provider->arch() ) < 0)  // better arch
00247                         || ((upos->second->arch().compare( provider->arch() ) == 0)                 // or same arch
00248                             && (upos->second->edition().compare( provider->edition() ) < 0) ) ) // and better edition
00249                     {
00250                         // new provider is 'better'
00251 
00252                         // erase the old provider
00253                         for (PoolItemList::iterator it = providers.begin(); it != providers.end(); ++it) {
00254                             if (*it == upos->second) {
00255                                 _context->setScippedPossibilities( true ); // Flag that there are other possibilities
00256                                 // which we are currently ignore
00257                                 _XDEBUG("Kicking " << *it << " for " << provider)
00258                                     providers.erase( it );
00259                                 break;
00260                             }
00261                         } 
00262                         upos = uniq.end();      // trigger insertion of new provider below
00263                     }
00264                 }
00265                 if (upos == uniq.end()) {
00266                     providers.push_front( provider );
00267                     uniq[provider->name()] = provider;
00268                 }
00269             } else {
00270                 // try all alternatives
00271                 providers.push_front( provider );
00272             }
00273         }
00274 
00275         return true;
00276     }
00277 };
00278 
00279 
00280 struct NoInstallableProviders
00281 {
00282     PoolItem_Ref requirer;
00283     ResolverContext_Ptr context;
00284 
00285     bool operator()( const CapAndItem cai)
00286     {
00287         PoolItem provider = cai.item;
00288         Capability match = cai.cap;
00289 
00290         string msg_str;
00291         //const Capability match;
00292 
00293         ResStatus status = context->getStatus( provider );
00294 
00295         ResolverInfoMisc_Ptr misc_info;
00296 
00297         if (status.isToBeUninstalled()) {
00298             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_UNINSTALL_PROVIDER, requirer, RESOLVER_INFO_PRIORITY_VERBOSE, match);
00299             misc_info->setOtherPoolItem (provider);
00300         } else if (context->isParallelInstall (provider)) {
00301             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_PARALLEL_PROVIDER, requirer, RESOLVER_INFO_PRIORITY_VERBOSE, match);
00302             misc_info->setOtherPoolItem (provider);
00303         } else if (status.isImpossible()
00304                   || ! context->itemIsPossible (provider)) {
00305             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NOT_INSTALLABLE_PROVIDER, requirer, RESOLVER_INFO_PRIORITY_VERBOSE, match);
00306             misc_info->setOtherPoolItem (provider);
00307         } else if (provider.status().isLocked()) {
00308             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_LOCKED_PROVIDER, requirer, RESOLVER_INFO_PRIORITY_VERBOSE, match);
00309             misc_info->setOtherPoolItem (provider);
00310         } else if (provider.status().isKept() && provider.status().isByUser()) {
00311             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_KEEP_PROVIDER, requirer, RESOLVER_INFO_PRIORITY_VERBOSE, match);
00312             misc_info->setOtherPoolItem (provider);         
00313         } else  if (provider->arch().compatibleWith( context->architecture() )) {
00314             misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_OTHER_ARCH_PROVIDER,
00315                                                                    requirer, RESOLVER_INFO_PRIORITY_VERBOSE, match);
00316             misc_info->setOtherPoolItem (provider);
00317         }
00318 
00319         if (misc_info != NULL) {
00320             context->addInfo (misc_info);
00321         }
00322 
00323         return true;
00324     }
00325 };
00326 
00327 typedef map<string, PoolItem_Ref> UpgradesMap;
00328 
00329 struct LookForUpgrades
00330 {
00331     PoolItem_Ref installed;
00332     ResolverContext_Ptr _context;    
00333     UpgradesMap upgrades;
00334 
00335     LookForUpgrades (PoolItem_Ref i, ResolverContext_Ptr ctx)
00336         : installed (i)
00337         , _context (ctx)        
00338     { }
00339 
00340     bool operator()( PoolItem_Ref provider )
00341     {
00342         UpgradesMap::iterator it = upgrades.find( provider->name() );
00343 
00344         if (it != upgrades.end()) {                             // provider with same name found
00345             if (!_context->upgradeMode()
00346                 && it->second->arch() != installed->arch()
00347                 && provider->arch() == installed->arch()) {
00348                 // prefering the same architecture as the installed item
00349                 // NOT in upgrade mode
00350                 it->second = provider;
00351             } else {
00352                 int cmp = it->second->arch().compare( provider->arch() );
00353                 if ((_context->upgradeMode()                                    // only in upgrade mode
00354                      || it->second->arch() != installed->arch())                // or have not found the same arch as installed item
00355                     && cmp < 0) {                                               // new provider has better arch
00356                     it->second = provider;
00357                 }
00358                 else if (cmp == 0) {                                    // new provider has equal arch
00359                     if (it->second->edition().compare( provider->edition() ) < 0) {
00360                         it->second = provider;                          // new provider has better edition
00361                     }
00362                 }
00363             }
00364         } else {
00365             upgrades[provider->name()] = provider;
00366         }
00367         return true;
00368     }
00369 };
00370 
00371 
00372 // check for an installed or to-be-installed item
00373 // (used to match supplements/enhances of multiple providers)
00374 
00375 struct HintItem
00376 {
00377     PoolItem_Ref match;
00378 
00379     bool operator()( const CapAndItem & cai )
00380     {
00381         if (cai.item.status().staysInstalled()
00382             || cai.item.status().isToBeInstalled())
00383         {
00384             match = cai.item;
00385             return false;               // have one, we're done
00386         }
00387         return true;
00388     }
00389 };
00390 
00391 
00392 // check 'codependent' items
00393 //   by looking at the name prefix: 'foo' and 'foo-bar' are codependent
00394 
00395 static bool
00396 codependent_items (const PoolItem_Ref item1, const PoolItem_Ref item2)
00397 {
00398     string name1 = item1->name();
00399     string name2 = item2->name();
00400     string::size_type len1 = name1.size();
00401     string::size_type len2 = name2.size();
00402 
00403     if (len2 < len1) {
00404         string swap = name1;
00405         string::size_type swap_len = len1;
00406         name1 = name2;
00407         name2 = swap;
00408         len1 = len2;
00409         len2 = swap_len;
00410     }
00411 
00412     // foo and foo-bar are automatically co-dependent
00413     if (len1 < len2
00414         && name1.compare (0, len1, name2) == 0
00415         && name2[len1] == '-') {
00416         return true;
00417     }
00418 
00419     return false;
00420 }
00421 
00422 
00423 // check if we have a match for a (supplements/enhances) hint
00424 
00425 static bool
00426 hint_match( const CapSet & cset, ResPool pool )
00427 {
00428     HintItem info;
00429     
00430     for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00431         Dep dep( Dep::PROVIDES );
00432         invokeOnEach( pool.byCapabilityIndexBegin( cit->index(), dep ),
00433                       pool.byCapabilityIndexEnd( cit->index(), dep ),
00434                       resfilter::ByCapMatch( *cit ),
00435                       functor::functorRef<bool,CapAndItem>(info) );
00436     }
00437     if (info.match) MIL << "hint_match(" << info.match << ")" << endl;
00438     return info.match; // as bool !
00439 }
00440 
00441 //----------------------------------------------------------------------------
00442 
00443 bool
00444 QueueItemRequire::process (const QueueItemList & mainQueue,
00445                           ResolverContext_Ptr context, QueueItemList & new_items)
00446 {
00447     _XDEBUG("QueueItemRequire::process(" << *this << ")");
00448 
00449     bool fulfilled = false;
00450             
00451     if (_requiring_item)
00452     {
00453         fulfilled = context->requirementIsInstalledOrUnneeded (_requiring_item->kind(),_capability);
00454     } else {
00455         fulfilled = context->requirementIsMet (_capability);
00456     }
00457     
00458     if (fulfilled) {
00459         _XDEBUG("requirement is already met in current context");
00460         return true;
00461     }
00462 
00463     // checking for ignoring dependencies
00464     IgnoreMap ignoreMap = context->getIgnoreRequires();
00465     for (IgnoreMap::iterator it = ignoreMap.begin();
00466          it != ignoreMap.end(); it++) {
00467         if ( (!(it->first) // ignore ALL requirements on this capability
00468               || it->first == _requiring_item)
00469              && it->second == _capability) {
00470             _XDEBUG("Found ignoring requires " << _capability << " for " << _requiring_item);
00471             return true;
00472         } else {
00473             _XDEBUG("Ignoring requires " << it->second << " for " <<  it->first << " does not fit");        
00474         }
00475     }
00476 
00477     RequireProcess info (_requiring_item,  Capability(), context,  pool());
00478 
00479     int num_providers = 0;
00480 
00481     if (! _remove_only) {
00482 
00483         Dep dep( Dep::PROVIDES );
00484         XXX << "Look for providers of " << _capability << endl;
00485         // world->foreachProvidingResItem (_capability, require_process_cb, &info);
00486         invokeOnEach( pool().byCapabilityIndexBegin( _capability.index(), dep ),
00487                       pool().byCapabilityIndexEnd( _capability.index(), dep ),
00488                       resfilter::ByCapMatch( _capability ),
00489                       functor::functorRef<bool,CapAndItem>(info) );
00490 
00491         _XDEBUG("Look for providers of " << _capability);
00492 
00493         num_providers = info.providers.size();
00494 
00495         _XDEBUG( "requirement is met by " << num_providers << " resolvable");
00496 
00497 
00498         // if there are multiple providers, try to reduce branching by cleaning up the providers list
00499         // first check all providers if they are to-be-installed or uninstalled
00500         //   if there are to-be-installed providers, erase all uninstalled providers
00501         //   if there are locale providers and none match, try a language fallback
00502         //   prefer providers which enhance an installed or to-be-installed resolvables
00503 
00504         if (num_providers > 1) {                                        // prefer to-be-installed providers
00505 #if 1 // see also line 618
00506             // if there are exactly two providers which differ in architecture
00507             // prefer the better arch
00508             // this will reduce the number of branches for X-32bit.x86_64 vs. X.i586 dramatically
00509             //
00510             // - left commented out as advised by mls@suse.de, might be problematic on non-x86 archs
00511             // - Due the new behaviour of the solver this code will be executed.
00512             //   New: If there is no solution for the "best-architecture" way the solver tries
00513             //        the other branches too.
00514 
00515             if (num_providers == 2) {
00516                 PoolItemList::iterator it = info.providers.begin();
00517                 PoolItem first( *it++ );
00518                 PoolItem second( *it );
00519 
00520                 if (NVRA(first.resolvable()) == NVRA(second.resolvable()))
00521                 {
00522                     // regarding items with the same NVRA only. Bug238284 
00523                     int cmp = first->arch().compare( second->arch() );
00524                     if (cmp < 0) {              // second is better
00525                         --it;
00526                     }
00527 
00528                     if (cmp != 0) {
00529                         info.providers.erase( it );             // erase one of both
00530                         num_providers = 1;
00531                         goto provider_done;
00532                     }
00533                 }
00534             }
00535 #endif
00536             MIL << "Have " << num_providers << " providers for " << _capability << endl;
00537             int to_be_installed = 0;
00538             int uninstalled = 0;
00539             std::map<std::string,PoolItem> language_freshens;
00540             ZYpp::Ptr z = zypp::getZYpp();
00541             ZYpp::LocaleSet requested_locales = z->getRequestedLocales();
00542             bool requested_locale_match = false;
00543             PoolItemSet hints;                  // those which supplement or enhance an installed or to-be-installed
00544 
00545             for (PoolItemList::iterator it = info.providers.begin(); it != info.providers.end(); ++it) {
00546                 PoolItem item = *it;
00547                 if (item.status().isToBeInstalled()) {
00548                     to_be_installed++;
00549                 }
00550                 if (item.status().staysUninstalled()) {
00551                     uninstalled++;
00552                 }
00553                 if (!requested_locale_match) {
00554                     CapSet freshens( item->dep( Dep::FRESHENS ) );
00555 
00556                     // try to find a match of the locale freshens with one of the requested locales
00557                     //   if we have a match, we're done.
00558 
00559                     for (CapSet::const_iterator cit = freshens.begin(); cit != freshens.end(); ++cit) {
00560                         if (cit->refers() == ResTraits<Language>::kind) {
00561                             string loc = cit->index();
00562                             MIL << "Look for language fallback " << loc << ":" << item << endl;
00563                             if (requested_locales.find( Locale( loc ) ) != requested_locales.end()) {
00564                                 MIL << "Locale '" << loc << "' is requested, not looking further" << endl;
00565                                 requested_locale_match = true;
00566                                 break;
00567                             }
00568                             language_freshens[loc] = item;
00569                         }
00570                     }
00571                 }
00572 
00573 
00574                 // now check if a provider supplements or enhances an installed or to-be-installed resolvable
00575 
00576                 if (hint_match( item->dep( Dep::SUPPLEMENTS ), pool() )
00577                     || hint_match( item->dep( Dep::ENHANCES ), pool() ))
00578                 {
00579                     hints.insert( item );
00580                 }
00581 
00582             } // for
00583 
00584             if (hints.empty()
00585                 && to_be_installed == 0
00586                 && !requested_locale_match)
00587             {
00588                 // loop over requested locales, loop over their fallbacks, and try to find a matching provider
00589 
00590                 for (ZYpp::LocaleSet::const_iterator rit = requested_locales.begin(); rit != requested_locales.end(); ++rit) {
00591 
00592                     // loop over possible fallbacks
00593                     Locale l = *rit;
00594                     for (;;) {
00595                         Locale fallback = l.fallback();
00596                         if (fallback == Locale::noCode
00597                             || fallback == l)
00598                         {
00599                             break;
00600                         }
00601                         MIL << "requested " << l << " fallback " << fallback << endl;
00602                         std::map<std::string,PoolItem>::const_iterator match = language_freshens.find( fallback.code() );
00603                         if (match != language_freshens.end()) {
00604                             MIL << match->second << " matches the fallback" << endl;
00605                             info.providers.clear();
00606                             info.providers.push_back( match->second );
00607                             break;
00608                         }
00609                         l = fallback;
00610                     }
00611                 }
00612 #if 0   // just debug
00613                 std::string mil = "language_freshens ";
00614                 for (std::map<std::string,PoolItem>::const_iterator it = language_freshens.begin(); it != language_freshens.end(); ++it) {
00615                     if (it != language_freshens.begin()) mil += ", ";
00616                     mil += it->first;
00617                 }
00618                 MIL << mil << endl;
00619 #endif
00620             }
00621             else if (to_be_installed == 0
00622                      && !hints.empty())
00623             {
00624                 MIL << "Have " << hints.size() << " hints" << endl;
00625                 info.providers.clear();
00626                 for (PoolItemSet::const_iterator it = hints.begin(); it != hints.end(); ++it)
00627                     info.providers.push_back( *it );
00628             }
00629             else { 
00630 
00631             // if we have one or more to-be-installed, erase all uninstalled (if there are any)
00632 
00633             MIL << to_be_installed << " to-be-installed, " << uninstalled << " uninstalled" << endl;
00634 
00635             if (to_be_installed > 0
00636                 && uninstalled > 0)
00637             {
00638                 PoolItemList::iterator next;
00639                 for (PoolItemList::iterator it = info.providers.begin(); it != info.providers.end(); ++it) {
00640                     next = it; ++next;
00641                     if (it->status().staysUninstalled()) {
00642                         MIL << "Not considering " << *it << endl;
00643                         info.providers.erase (it);
00644                     }
00645                     it = next;
00646                 }
00647             }
00648             }
00649 
00650             if (!context->tryAllPossibilities()) {
00651                 // Evaluate the best architecture of the providers
00652                 Arch bestArch = Arch(); // is noarch
00653                 PoolItemList::iterator it;
00654                 for (it = info.providers.begin();
00655                      it != info.providers.end(); it++) {
00656                     if (bestArch.compare( (*it)->arch() ) < 0) {        // better arch
00657                         bestArch = (*it)->arch();
00658                     }   
00659                 }
00660                 
00661                 // filter out all resolvables which have worser architecture, are NOT noarch
00662                 // and have not the same name as the requirement. The last one is needed
00663                 // for updating packages via patch/atoms.
00664                 PoolItemList::iterator next;        
00665                 for (it = info.providers.begin();
00666                      it != info.providers.end();) {
00667 
00668                     bool nameFit = false;
00669                     CapFactory factory;             
00670                     if (isKind<capability::NamedCap>( _capability ) ) {
00671                         Capability capTest =  factory.parse ( (*it)->kind(), (*it)->name(), Rel::ANY, Edition::noedition );
00672                         if (capTest.matches (_capability) == CapMatch::yes) {
00673                             nameFit = true;
00674                             _XDEBUG("Required Capability " << _capability << " has the same name as the provider:" << *it);
00675                             _XDEBUG("    --> do not trow away althout it could have the wrong architecture");
00676                         }
00677                     }
00678                     
00679                     next = it; ++next;
00680                     if ((*it)->arch() != bestArch
00681                         && (*it)->arch() != Arch_noarch
00682                         && !nameFit) {
00683                         _XDEBUG("Kicking " << *it << " due best architecture " << bestArch);
00684                         info.providers.erase( it );
00685                     }
00686                     it = next;
00687                 }
00688             }
00689 
00690             num_providers = info.providers.size();
00691 
00692         } // num_providers > 1
00693 #if 1 // see also line 474
00694 provider_done:;
00695 #endif
00696     } // !_remove_only
00697 
00698     //
00699     // No providers found
00700     //
00701 
00702     if (num_providers == 0) {
00703 
00704         if (_soft) goto finished;                       // don't care for soft requires
00705 
00706         _DEBUG( "Unfulfilled requirement '" << _capability << "'. trying different solution");
00707 
00708         QueueItemUninstall_Ptr uninstall_item = NULL;
00709         QueueItemBranch_Ptr branch_item = NULL;
00710         bool explore_uninstall_branch = true;
00711 
00712         
00713 
00714         if (!_upgraded_item
00715             || _lost_item)
00716         {
00717             ResolverInfo_Ptr err_info;
00718             NoInstallableProviders info;
00719             info.requirer = _requiring_item;
00720             info.context = context;
00721 
00722             // Maybe we can add some extra info on why none of the providers are suitable.
00723 
00724             // pool()->foreachProvidingResItem (_capability, no_installable_providers_info_cb, (void *)&info);
00725 
00726             Dep dep( Dep::PROVIDES );
00727 
00728             invokeOnEach( pool().byCapabilityIndexBegin( _capability.index(), dep ), // begin()
00729                           pool().byCapabilityIndexEnd( _capability.index(), dep ),   // end()
00730                           resfilter::ByCapMatch( _capability ),
00731                           functor::functorRef<bool,CapAndItem>(info) );
00732 
00733         }
00734         //
00735         // If this is an upgrade, we might be able to avoid removing stuff by upgrading it instead.
00736         //
00737 
00738         if ((_upgraded_item
00739              || _lost_item // foo-devel requires foo; foo is lost due obsolete --> try to upgrade foo-devel
00740              || context->verifying()) // We are in the verify mode. So there could be already missing requirements
00741                                       // So try to solve it via update
00742             && _requiring_item)
00743         {
00744 
00745             LookForUpgrades info (_requiring_item, context);
00746 
00747 //          pool()->foreachUpgrade (_requiring_item, new Channel(CHANNEL_TYPE_ANY), look_for_upgrades_cb, (void *)&upgrade_list);
00748 
00749             invokeOnEach( pool().byNameBegin( _requiring_item->name() ), pool().byNameEnd( _requiring_item->name() ),
00750                           functor::chain (resfilter::ByKind( _requiring_item->kind() ),
00751                                           resfilter::byEdition<CompareByGT<Edition> >( _requiring_item->edition() ) ),
00752                                           functor::functorRef<bool,PoolItem>(info) );
00753 
00754             if (!info.upgrades.empty()) {
00755                 string label;
00756 
00757                 branch_item = new QueueItemBranch (pool());
00758 
00759                 ostringstream req_str;  req_str << _requiring_item;
00760                 ostringstream up_str;
00761                 if (_upgraded_item)
00762                     up_str << _upgraded_item;
00763                 else
00764                     up_str << _requiring_item;
00765                 ostringstream cap_str; cap_str << _capability;
00766 
00767                  // Translator: 1.%s = dependency; 2.%s and 3.%s = name of package,patch,...
00768                 label = str::form (_("for requiring %s for %s when upgrading %s"),
00769                                    cap_str.str().c_str(), req_str.str().c_str(), up_str.str().c_str());
00770                 branch_item->setLabel (label);
00771                 _DEBUG("Branching: " + label)
00772 
00773                 for (UpgradesMap::const_iterator iter = info.upgrades.begin(); iter != info.upgrades.end(); ++iter) {
00774                     PoolItem_Ref upgrade_item = iter->second;
00775                     QueueItemInstall_Ptr install_item;
00776 
00777                     if (context->itemIsPossible (upgrade_item)) {
00778 
00779                         install_item = new QueueItemInstall (pool(), upgrade_item, _soft);
00780                         install_item->setUpgrades (_requiring_item);
00781                         branch_item->addItem (install_item);
00782 
00783                         ResolverInfoNeededBy_Ptr upgrade_info = new ResolverInfoNeededBy (upgrade_item);
00784                         if (_upgraded_item)
00785                             upgrade_info->addRelatedPoolItem (_upgraded_item);
00786                         install_item->addInfo (upgrade_info);
00787 
00788                         // If an upgrade item has its requirements met, don't do the uninstall branch.
00789                         //   FIXME: should we also look at conflicts here?
00790 
00791                         if (explore_uninstall_branch) {
00792                             CapSet requires = upgrade_item->dep (Dep::REQUIRES);
00793                             CapSet::const_iterator iter = requires.begin();
00794                             for (; iter != requires.end(); iter++) {
00795                                 const Capability req = *iter;
00796                                 if (! context->requirementIsMet (req)) {
00797                                         break;
00798                                 }
00799                             }
00800                             if (iter == requires.end()) {
00801                                 explore_uninstall_branch = false;
00802                             }
00803                         }
00804 
00805                     } /* if (context->itemIsPossible ( ... */
00806                 } /* for (iter = upgrade_list; ... */
00807             } /* if (info.upgrades) ... */
00808 
00809             if (!info.upgrades.empty()
00810                 && branch_item->isEmpty ())
00811             {
00812 
00813                 for (UpgradesMap::const_iterator iter = info.upgrades.begin(); iter != info.upgrades.end(); ++iter) {
00814                     ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_UPGRADE, _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE);
00815                     if (iter == info.upgrades.begin()) {
00816                         misc_info->setOtherPoolItem( iter->second );
00817                     }
00818                     misc_info->addRelatedPoolItem( iter->second );
00819                     context->addInfo( misc_info );
00820 
00821                     explore_uninstall_branch = true;
00822                 }
00823 
00824                 //
00825                 //  The exception: we always want to consider uninstalling
00826                 //  when the requirement has resulted from a item losing
00827                 //  one of it's provides.
00828 
00829             } else if (!info.upgrades.empty()
00830                        && explore_uninstall_branch
00831                        && _requiring_item
00832                        && _upgraded_item
00833                        && codependent_items (_requiring_item, _upgraded_item)
00834                        && !_lost_item)
00835             {
00836                 explore_uninstall_branch = false;
00837             }
00838 
00839         } /* if (_upgrade_item && _requiring_item) ... */
00840 
00841         ResStatus status = context->getStatus(_requiring_item);
00842         
00843         if (context->verifying()) {
00844             // We always consider uninstalling when in verification mode.
00845             explore_uninstall_branch = true;
00846         }
00847         else if (status.isToBeInstalled()           // scheduled for installation
00848                  && !status.isToBeUninstalled()     // not scheduled for uninstallation
00849                  || _requiring_item.status().staysInstalled()) // not scheduled at all but installed
00850         {
00851             // The item has to be set for installing/updating explicity.
00852             // So the uninstall branch could be not useful if upgrade is not successful.
00853             // Adding the info for solution handling at the end of solving
00854             ResolverInfo_Ptr misc_info;
00855             if (!_upgraded_item) {
00856                 if (_remove_only) {
00857                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_OTHER_PROVIDER,
00858                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00859                 } else {
00860                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_PROVIDER,
00861                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00862                 }
00863             } else {
00864                 misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CANT_SATISFY,
00865                                                   _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE,
00866                                                   _capability);
00867             }       
00868             context->addInfo (misc_info);
00869         }
00870 
00871         if (explore_uninstall_branch && _requiring_item) {
00872             ResolverInfo_Ptr log_info;
00873             uninstall_item = new QueueItemUninstall (pool(), _requiring_item, QueueItemUninstall::UNSATISFIED);
00874             uninstall_item->setCapability (_capability);
00875 
00876             if (_lost_item) {
00877                 log_info = new ResolverInfoDependsOn (_requiring_item, _lost_item);
00878                 uninstall_item->addInfo (log_info);
00879             }
00880 
00881             if (_remove_only)
00882                 uninstall_item->setRemoveOnly ();
00883         }
00884 
00885         if (uninstall_item && branch_item) {
00886             branch_item->addItem (uninstall_item);
00887             new_items.push_back (branch_item);
00888         } else if (uninstall_item) {
00889             new_items.push_front (uninstall_item);
00890         } else if (branch_item) {
00891             new_items.push_back (branch_item);
00892         } else {
00893             // We can't do anything to resolve the missing requirement, so we fail.
00894             ResolverInfo_Ptr misc_info;
00895             if (!_upgraded_item) {
00896                 if (_remove_only) {
00897                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_OTHER_PROVIDER,
00898                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00899                 } else {
00900                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_PROVIDER,
00901                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00902                 }
00903             } else {
00904                 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CANT_SATISFY,
00905                                                                    _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE,
00906                                                                    _capability);
00907             }
00908             context->addError (misc_info);
00909         }
00910 
00911     }
00912 
00913     //
00914     // exactly 1 provider found
00915     //
00916 
00917     else if (num_providers == 1) {
00918 
00919         _XDEBUG( "Found exactly one resolvable, installing it.");
00920 
00921         PoolItem item = info.providers.front();
00922 
00923         // if this a soft require (a recommends), don't override a KEEP_STATE (-> bug #154650)
00924         // see also below
00925         if (_soft
00926             && item.status().isUninstalled()
00927             && !item.status().maySetSoftTransact( true, ResStatus::SOLVER ) )
00928         {
00929             _DEBUG("Can't soft-transact " << item);
00930             goto finished;
00931         }
00932         QueueItemInstall_Ptr install_item = new QueueItemInstall (pool(), item, _soft);
00933         install_item->addDependency (_capability);
00934 
00935         // The requiring item could be NULL if the requirement was added as an extra dependency.
00936         if (_requiring_item) {
00937             install_item->addNeededBy (_requiring_item);
00938         }
00939         new_items.push_front (install_item);
00940 
00941     }
00942 
00943     //
00944     // multiple providers found
00945     //
00946 
00947     else if (num_providers > 1) {
00948 
00949         _DEBUG( "Branching: Found more than one provider of " << _capability);
00950 
00951         QueueItemBranch_Ptr branch_item = new QueueItemBranch( pool() );
00952 
00953         for (PoolItemList::const_iterator iter = info.providers.begin(); iter != info.providers.end(); iter++) {
00954 
00955             PoolItem item = *iter;
00956 
00957             // if this a soft require (a recommends), don't override a KEEP_STATE (-> bug #154650)
00958             // see also above
00959             if (_soft
00960                 && item.status().isUninstalled()
00961                 && !item.status().maySetSoftTransact( true, ResStatus::SOLVER ) )
00962             {
00963                 _DEBUG("Can't soft-transact " << item);
00964                 continue;
00965             }
00966 
00967             QueueItemInstall_Ptr install_item = new QueueItemInstall( pool(), item, _soft );
00968             install_item->addDependency( _capability );
00969             branch_item->addItem( install_item );
00970 
00971             // The requiring item could be NULL if the requirement was added as an extra dependency.
00972             if (_requiring_item) {
00973                 install_item->addNeededBy( _requiring_item );
00974             }
00975         }
00976 
00977         if (!branch_item->isEmpty())
00978             new_items.push_back (branch_item);
00979 
00980     } else {
00981         abort ();
00982     }
00983 
00984 finished:
00985 
00986     return true;
00987 }
00988 
00989 //---------------------------------------------------------------------------
00990 
00991 QueueItem_Ptr
00992 QueueItemRequire::copy (void) const
00993 {
00994     QueueItemRequire_Ptr new_require = new QueueItemRequire (pool(), _capability);
00995 
00996     new_require->QueueItem::copy(this);
00997 
00998     new_require->_requiring_item = _requiring_item;
00999     new_require->_upgraded_item  = _upgraded_item;
01000     new_require->_remove_only    = _remove_only;
01001 
01002     return new_require;
01003 }
01004 
01005 
01006 int
01007 QueueItemRequire::cmp (QueueItem_constPtr item) const
01008 {
01009     int cmp = this->compare (item);             // assures equal type
01010     if (cmp != 0)
01011         return cmp;
01012 
01013     QueueItemRequire_constPtr require = dynamic_pointer_cast<const QueueItemRequire>(item);
01014 
01015     if (_capability != require->capability())
01016     {
01017         cmp = -1;
01018     }
01019     return cmp;
01020 }
01021 
01023     };// namespace detail
01026   };// namespace solver
01029 };// namespace zypp
01031 

Generated on Thu Apr 24 02:24:53 2008 for zypp by  doxygen 1.4.6