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

Generated on Fri Jul 4 16:57:58 2008 for zypp by  doxygen 1.5.0