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             MIL << "Have " << num_providers << " providers for " << _capability << endl;
00459             int to_be_installed = 0;
00460             int uninstalled = 0;
00461             std::map<std::string,PoolItem> language_freshens;
00462             ZYpp::Ptr z = zypp::getZYpp();
00463             ZYpp::LocaleSet requested_locales = z->getRequestedLocales();
00464             bool requested_locale_match = false;
00465             PoolItemSet hints;                  // those which supplement or enhance an installed or to-be-installed
00466 
00467             for (PoolItemList::iterator it = info.providers.begin(); it != info.providers.end(); ++it) {
00468                 PoolItem item = *it;
00469                 if (item.status().isToBeInstalled()) {
00470                     to_be_installed++;
00471                 }
00472                 if (item.status().staysUninstalled()) {
00473                     uninstalled++;
00474                 }
00475                 if (!requested_locale_match) {
00476                     CapSet freshens( item->dep( Dep::FRESHENS ) );
00477 
00478                     // try to find a match of the locale freshens with one of the requested locales
00479                     //   if we have a match, we're done.
00480 
00481                     for (CapSet::const_iterator cit = freshens.begin(); cit != freshens.end(); ++cit) {
00482                         if (cit->refers() == ResTraits<Language>::kind) {
00483                             string loc = cit->index();
00484                             MIL << "Look for language fallback " << loc << ":" << item << endl;
00485                             if (requested_locales.find( Locale( loc ) ) != requested_locales.end()) {
00486                                 MIL << "Locale '" << loc << "' is requested, not looking further" << endl;
00487                                 requested_locale_match = true;
00488                                 break;
00489                             }
00490                             language_freshens[loc] = item;
00491                         }
00492                     }
00493                 }
00494 
00495 
00496                 // now check if a provider supplements or enhances an installed or to-be-installed resolvable
00497 
00498                 if (hint_match( item->dep( Dep::SUPPLEMENTS ), pool() )
00499                     || hint_match( item->dep( Dep::ENHANCES ), pool() ))
00500                 {
00501                     hints.insert( item );
00502                 }
00503 
00504             } // for
00505 
00506             if (hints.empty()
00507                 && to_be_installed == 0
00508                 && !requested_locale_match)
00509             {
00510                 // loop over requested locales, loop over their fallbacks, and try to find a matching provider
00511 
00512                 for (ZYpp::LocaleSet::const_iterator rit = requested_locales.begin(); rit != requested_locales.end(); ++rit) {
00513 
00514                     // loop over possible fallbacks
00515                     Locale l = *rit;
00516                     for (;;) {
00517                         Locale fallback = l.fallback();
00518                         if (fallback == Locale::noCode
00519                             || fallback == l)
00520                         {
00521                             break;
00522                         }
00523                         MIL << "requested " << l << " fallback " << fallback << endl;
00524                         std::map<std::string,PoolItem>::const_iterator match = language_freshens.find( fallback.code() );
00525                         if (match != language_freshens.end()) {
00526                             MIL << match->second << " matches the fallback" << endl;
00527                             info.providers.clear();
00528                             info.providers.push_back( match->second );
00529                             break;
00530                         }
00531                         l = fallback;
00532                     }
00533                 }
00534 #if 0   // just debug
00535                 std::string mil = "language_freshens ";
00536                 for (std::map<std::string,PoolItem>::const_iterator it = language_freshens.begin(); it != language_freshens.end(); ++it) {
00537                     if (it != language_freshens.begin()) mil += ", ";
00538                     mil += it->first;
00539                 }
00540                 MIL << mil << endl;
00541 #endif
00542             }
00543             else if (to_be_installed == 0
00544                      && !hints.empty())
00545             {
00546                 MIL << "Have " << hints.size() << " hints" << endl;
00547                 info.providers.clear();
00548                 for (PoolItemSet::const_iterator it = hints.begin(); it != hints.end(); ++it)
00549                     info.providers.push_back( *it );
00550             }
00551             else { 
00552 
00553             // if we have one or more to-be-installed, erase all uninstalled (if there are any)
00554 
00555             MIL << to_be_installed << " to-be-installed, " << uninstalled << " uninstalled" << endl;
00556 
00557             if (to_be_installed > 0
00558                 && uninstalled > 0)
00559             {
00560                 PoolItemList::iterator next;
00561                 for (PoolItemList::iterator it = info.providers.begin(); it != info.providers.end(); ++it) {
00562                     next = it; ++next;
00563                     if (it->status().staysUninstalled()) {
00564                         MIL << "Not considering " << *it << endl;
00565                         info.providers.erase (it);
00566                     }
00567                     it = next;
00568                 }
00569             }
00570             }
00571 
00572             num_providers = info.providers.size();
00573 
00574         } // num_providers > 1
00575 
00576     } // !_remove_only
00577 
00578     //
00579     // No providers found
00580     //
00581 
00582     if (num_providers == 0) {
00583 
00584         if (_soft) goto finished;                       // don't care for soft requires
00585 
00586         _DEBUG( "Unfulfilled requirement '" << _capability << "'. trying different solution");
00587 
00588         QueueItemUninstall_Ptr uninstall_item = NULL;
00589         QueueItemBranch_Ptr branch_item = NULL;
00590         bool explore_uninstall_branch = true;
00591 
00592         
00593 
00594         if (!_upgraded_item
00595             || _lost_item)
00596         {
00597             ResolverInfo_Ptr err_info;
00598             NoInstallableProviders info;
00599             info.requirer = _requiring_item;
00600             info.context = context;
00601 
00602             // Maybe we can add some extra info on why none of the providers are suitable.
00603 
00604             // pool()->foreachProvidingResItem (_capability, no_installable_providers_info_cb, (void *)&info);
00605 
00606             Dep dep( Dep::PROVIDES );
00607 
00608             invokeOnEach( pool().byCapabilityIndexBegin( _capability.index(), dep ), // begin()
00609                           pool().byCapabilityIndexEnd( _capability.index(), dep ),   // end()
00610                           resfilter::ByCapMatch( _capability ),
00611                           functor::functorRef<bool,CapAndItem>(info) );
00612 
00613         }
00614         //
00615         // If this is an upgrade, we might be able to avoid removing stuff by upgrading it instead.
00616         //
00617 
00618         if ((_upgraded_item
00619              || _lost_item // foo-devel requires foo; foo is lost due obsolete --> try to upgrade foo-devel
00620              || context->verifying()) // We are in the verify mode. So there could be already missing requirements
00621                                       // So try to solve it via update
00622             && _requiring_item)
00623         {
00624 
00625             LookForUpgrades info (_requiring_item);
00626 
00627 //          pool()->foreachUpgrade (_requiring_item, new Channel(CHANNEL_TYPE_ANY), look_for_upgrades_cb, (void *)&upgrade_list);
00628 
00629             invokeOnEach( pool().byNameBegin( _requiring_item->name() ), pool().byNameEnd( _requiring_item->name() ),
00630                           functor::chain (resfilter::ByKind( _requiring_item->kind() ),
00631                                           resfilter::byEdition<CompareByGT<Edition> >( _requiring_item->edition() ) ),
00632                                           functor::functorRef<bool,PoolItem>(info) );
00633 
00634             if (!info.upgrades.empty()) {
00635                 string label;
00636 
00637                 branch_item = new QueueItemBranch (pool());
00638 
00639                 ostringstream req_str;  req_str << _requiring_item;
00640                 ostringstream up_str;
00641                 if (_upgraded_item)
00642                     up_str << _upgraded_item;
00643                 else
00644                     up_str << _requiring_item;
00645                 ostringstream cap_str; cap_str << _capability;
00646 
00647                  // Translator: 1.%s = dependency; 2.%s and 3.%s = name of package,patch,...
00648                 label = str::form (_("for requiring %s for %s when upgrading %s"),
00649                                    cap_str.str().c_str(), req_str.str().c_str(), up_str.str().c_str());
00650                 branch_item->setLabel (label);
00651                 _DEBUG("Branching: " + label)
00652 
00653                 for (UpgradesMap::const_iterator iter = info.upgrades.begin(); iter != info.upgrades.end(); ++iter) {
00654                     PoolItem_Ref upgrade_item = iter->second;
00655                     QueueItemInstall_Ptr install_item;
00656 
00657                     if (context->itemIsPossible (upgrade_item)) {
00658 
00659                         install_item = new QueueItemInstall (pool(), upgrade_item, _soft);
00660                         install_item->setUpgrades (_requiring_item);
00661                         branch_item->addItem (install_item);
00662 
00663                         ResolverInfoNeededBy_Ptr upgrade_info = new ResolverInfoNeededBy (upgrade_item);
00664                         if (_upgraded_item)
00665                             upgrade_info->addRelatedPoolItem (_upgraded_item);
00666                         install_item->addInfo (upgrade_info);
00667 
00668                         // If an upgrade item has its requirements met, don't do the uninstall branch.
00669                         //   FIXME: should we also look at conflicts here?
00670 
00671                         if (explore_uninstall_branch) {
00672                             CapSet requires = upgrade_item->dep (Dep::REQUIRES);
00673                             CapSet::const_iterator iter = requires.begin();
00674                             for (; iter != requires.end(); iter++) {
00675                                 const Capability req = *iter;
00676                                 if (! context->requirementIsMet (req)) {
00677                                         break;
00678                                 }
00679                             }
00680                             if (iter == requires.end()) {
00681                                 explore_uninstall_branch = false;
00682                             }
00683                         }
00684 
00685                     } /* if (context->itemIsPossible ( ... */
00686                 } /* for (iter = upgrade_list; ... */
00687             } /* if (info.upgrades) ... */
00688 
00689             if (!info.upgrades.empty()
00690                 && branch_item->isEmpty ())
00691             {
00692 
00693                 for (UpgradesMap::const_iterator iter = info.upgrades.begin(); iter != info.upgrades.end(); ++iter) {
00694                     ResolverInfoMisc_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_UPGRADE, _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE);
00695                     if (iter == info.upgrades.begin()) {
00696                         misc_info->setOtherPoolItem( iter->second );
00697                     }
00698                     misc_info->addRelatedPoolItem( iter->second );
00699                     context->addInfo( misc_info );
00700 
00701                     explore_uninstall_branch = true;
00702                 }
00703 
00704                 //
00705                 //  The exception: we always want to consider uninstalling
00706                 //  when the requirement has resulted from a item losing
00707                 //  one of it's provides.
00708 
00709             } else if (!info.upgrades.empty()
00710                        && explore_uninstall_branch
00711                        && _requiring_item
00712                        && _upgraded_item
00713                        && codependent_items (_requiring_item, _upgraded_item)
00714                        && !_lost_item)
00715             {
00716                 explore_uninstall_branch = false;
00717             }
00718 
00719         } /* if (_upgrade_item && _requiring_item) ... */
00720 
00721         ResStatus status = context->getStatus(_requiring_item);
00722         
00723         if (context->verifying()) {
00724             // We always consider uninstalling when in verification mode.
00725             explore_uninstall_branch = true;
00726         }
00727         else if (status.isToBeInstalled()           // scheduled for installation
00728                  && !status.isToBeUninstalled()     // not scheduled for uninstallation
00729                  || _requiring_item.status().staysInstalled()) // not scheduled at all but installed
00730         {
00731             // The item has to be set for installing/updating explicity.
00732             // So the uninstall branch could be not useful if upgrade is not successful.
00733             // Adding the info for solution handling at the end of solving
00734             ResolverInfo_Ptr misc_info;
00735             if (!_upgraded_item) {
00736                 if (_remove_only) {
00737                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_OTHER_PROVIDER,
00738                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00739                 } else {
00740                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_PROVIDER,
00741                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00742                 }
00743             } else {
00744                 misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CANT_SATISFY,
00745                                                   _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE,
00746                                                   _capability);
00747             }       
00748             context->addInfo (misc_info);
00749         }
00750 
00751         if (explore_uninstall_branch && _requiring_item) {
00752             ResolverInfo_Ptr log_info;
00753             uninstall_item = new QueueItemUninstall (pool(), _requiring_item, QueueItemUninstall::UNSATISFIED);
00754             uninstall_item->setCapability (_capability);
00755 
00756             if (_lost_item) {
00757                 log_info = new ResolverInfoDependsOn (_requiring_item, _lost_item);
00758                 uninstall_item->addInfo (log_info);
00759             }
00760 
00761             if (_remove_only)
00762                 uninstall_item->setRemoveOnly ();
00763         }
00764 
00765         if (uninstall_item && branch_item) {
00766             branch_item->addItem (uninstall_item);
00767             new_items.push_back (branch_item);
00768         } else if (uninstall_item) {
00769             new_items.push_front (uninstall_item);
00770         } else if (branch_item) {
00771             new_items.push_back (branch_item);
00772         } else {
00773             // We can't do anything to resolve the missing requirement, so we fail.
00774             ResolverInfo_Ptr misc_info;
00775             if (!_upgraded_item) {
00776                 if (_remove_only) {
00777                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_OTHER_PROVIDER,
00778                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00779                 } else {
00780                     misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_NO_PROVIDER,
00781                                                      _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE, _capability);
00782                 }
00783             } else {
00784                 ResolverInfo_Ptr misc_info = new ResolverInfoMisc (RESOLVER_INFO_TYPE_CANT_SATISFY,
00785                                                                    _requiring_item, RESOLVER_INFO_PRIORITY_VERBOSE,
00786                                                                    _capability);
00787             }
00788             context->addError (misc_info);
00789         }
00790 
00791     }
00792 
00793     //
00794     // exactly 1 provider found
00795     //
00796 
00797     else if (num_providers == 1) {
00798 
00799         _XDEBUG( "Found exactly one resolvable, installing it.");
00800 
00801         PoolItem item = info.providers.front();
00802 
00803         // if this a soft require (a recommends), don't override a KEEP_STATE (-> bug #154650)
00804         // see also below
00805         if (_soft
00806             && item.status().isUninstalled()
00807             && !item.status().maySetSoftTransact( true, ResStatus::SOLVER ) )
00808         {
00809             _DEBUG("Can't soft-transact " << item);
00810             goto finished;
00811         }
00812         QueueItemInstall_Ptr install_item = new QueueItemInstall (pool(), item, _soft);
00813         install_item->addDependency (_capability);
00814 
00815         // The requiring item could be NULL if the requirement was added as an extra dependency.
00816         if (_requiring_item) {
00817             install_item->addNeededBy (_requiring_item);
00818         }
00819         new_items.push_front (install_item);
00820 
00821     }
00822 
00823     //
00824     // multiple providers found
00825     //
00826 
00827     else if (num_providers > 1) {
00828 
00829         _DEBUG( "Branching: Found more than one provider of " << _capability);
00830 
00831         QueueItemBranch_Ptr branch_item = new QueueItemBranch( pool() );
00832 
00833         for (PoolItemList::const_iterator iter = info.providers.begin(); iter != info.providers.end(); iter++) {
00834 
00835             PoolItem item = *iter;
00836 
00837             // if this a soft require (a recommends), don't override a KEEP_STATE (-> bug #154650)
00838             // see also above
00839             if (_soft
00840                 && item.status().isUninstalled()
00841                 && !item.status().maySetSoftTransact( true, ResStatus::SOLVER ) )
00842             {
00843                 _DEBUG("Can't soft-transact " << item);
00844                 continue;
00845             }
00846 
00847             QueueItemInstall_Ptr install_item = new QueueItemInstall( pool(), item, _soft );
00848             install_item->addDependency( _capability );
00849             branch_item->addItem( install_item );
00850 
00851             // The requiring item could be NULL if the requirement was added as an extra dependency.
00852             if (_requiring_item) {
00853                 install_item->addNeededBy( _requiring_item );
00854             }
00855         }
00856 
00857         if (!branch_item->isEmpty())
00858             new_items.push_back (branch_item);
00859 
00860     } else {
00861         abort ();
00862     }
00863 
00864 finished:
00865 
00866     return true;
00867 }
00868 
00869 //---------------------------------------------------------------------------
00870 
00871 QueueItem_Ptr
00872 QueueItemRequire::copy (void) const
00873 {
00874     QueueItemRequire_Ptr new_require = new QueueItemRequire (pool(), _capability);
00875 
00876     new_require->QueueItem::copy(this);
00877 
00878     new_require->_requiring_item = _requiring_item;
00879     new_require->_upgraded_item  = _upgraded_item;
00880     new_require->_remove_only    = _remove_only;
00881 
00882     return new_require;
00883 }
00884 
00885 
00886 int
00887 QueueItemRequire::cmp (QueueItem_constPtr item) const
00888 {
00889     int cmp = this->compare (item);             // assures equal type
00890     if (cmp != 0)
00891         return cmp;
00892 
00893     QueueItemRequire_constPtr require = dynamic_pointer_cast<const QueueItemRequire>(item);
00894 
00895     if (_capability != require->capability())
00896     {
00897         cmp = -1;
00898     }
00899     return cmp;
00900 }
00901 
00903     };// namespace detail
00906   };// namespace solver
00909 };// namespace zypp
00911 

Generated on Thu May 4 16:03:25 2006 for zypp by  doxygen 1.4.6