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

Generated on Wed Sep 27 01:16:39 2006 for zypp by  doxygen 1.4.6