QueueItemRequire.cc

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

Generated on Tue Nov 28 16:49:31 2006 for zypp by  doxygen 1.5.0