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

Generated on Tue Sep 25 19:23:07 2007 for libzypp by  doxygen 1.5.3