ResolverUpgrade.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*---------------------------------------------------------------------\
00003 |                          ____ _   __ __ ___                          |
00004 |                         |__  / \ / / . \ . \                         |
00005 |                           / / \ V /|  _/  _/                         |
00006 |                          / /__ | | | | | |                           |
00007 |                         /_____||_| |_| |_|                           |
00008 |                                                                      |
00009 \---------------------------------------------------------------------*/
00010 /* ResolverUpgrade.cc
00011  *
00012  * Implements the distribution upgrade algorithm.
00013  *
00014  * Copyright (C) 2005 SUSE Linux Products GmbH
00015  *
00016  * This program is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU General Public License,
00018  * version 2, as published by the Free Software Foundation.
00019  *
00020  * This program is distributed in the hope that it will be useful, but
00021  * WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00023  * General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License
00026  * along with this program; if not, write to the Free Software
00027  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00028  * 02111-1307, USA.
00029  */
00030 
00031 /*
00032   stolen from PMPackageManager_update.cc
00033   original author Michael Andres <ma@suse.de>
00034   zypp port by Klaus Kaempf <kkaempf@suse.de>
00035 
00036 /-*/
00037 
00038 #include "zypp/CapSet.h"
00039 #include "zypp/capability/SplitCap.h"
00040 
00041 #include "zypp/base/Logger.h"
00042 #include "zypp/base/String.h"
00043 #include "zypp/base/Gettext.h"
00044 #include "zypp/base/Exception.h"
00045 
00046 #include "zypp/base/Algorithm.h"
00047 #include "zypp/ResPool.h"
00048 #include "zypp/ResStatus.h"
00049 #include "zypp/ResFilters.h"
00050 #include "zypp/CapFilters.h"
00051 #include "zypp/Capability.h"
00052 #include "zypp/CapFactory.h"
00053 #include "zypp/VendorAttr.h"
00054 #include "zypp/Package.h"
00055 
00056 #include "zypp/capability/CapabilityImpl.h"
00057 #include "zypp/ZYppFactory.h"
00058 
00059 #include "zypp/solver/detail/Types.h"
00060 #include "zypp/solver/detail/Helper.h"
00061 #include "zypp/solver/detail/Resolver.h"
00062 
00063 #include "zypp/Target.h"
00064 
00066 namespace zypp
00067 { 
00068 
00069   namespace solver
00070   { 
00071 
00072     namespace detail
00073     { 
00074 
00075 using namespace std;
00076 using namespace zypp;
00077 using zypp::capability::SplitCap;
00078 
00079 
00085 struct AVOrder : public std::binary_function<PoolItem_Ref,PoolItem_Ref,bool>
00086 {
00087     // NOTE: operator() provides LESS semantics to order the set.
00088     // So LESS means 'prior in set'. We want 'better' archs and
00089     // 'better' editions at the beginning of the set. So we return
00090     // TRUE if (lhs > rhs)!
00091     //
00092     bool operator()( const PoolItem_Ref lhs, const PoolItem_Ref rhs ) const
00093         {
00094             int res = lhs->arch().compare( rhs->arch() );
00095             if ( res )
00096                 return res > 0;
00097             res = lhs->edition().compare( rhs->edition() );
00098             if ( res )
00099                 return res > 0;
00100 
00101             // no more criteria, still equal:
00102             // use the ResObject::constPtr (the poiner value)
00103             // (here it's arbitrary whether < or > )
00104             return lhs.resolvable() < rhs.resolvable();
00105         }
00106 };
00107 
00108 typedef std::set<PoolItem_Ref, AVOrder> PoolItemOrderSet;
00109 
00110 
00111 
00112 // check if downgrade is allowed
00113 // (Invariant on entry: installed.edition >= candidate.edition)
00114 //
00115 // candidate must have allowed vendor (e.g. 'SuSE', 'Novell', ...) and candidates buildtime must be
00116 // newer.
00117 
00118 static bool
00119 downgrade_allowed( PoolItem_Ref installed, PoolItem_Ref candidate, bool silent_downgrades )
00120 {
00121     if (installed.status().isLocked()) {
00122         MIL << "Installed " << installed << " is locked, not upgrading" << endl;
00123         return false;
00124     }
00125 
00126     Resolvable::constPtr ires = installed.resolvable();
00127     Package::constPtr ipkg = asKind<Package>(ires);
00128     Resolvable::constPtr cres = candidate.resolvable();
00129     Package::constPtr cpkg = asKind<Package>(cres);
00130 
00131     if (ipkg)
00132       DBG << "Installed vendor '" << ipkg->vendor() << "'" << endl;
00133     if (cpkg)
00134       DBG << "Candidate vendor '" << cpkg->vendor() << "'" << endl;
00135 
00136     if (cpkg
00137         && VendorAttr::instance().isKnown( cpkg->vendor() ) )
00138     {
00139         if ( silent_downgrades )
00140             return true;
00141         if ( ipkg->buildtime() < cpkg->buildtime() ) {                  // installed has older buildtime
00142             MIL << "allowed downgrade " << installed << " to " << candidate << endl;
00143             return true;                                                // see bug #152760
00144         }
00145     }
00146     return false;
00147 }
00148 
00149 
00150 
00151 struct FindObsoletes
00152 {
00153     bool obsoletes;
00154 
00155     FindObsoletes ()
00156         : obsoletes (false)
00157     { }
00158 
00159     bool operator()( const CapAndItem & cai )
00160     {
00161         obsoletes = true;                               // we have a match
00162         return false;                                   // stop looping here
00163     }
00164 };
00165 
00166 
00167 // does the candidate obsolete the capability ?
00168 
00169 bool
00170 Resolver::doesObsoleteCapability (PoolItem_Ref candidate, const Capability & cap)
00171 {
00172     _DEBUG("doesObsoleteCapability " << candidate << ", " << cap);
00173 
00174     Dep dep (Dep::OBSOLETES);
00175     FindObsoletes info;
00176     invokeOnEach( _pool.byCapabilityIndexBegin( cap.index(), dep ),
00177                   _pool.byCapabilityIndexEnd( cap.index(), dep ),
00178                   resfilter::ByCapMatch( cap ),
00179                   functor::functorRef<bool,CapAndItem>(info) );
00180 
00181     _DEBUG((info.obsoletes ? "YES" : "NO"));
00182     return info.obsoletes;
00183 }
00184 
00185 
00186 bool
00187 Resolver::doesObsoleteItem (PoolItem_Ref candidate, PoolItem_Ref installed)
00188 {
00189     CapFactory factory;
00190     Capability installedCap =  factory.parse ( installed->kind(), installed->name(), Rel::EQ, installed->edition());
00191 
00192     return doesObsoleteCapability (candidate, installedCap);
00193 }
00194 
00195 
00196 //-----------------------------------------------------------------------------
00197 
00198 
00199 // find best available providers for installed name
00200 
00201 typedef map<string, PoolItem_Ref> FindMap;
00202 
00203 struct FindProviders
00204 {
00205     FindMap providers;          // the best providers which matched
00206 
00207     FindProviders ()
00208     { }
00209 
00210     bool operator()( const CapAndItem & cai )
00211     {
00212         PoolItem provider( cai.item );
00213         if ( provider.status().isToBeUninstalled() ) {
00214             MIL << "  IGNORE relation match (package is tagged to delete): " << cai.cap << " ==> " << provider << endl;
00215         }
00216         else {
00217             FindMap::iterator it = providers.find( provider->name() );
00218 
00219             if (it != providers.end()) {                                // provider with same name found
00220                 int cmp = it->second->arch().compare( provider->arch() );
00221                 if (cmp < 0) {                                          // new provider has better arch
00222                     it->second = provider;
00223                 }
00224                 else if (cmp == 0) {                                    // new provider has equal arch
00225                     if (it->second->edition().compare( provider->edition() ) < 0) {
00226                         it->second = provider;                          // new provider has better edition
00227                     }
00228                 }
00229             }
00230             else {
00231                 providers[provider->name()] = provider;
00232             }
00233         }
00234         return true;
00235     }
00236 };
00237 
00238 
00239 //-----------------------------------------------------------------------------
00240 
00242 //
00243 //
00244 //      METHOD NAME : Resolver::doUpgrade
00245 //      METHOD TYPE : int
00246 //
00247 //      DESCRIPTION : go through all installed (but not yet touched by user)
00248 //              packages and look for update candidates
00249 //              handle splitprovides and replaced and dropped
00250 //
00251 void
00252 Resolver::doUpgrade( UpgradeStatistics & opt_stats_r )
00253 {
00254   typedef map<PoolItem_Ref,PoolItem_Ref> CandidateMap;
00255   typedef intrusive_ptr<const SplitCap> SplitCapPtr;
00256   typedef map<PoolItem_Ref,PoolItemOrderSet> SplitMap;
00257   typedef map<PoolItem_Ref,PoolItemOrderSet> TodoMap;
00258 
00259   CandidateMap candidatemap;
00260 
00261   SplitMap    splitmap;
00262   TodoMap     applyingSplits;
00263   TodoMap     addSplitted;
00264   TodoMap     addProvided;
00265   TodoMap     addMultiProvided;
00266 
00267   Target_Ptr target;
00268   try {
00269         target = getZYpp()->target();
00270   }
00271   catch( const Exception & excpt_r) {
00272         ERR << "Huh, no target ?";
00273         ZYPP_CAUGHT(excpt_r);
00274         if (!_testing) return;          // can't continue without target
00275         MIL << "Running in test mode, continuing without target" << endl;
00276   }
00277   MIL << "target at " << target << endl;
00278 
00279   MIL << "doUpgrade start... "
00280     << "(delete_unmaintained:" << (opt_stats_r.delete_unmaintained?"yes":"no") << ")"
00281     << "(silent_downgrades:" << (opt_stats_r.silent_downgrades?"yes":"no") << ")"
00282     << "(keep_installed_patches:" << (opt_stats_r.keep_installed_patches?"yes":"no") << ")"
00283     << endl;
00284 
00285   _update_items.clear();
00286   {
00287     UpgradeOptions opts( opt_stats_r );
00288     opt_stats_r = UpgradeStatistics();
00289     (UpgradeOptions&)opt_stats_r = opts;
00290   }
00291 
00293   // Reset all auto states and build PoolItemOrderSet of available candidates
00294   // (those that do not belong to PoolItems set to delete).
00295   //
00296   // On the fly remember splitprovides and afterwards check, which
00297   // of them do apply.
00299   PoolItemOrderSet available; // candidates available for install (no matter if selected for install or not)
00300 
00301   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00302     PoolItem_Ref item = *it;
00303     PoolItem_Ref candidate;
00304     PoolItem_Ref installed;
00305 
00306     if ( item.status().isToBeUninstalled() ) {
00307       MIL << "doUpgrade available: SKIP to delete " << item << endl;
00308       ++opt_stats_r.pre_todel;
00309       continue;
00310     }
00311     if ( item.status().isLocked() ) {
00312       MIL << "doUpgrade available: SKIP locked " << item << endl;
00313       if ( item.status().staysInstalled() ) {
00314         ++opt_stats_r.pre_nocand;
00315       }
00316       continue;
00317     }
00318 
00319     if ( item.status().staysInstalled() ) {     // installed item
00320       installed = item;
00321       CandidateMap::const_iterator cand_it = candidatemap.find( installed );
00322       if (cand_it != candidatemap.end()) {
00323         candidate = cand_it->second;                            // found candidate already
00324       }
00325       else {
00326         candidate = Helper::findUpdateItem( _pool, installed ); // find 'best' upgrade candidate
00327       }
00328       if (!candidate) {
00329         MIL << "doUpgrade available: SKIP no candidate for " << installed << endl;
00330         ++opt_stats_r.pre_nocand;
00331         continue;
00332       }
00333       MIL << "item " << item << " is installed, candidate is " << candidate << endl;
00334       if (candidate.status().isSeen()) {                        // seen already
00335         candidate.status().setSeen(true);
00336         continue;
00337       }
00338       candidate.status().setSeen(true);                         // mark as seen
00339       candidatemap[installed] = candidate;
00340     }
00341     else {                                      // assume Uninstalled
00342       if (item.status().isSeen()) {                             // seen already
00343         item.status().setSeen(true);
00344         continue;
00345       }
00346       candidate = item;
00347       candidate.status().setSeen(true);                         // mark as seen
00348       installed = Helper::findInstalledItem( _pool, candidate );
00349       if (installed) {                                          // check if we already have an installed
00350         if ( installed.status().isLocked() ) {
00351           MIL << "doUpgrade available: SKIP candidate " << candidate << ", locked " << installed << endl;
00352           continue;
00353         }
00354 
00355         MIL << "found installed " << installed << " for item " << candidate << endl;
00356         CandidateMap::const_iterator cand_it = candidatemap.find( installed );
00357         if (cand_it == candidatemap.end()                                               // not in map yet
00358             || (cand_it->second->arch().compare( candidate->arch() ) < 0)               // or the new has better architecture
00359             || ((cand_it->second->arch().compare( candidate->arch() ) == 0)             // or the new has the same architecture
00360                 && (cand_it->second->edition().compare( candidate->edition() ) < 0) ) ) //   and a better edition (-> 157501)
00361         {
00362             candidatemap[installed] = candidate;                                // put it in !
00363         }
00364       }
00365     }
00366 
00367     ++opt_stats_r.pre_avcand;
00368     available.insert( candidate );
00369 
00370     MIL << "installed " << installed << ", candidate " << candidate << endl;
00371 
00372     // remember any splitprovides to packages actually installed.
00373     CapSet caps = candidate->dep (Dep::PROVIDES);
00374     for (CapSet::iterator cit = caps.begin(); cit != caps.end(); ++cit ) {
00375         if (isKind<capability::SplitCap>( *cit ) ) {
00376 
00377             capability::CapabilityImpl::SplitInfo splitinfo = capability::CapabilityImpl::getSplitInfo( *cit );
00378 
00379             PoolItem splititem = Helper::findInstalledByNameAndKind (_pool, splitinfo.name, ResTraits<zypp::Package>::kind);
00380             MIL << "has split cap " << splitinfo.name << ":" << splitinfo.path << ", splititem:" << splititem << endl;
00381             if (splititem) {
00382                 if (target) {
00383                     ResObject::constPtr robj = target->whoOwnsFile( splitinfo.path );
00384                     if (robj)
00385                       MIL << "whoOwnsFile(): " << *robj << endl;
00386                     if (robj
00387                         && robj->name() == splitinfo.name)
00388                     {
00389                       MIL << "split matched !" << endl;
00390                         splitmap[splititem].insert( candidate );
00391                     }
00392                 }
00393             }
00394         }
00395     }
00396 
00397   } // iterate over the complete pool
00398 
00399   // reset all seen (for next run)
00400   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00401         it->status().setSeen( false );
00402   }
00403 
00404   MIL << "doUpgrade: " << opt_stats_r.pre_todel  << " packages tagged to delete" << endl;
00405   MIL << "doUpgrade: " << opt_stats_r.pre_nocand << " packages without candidate (foreign, replaced or dropped)" << endl;
00406   MIL << "doUpgrade: " << opt_stats_r.pre_avcand << " packages available for update" << endl;
00407 
00408   MIL << "doUpgrade: going to check " << splitmap.size() << " probably splitted packages" << endl;
00409   {
00411     // splitmap entries are gouped by PoolItems (we know this). So get the
00412     // filelist as a new PoolItem occures, and use it for consecutive entries.
00413     //
00414     // On the fly build SplitPkgMap from splits that do apply (i.e. file is
00415     // in PoolItems's filelist). The way splitmap was created, candidates added
00416     // are not initially tagged to delete!
00418 
00419     PoolItem_Ref citem;
00420 
00421     for ( SplitMap::iterator it = splitmap.begin(); it != splitmap.end(); ++it ) {
00422         applyingSplits[it->first].insert( it->second.begin(), it->second.end() );
00423         _DEBUG("  split count for " << it->first->name() << " now " << applyingSplits[it->first].size());
00424     }
00425     splitmap.clear();
00426   }
00427 
00429   // Now iterate installed packages, not selected to delete, and
00430   // figure out what might be an appropriate replacement. Current
00431   // packages state is changed immediately. Additional packages are
00432   // reported but set to install later.
00434   MIL << "doUpgrade pass 1..." << endl;
00435 
00436   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00437 
00438     PoolItem_Ref installed(*it);
00439     ResStatus status (installed.status());
00440 
00441     if ( ! status.staysInstalled() ) {
00442       continue;
00443     }
00444     ++opt_stats_r.chk_installed_total;
00445 
00446     if ( status.transacts() ) {                                 // we know its installed, if it transacts also
00447       MIL << "SKIP to delete: " << installed.resolvable() << endl;      // it'll be deleted
00448       ++opt_stats_r.chk_already_todel;
00449       continue;
00450     }
00451 
00452     if ( installed.status().isLocked() ) {                      // skip locked
00453       MIL << "SKIP taboo: " << installed << endl;
00454       ++opt_stats_r.chk_is_taboo;
00455       _update_items.push_back( installed );                     // remember in problem list
00456       continue;
00457     }
00458 
00459     if ( isKind<Patch>(installed.resolvable())
00460          || isKind<Atom>(installed.resolvable())
00461          || isKind<Script>(installed.resolvable())
00462          || isKind<Message>(installed.resolvable()) )
00463       {
00464         if ( ! opt_stats_r.keep_installed_patches )
00465           {
00466             if ( isKind<Patch>(installed.resolvable()) )
00467               MIL << "OUTDATED Patch: " << installed << endl;
00468             installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00469           }
00470         else
00471           {
00472             if ( isKind<Patch>(installed.resolvable()) )
00473               MIL << "SKIP Patch: " << installed << endl;
00474           }
00475         continue;
00476       }
00477 
00478     CandidateMap::iterator cand_it = candidatemap.find( installed );
00479 
00480     bool probably_dropped = false;
00481 
00482     MIL << "REPLACEMENT FOR " << installed << endl;
00484     // figure out replacement
00486     if ( cand_it != candidatemap.end() ) {
00487 
00488       PoolItem_Ref candidate (cand_it->second);
00489 
00490       if ( ! candidate.status().isToBeInstalled() ) {
00491         int cmp = installed->edition().compare( candidate->edition() );
00492         if ( cmp < 0 ) {                                                // new edition
00493           candidate.status().setToBeInstalled( ResStatus::APPL_HIGH );
00494           MIL << " ==> INSTALL (new version): " << candidate << endl;
00495           ++opt_stats_r.chk_to_update;
00496         } else {                                                        // older or equal edition
00497           // check whether to downgrade:
00498 
00499           if (cmp == 0                                                  // equal
00500               || !downgrade_allowed( installed, candidate,
00501                                      opt_stats_r.silent_downgrades) )   //  or downgrade not allowed
00502           {
00503             MIL << " ==> (keep installed)" << candidate << endl;        // keep installed
00504             ++opt_stats_r.chk_to_keep_installed;
00505           } else {                                                      // older and downgrade allowed
00506             candidate.status().setToBeInstalled( ResStatus::APPL_HIGH );
00507             MIL << " ==> INSTALL (SuSE version downgrade): " << candidate << endl;
00508             ++opt_stats_r.chk_to_downgrade;
00509           }
00510         }
00511       } else {
00512         MIL << " ==> INSTALL (preselected): " << candidate << endl;
00513         ++opt_stats_r.chk_already_toins;
00514       }
00515 
00516     }
00517     else {              // no candidate
00518 
00519       // replaced or dropped (anyway there's no candidate for this!)
00520       // If unique provides exists check if obsoleted (replaced).
00521       // Remember new package for 2nd pass.
00522 
00523       Dep dep (Dep::PROVIDES);
00524       CapFactory factory;
00525       Capability installedCap = factory.parse( installed->kind(), installed->name(), Rel::EQ, installed->edition() );
00526 
00527       FindProviders info;
00528 
00529       invokeOnEach( _pool.byCapabilityIndexBegin( installed->name(), dep ),
00530                     _pool.byCapabilityIndexEnd( installed->name(), dep ),
00531                     functor::chain( resfilter::ByCaIUninstalled(),
00532                                     resfilter::ByCapMatch( installedCap ) ) ,
00533                     functor::functorRef<bool,CapAndItem>(info) );
00534 
00535       int num_providers = info.providers.size();
00536 
00537       _DEBUG("lookup " << num_providers << " provides for installed " << installedCap);
00538 
00539       // copy from map to set
00540       PoolItemOrderSet providers;
00541       for (FindMap::const_iterator mapit = info.providers.begin(); mapit != info.providers.end(); ++mapit) {
00542         providers.insert( mapit->second );
00543       }
00544 
00545       switch ( info.providers.size() ) {
00546       case 0:
00547         MIL << " ==> (dropped)" << endl;
00548         // wait untill splits are processed. Might be a split obsoletes
00549         // this one (i.e. package replaced but not provided by new one).
00550         // otherwise it's finaly dropped.
00551         probably_dropped = true;
00552         break;
00553       case 1:
00554         addProvided[installed] = providers;
00555         MIL << " ==> REPLACED by: " << (*providers.begin()) << endl;
00556         // count stats later
00557         // check obsoletes later
00558         break;
00559       default:
00560         addMultiProvided[installed] = providers;
00561         MIL << " ==> pass 2 (" << providers.size() << " times provided)" << endl;
00562         // count stats later
00563         // check obsoletes later
00564         break;
00565       }
00566 
00567     }   // no candidate
00568 
00570     // anyway check for packages split off
00572 
00573     TodoMap::iterator sit = applyingSplits.find( installed );
00574     if ( sit != applyingSplits.end() ) {
00575       PoolItemOrderSet & toadd( sit->second );
00576       if ( !toadd.size() ) {
00577         INT << "Empty SplitPkgMap entry for " << installed << endl;
00578       } else {
00579         for ( PoolItemOrderSet::iterator ait = toadd.begin(); ait != toadd.end(); ++ait ) {
00580           PoolItem_Ref split_candidate = *ait;
00581           MIL << " ==> ADD (splitted): " << split_candidate << endl;
00582           if ( probably_dropped
00583                && split_candidate.status().staysUninstalled()
00584                && doesObsoleteItem (split_candidate, installed))
00585           {
00586             probably_dropped = false;
00587           }
00588         }
00589         addSplitted[installed] = toadd;
00590       }
00591       // count stats later
00592     }
00593 
00595     // now handle dropped package
00597 
00598     if ( probably_dropped ) {
00599       if ( opt_stats_r.delete_unmaintained ) {
00600         installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00601       }
00602       ++opt_stats_r.chk_dropped;
00603       _update_items.push_back( installed );
00604     }
00605 
00606   } // pass 1 end
00607 
00609   // Now check the remembered packages and check non unique provided.
00610   // Maybe one of them was somehow selected. Otherwise we have to guess
00611   // one.
00613   MIL << "doUpgrade pass 2..." << endl;
00614 
00615   // look at the ones with a single provide first
00616 
00617   for ( TodoMap::iterator it = addProvided.begin(); it != addProvided.end(); ++it ) {
00618 
00619     PoolItemOrderSet & tset( it->second );              // these are the providers (well, just one)
00620 
00621     for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
00622       PoolItem_Ref provider (*sit);
00623 
00624       if (provider.status().setToBeInstalled( ResStatus::APPL_HIGH )) {
00625         ++opt_stats_r.chk_replaced;
00626       }
00627 
00628       // needs installed
00629 
00630       if ( doesObsoleteItem (provider, it->first ) ) {
00631         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00632       }
00633     }
00634 
00635   }
00636 
00637   // look at the split providers
00638 
00639   for ( TodoMap::iterator it = addSplitted.begin(); it != addSplitted.end(); ++it ) {
00640 
00641     PoolItemOrderSet & tset( it->second );
00642     PoolItem_Ref lastItem = PoolItem_Ref();
00643 
00644     for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
00645         if (!lastItem
00646             || compareByN ( lastItem.resolvable(), sit->resolvable()) != 0) // do not install packages with the same NVR and other architecture
00647         {
00648             PoolItem_Ref item( *sit );
00649 
00650             // only install split if its actually a different edition
00651 
00652             PoolItem_Ref already_installed = Helper::findInstalledItem( _pool, item );
00653             if (!already_installed
00654                 || already_installed->edition().compare( item->edition() ) != 0 )
00655             {
00656                 if (item.status().setToBeInstalled( ResStatus::APPL_HIGH )) {
00657                     ++opt_stats_r.chk_add_split;
00658                 }
00659             }
00660         }
00661         lastItem = *sit;
00662     }
00663 
00664   }
00665 
00666   // look at the ones with multiple providers
00667 
00668   for ( TodoMap::iterator it = addMultiProvided.begin(); it != addMultiProvided.end(); ++it ) {
00669     MIL << "GET ONE OUT OF " << it->second.size() << " for " << it->first << endl;
00670 
00671     PoolItem_Ref guess;
00672     PoolItemOrderSet & gset( it->second );
00673 
00674     for ( PoolItemOrderSet::iterator git = gset.begin(); git != gset.end(); ++git ) {
00675       PoolItem_Ref item (*git);
00676 
00677       if (git == gset.begin())          // default to first of set; the set is ordered, first is the best
00678         guess = item;
00679 
00680       if ( item.status().isToBeInstalled()) {
00681         MIL << " ==> (pass 2: meanwhile set to install): " << item << endl;
00682         if ( ! doesObsoleteItem (item, it->first ) ) {
00683           it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00684         }
00685         guess = PoolItem_Ref();
00686         break;
00687       } else {
00688         // Be prepared to guess.
00689         // Most common situation for guessing is something like:
00690         //   qt-devel
00691         //   qt-devel-experimental
00692         //   qt-devel-japanese
00693         // That's why currently the shortest package name wins.
00694         if ( !guess || guess->name().size() > item->name().size() ) {
00695           guess = item;
00696         }
00697       }
00698     }
00699 
00700     if ( guess ) {
00701       guess.status().setToBeInstalled( ResStatus::APPL_HIGH );
00702       MIL << " ==> REPLACED by: (pass 2: guessed): " << guess << endl;
00703       if ( ! doesObsoleteItem (guess, it->first ) ) {
00704         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00705       }
00706       ++opt_stats_r.chk_replaced_guessed;
00707     }
00708   }
00709 
00711   // done
00713   MIL << opt_stats_r << endl;
00714 
00715   // Setting Resolver to upgrade mode
00716   _upgradeMode = true;
00717 }
00718 
00720     };// namespace detail
00723   };// namespace solver
00726 };// namespace zypp
00728 
00729 

Generated on Thu Apr 24 02:24:54 2008 for zypp by  doxygen 1.4.6