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

Generated on Thu Jul 6 00:07:23 2006 for zypp by  doxygen 1.4.6