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, Target_Ptr target)
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 if (ipkg) DBG << "Installed vendor '" << ipkg->vendor() << "'" << endl;
00131 if (cpkg) DBG << "Candidate vendor '" << cpkg->vendor() << "'" << endl;
00132     if (cpkg
00133         && VendorAttr::instance().isKnown( cpkg->vendor() ) )
00134     {
00135         if (target
00136             && target->root().asString() != "/")        // downgrade ok if we're running from inst-sys
00137         {
00138             return true;
00139         }
00140         if ( ipkg->buildtime() < cpkg->buildtime() ) {                  // installed has older buildtime
00141             MIL << "allowed downgrade " << installed << " to " << candidate << endl;
00142             return true;                                                // see bug #152760
00143         }
00144     }
00145     return false;
00146 }
00147 
00148 
00149 
00150 struct FindObsoletes
00151 {
00152     bool obsoletes;
00153 
00154     FindObsoletes ()
00155         : obsoletes (false)
00156     { }
00157 
00158     bool operator()( const CapAndItem & cai )
00159     {
00160         obsoletes = true;                               // we have a match
00161         return false;                                   // stop looping here
00162     }
00163 };
00164 
00165 
00166 // does the candidate obsolete the capability ?
00167 
00168 bool
00169 Resolver::doesObsoleteCapability (PoolItem_Ref candidate, const Capability & cap)
00170 {
00171     _DEBUG("doesObsoleteCapability " << candidate << ", " << cap);
00172 
00173     Dep dep (Dep::OBSOLETES);
00174     FindObsoletes info;
00175     invokeOnEach( _pool.byCapabilityIndexBegin( cap.index(), dep ),
00176                   _pool.byCapabilityIndexEnd( cap.index(), dep ),
00177                   resfilter::ByCapMatch( cap ),
00178                   functor::functorRef<bool,CapAndItem>(info) );
00179 
00180     _DEBUG((info.obsoletes ? "YES" : "NO"));
00181     return info.obsoletes;
00182 }
00183 
00184 
00185 bool
00186 Resolver::doesObsoleteItem (PoolItem_Ref candidate, PoolItem_Ref installed)
00187 {
00188     CapFactory factory;
00189     Capability installedCap =  factory.parse ( installed->kind(), installed->name(), Rel::EQ, installed->edition());
00190 
00191     return doesObsoleteCapability (candidate, installedCap);
00192 }
00193 
00194 
00195 //-----------------------------------------------------------------------------
00196 
00197 
00198 // find best available providers for installed name
00199 
00200 typedef map<string, PoolItem_Ref> FindMap;
00201 
00202 struct FindProviders
00203 {
00204     FindMap providers;          // the best providers which matched
00205 
00206     FindProviders ()
00207     { }
00208 
00209     bool operator()( const CapAndItem & cai )
00210     {
00211         PoolItem provider( cai.item );
00212         if ( provider.status().isToBeUninstalled() ) {
00213             MIL << "  IGNORE relation match (package is tagged to delete): " << cai.cap << " ==> " << provider << endl;
00214         }
00215         else {
00216             FindMap::iterator it = providers.find( provider->name() );
00217 
00218             if (it != providers.end()) {                                // provider with same name found
00219                 int cmp = it->second->arch().compare( provider->arch() );
00220                 if (cmp < 0) {                                          // new provider has better arch
00221                     it->second = provider;
00222                 }
00223                 else if (cmp == 0) {                                    // new provider has equal arch
00224                     if (it->second->edition().compare( provider->edition() ) < 0) {
00225                         it->second = provider;                          // new provider has better edition
00226                     }
00227                 }
00228             }
00229             else {
00230                 providers[provider->name()] = provider;
00231             }
00232         }
00233         return true;
00234     }
00235 };
00236 
00237 
00238 //-----------------------------------------------------------------------------
00239 
00241 //
00242 //
00243 //      METHOD NAME : Resolver::doUpgrade
00244 //      METHOD TYPE : int
00245 //
00246 //      DESCRIPTION : go through all installed (but not yet touched by user)
00247 //              packages and look for update candidates
00248 //              handle splitprovides and replaced and dropped
00249 //
00250 void
00251 Resolver::doUpgrade( UpgradeStatistics & opt_stats_r )
00252 {
00253   typedef map<PoolItem_Ref,PoolItem_Ref> CandidateMap;
00254   typedef intrusive_ptr<const SplitCap> SplitCapPtr;
00255   typedef map<PoolItem_Ref,PoolItemOrderSet> SplitMap;
00256   typedef map<PoolItem_Ref,PoolItemOrderSet> TodoMap;
00257 
00258   CandidateMap candidatemap;
00259 
00260   SplitMap    splitmap;
00261   TodoMap     applyingSplits;
00262   TodoMap     addSplitted;
00263   TodoMap     addProvided;
00264   TodoMap     addMultiProvided;
00265 
00266   Target_Ptr target;
00267   try {
00268         target = getZYpp()->target();
00269   }
00270   catch( const Exception & excpt_r) {
00271         ERR << "Huh, no target ?";
00272         ZYPP_CAUGHT(excpt_r);
00273         if (!_testing) return;          // can't continue without target
00274         MIL << "Running in test mode, continuing without target" << endl;
00275   }
00276 MIL << "target at " << target << endl;
00277 
00278   MIL << "doUpgrade start... "
00279     << "(delete_unmaintained:" << (opt_stats_r.delete_unmaintained?"yes":"no") << ")"
00280     << endl;
00281 
00282   _update_items.clear();
00283   {
00284     UpgradeOptions opts( opt_stats_r );
00285     opt_stats_r = UpgradeStatistics();
00286     (UpgradeOptions&)opt_stats_r = opts;
00287   }
00288 
00290   // Reset all auto states and build PoolItemOrderSet of available candidates
00291   // (those that do not belong to PoolItems set to delete).
00292   //
00293   // On the fly remember splitprovides and afterwards check, which
00294   // of them do apply.
00296   PoolItemOrderSet available; // candidates available for install (no matter if selected for install or not)
00297 
00298   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00299     PoolItem_Ref item = *it;
00300     PoolItem_Ref candidate;
00301     PoolItem_Ref installed;
00302 
00303     if ( item.status().isToBeUninstalled() ) {
00304       MIL << "doUpgrade available: SKIP to delete " << item << endl;
00305       ++opt_stats_r.pre_todel;
00306       continue;
00307     }
00308     if ( item.status().isLocked() ) {
00309       MIL << "doUpgrade available: SKIP locked " << item << endl;
00310       if ( item.status().staysInstalled() ) {
00311         ++opt_stats_r.pre_nocand;
00312       }
00313       continue;
00314     }
00315 
00316     if ( item.status().staysInstalled() ) {     // installed item
00317       installed = item;
00318       CandidateMap::const_iterator cand_it = candidatemap.find( installed );
00319       if (cand_it != candidatemap.end()) {
00320         candidate = cand_it->second;                            // found candidate already
00321       }
00322       else {
00323         candidate = Helper::findUpdateItem( _pool, installed ); // find 'best' upgrade candidate
00324       }
00325       if (!candidate) {
00326         MIL << "doUpgrade available: SKIP no candidate for " << installed << endl;
00327         ++opt_stats_r.pre_nocand;
00328         continue;
00329       }
00330 MIL << "item " << item << " is installed, candidate is " << candidate << endl;
00331       if (candidate.status().isSeen()) {                        // seen already
00332         candidate.status().setSeen(true);
00333         continue;
00334       }
00335       candidate.status().setSeen(true);                         // mark as seen
00336       candidatemap[installed] = candidate;
00337     }
00338     else {                                      // assume Uninstalled
00339       if (item.status().isSeen()) {                             // seen already
00340         item.status().setSeen(true);
00341         continue;
00342       }
00343       candidate = item;
00344       candidate.status().setSeen(true);                         // mark as seen
00345       installed = Helper::findInstalledItem( _pool, candidate );
00346       if (installed) {                                          // check if we already have an installed
00347         if ( installed.status().isLocked() ) {
00348           MIL << "doUpgrade available: SKIP candidate " << candidate << ", locked " << installed << endl;
00349           continue;
00350         }
00351 
00352 MIL << "found installed " << installed << " for item " << candidate << endl;
00353         CandidateMap::const_iterator cand_it = candidatemap.find( installed );
00354         if (cand_it == candidatemap.end()                                               // not in map yet
00355             || (cand_it->second->arch().compare( candidate->arch() ) < 0)               // or the new has better architecture
00356             || ((cand_it->second->arch().compare( candidate->arch() ) == 0)             // or the new has the same architecture
00357                 && (cand_it->second->edition().compare( candidate->edition() ) < 0) ) ) //   and a better edition (-> 157501)
00358         {
00359             candidatemap[installed] = candidate;                                // put it in !
00360         }
00361       }
00362     }
00363 
00364     ++opt_stats_r.pre_avcand;
00365     available.insert( candidate );
00366 
00367 MIL << "installed " << installed << ", candidate " << candidate << endl;
00368 
00369     // remember any splitprovides to packages actually installed.
00370     CapSet caps = candidate->dep (Dep::PROVIDES);
00371     for (CapSet::iterator cit = caps.begin(); cit != caps.end(); ++cit ) {
00372         if (isKind<capability::SplitCap>( *cit ) ) {
00373 
00374             capability::CapabilityImpl::SplitInfo splitinfo = capability::CapabilityImpl::getSplitInfo( *cit );
00375 
00376             PoolItem splititem = Helper::findInstalledByNameAndKind (_pool, splitinfo.name, ResTraits<zypp::Package>::kind);
00377 MIL << "has split cap " << splitinfo.name << ":" << splitinfo.path << ", splititem:" << splititem << endl;
00378             if (splititem) {
00379                 if (target) {
00380                     ResObject::constPtr robj = target->whoOwnsFile( splitinfo.path );
00381 if (robj) MIL << "whoOwnsFile(): " << *robj << endl;
00382                     if (robj
00383                         && robj->name() == splitinfo.name)
00384                     {
00385 MIL << "split matched !" << endl;
00386                         splitmap[splititem].insert( candidate );
00387                     }
00388                 }
00389             }
00390         }
00391     }
00392 
00393   } // iterate over the complete pool
00394 
00395   // reset all seen (for next run)
00396   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00397         it->status().setSeen( false );
00398   }
00399 
00400 #warning Cant update from broken install medium like STABLE
00401 #if 0
00402   // filter packages with requires that are not fulfilled by other candidates,
00403   // to reduce errors a bit when trying to update from a broken installation
00404   // medium (ie. STABLE)
00405   {
00406     CheckSetDeps::BrokenMap broken;
00407     CheckSetDeps checker(available, broken);
00408 
00409     checker.setTrackRelations(false);
00410     checker.checkAll();
00411 
00412     if(!broken.empty())
00413     {
00414       CheckSetDeps::BrokenMap::iterator bit, bend;
00415       for(bit = broken.begin(), bend = broken.end(); bit != bend; ++bit)
00416       {
00417         MIL << bit->first->name() << " is broken, not considering it for update" << endl;
00418         available.remove(bit->first);
00419         --opt_stats_r.pre_avcand;
00420         ++opt_stats_r.pre_nocand;
00421       }
00422     }
00423   }
00424 #endif
00425 
00426   MIL << "doUpgrade: " << opt_stats_r.pre_todel  << " packages tagged to delete" << endl;
00427   MIL << "doUpgrade: " << opt_stats_r.pre_nocand << " packages without candidate (foreign, replaced or dropped)" << endl;
00428   MIL << "doUpgrade: " << opt_stats_r.pre_avcand << " packages available for update" << endl;
00429 
00430   MIL << "doUpgrade: going to check " << splitmap.size() << " probably splitted packages" << endl;
00431   {
00433     // splitmap entries are gouped by PoolItems (we know this). So get the
00434     // filelist as a new PoolItem occures, and use it for consecutive entries.
00435     //
00436     // On the fly build SplitPkgMap from splits that do apply (i.e. file is
00437     // in PoolItems's filelist). The way splitmap was created, candidates added
00438     // are not initially tagged to delete!
00440 
00441     PoolItem_Ref citem;
00442 
00443     for ( SplitMap::iterator it = splitmap.begin(); it != splitmap.end(); ++it ) {
00444         applyingSplits[it->first].insert( it->second.begin(), it->second.end() );
00445         _DEBUG("  split count for " << it->first->name() << " now " << applyingSplits[it->first].size());
00446     }
00447     splitmap.clear();
00448   }
00449 
00451   // Now iterate installed packages, not selected to delete, and
00452   // figure out what might be an appropriate replacement. Current
00453   // packages state is changed immediately. Additional packages are
00454   // reported but set to install later.
00456   MIL << "doUpgrade pass 1..." << endl;
00457 
00458   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00459 
00460     PoolItem_Ref installed(*it);
00461     ResStatus status (installed.status());
00462 
00463     if ( ! status.staysInstalled() ) {
00464       continue;
00465     }
00466     ++opt_stats_r.chk_installed_total;
00467 
00468     if ( status.transacts() ) {                                 // we know its installed, if it transacts also
00469       MIL << "SKIP to delete: " << installed.resolvable() << endl;      // it'll be deleted
00470       ++opt_stats_r.chk_already_todel;
00471       continue;
00472     }
00473 
00474     if ( installed.status().isLocked() ) {                      // skip locked
00475       MIL << "SKIP taboo: " << installed << endl;
00476       ++opt_stats_r.chk_is_taboo;
00477       _update_items.push_back( installed );                     // remember in problem list
00478       continue;
00479     }
00480 
00481     CandidateMap::iterator cand_it = candidatemap.find( installed );
00482 
00483     bool probably_dropped = false;
00484 
00485     MIL << "REPLACEMENT FOR " << installed << endl;
00487     // figure out replacement
00489     if ( cand_it != candidatemap.end() ) {
00490 
00491       PoolItem_Ref candidate (cand_it->second);
00492 
00493       if ( ! candidate.status().isToBeInstalled() ) {
00494         int cmp = installed->edition().compare( candidate->edition() );
00495         if ( cmp < 0 ) {                                                // new edition
00496           candidate.status().setToBeInstalled( ResStatus::APPL_HIGH );
00497           MIL << " ==> INSTALL (new version): " << candidate << endl;
00498           ++opt_stats_r.chk_to_update;
00499         } else {                                                        // older or equal edition
00500           // check whether to downgrade:
00501 
00502           if (cmp == 0                                                  // equal
00503               || !downgrade_allowed (installed, candidate, target))     //  or downgrade not allowed
00504           {     
00505             MIL << " ==> (keep installed)" << candidate << endl;        // keep installed
00506             ++opt_stats_r.chk_to_keep_installed;
00507           } else {                                                      // older and downgrade allowed
00508             candidate.status().setToBeInstalled( ResStatus::APPL_HIGH );
00509             MIL << " ==> INSTALL (SuSE version downgrade): " << candidate << endl;
00510             ++opt_stats_r.chk_to_downgrade;
00511           }
00512         }
00513       } else {
00514         MIL << " ==> INSTALL (preselected): " << candidate << endl;
00515         ++opt_stats_r.chk_already_toins;
00516       }
00517 
00518     }
00519     else {              // no candidate
00520 
00521       // replaced or dropped (anyway there's no candidate for this!)
00522       // If unique provides exists check if obsoleted (replaced).
00523       // Remember new package for 2nd pass.
00524 
00525       Dep dep (Dep::PROVIDES);
00526       CapFactory factory;
00527       Capability installedCap = factory.parse( installed->kind(), installed->name(), Rel::EQ, installed->edition() );
00528 
00529       FindProviders info;
00530 
00531       invokeOnEach( _pool.byCapabilityIndexBegin( installed->name(), dep ),
00532                     _pool.byCapabilityIndexEnd( installed->name(), dep ),
00533                     functor::chain( resfilter::ByCaIUninstalled(),
00534                                     resfilter::ByCapMatch( installedCap ) ) ,
00535                     functor::functorRef<bool,CapAndItem>(info) );
00536 
00537       int num_providers = info.providers.size();
00538 
00539       _DEBUG("lookup " << num_providers << " provides for installed " << installedCap);
00540 
00541       // copy from map to set
00542       PoolItemOrderSet providers;
00543       for (FindMap::const_iterator mapit = info.providers.begin(); mapit != info.providers.end(); ++mapit) {
00544         providers.insert( mapit->second );
00545       }
00546 
00547       switch ( info.providers.size() ) {
00548       case 0:
00549         MIL << " ==> (dropped)" << endl;
00550         // wait untill splits are processed. Might be a split obsoletes
00551         // this one (i.e. package replaced but not provided by new one).
00552         // otherwise it's finaly dropped.
00553         probably_dropped = true;
00554         break;
00555       case 1:
00556         addProvided[installed] = providers;
00557         MIL << " ==> REPLACED by: " << (*providers.begin()) << endl;
00558         // count stats later
00559         // check obsoletes later
00560         break;
00561       default:
00562         addMultiProvided[installed] = providers;
00563         MIL << " ==> pass 2 (" << providers.size() << " times provided)" << endl;
00564         // count stats later
00565         // check obsoletes later
00566         break;
00567       }
00568 
00569     }   // no candidate
00570 
00572     // anyway check for packages split off
00574 
00575     TodoMap::iterator sit = applyingSplits.find( installed );
00576     if ( sit != applyingSplits.end() ) {
00577       PoolItemOrderSet & toadd( sit->second );
00578       if ( !toadd.size() ) {
00579         INT << "Empty SplitPkgMap entry for " << installed << endl;
00580       } else {
00581         for ( PoolItemOrderSet::iterator ait = toadd.begin(); ait != toadd.end(); ++ait ) {
00582           PoolItem_Ref split_candidate = *ait;
00583           MIL << " ==> ADD (splitted): " << split_candidate << endl;
00584           if ( probably_dropped
00585                && split_candidate.status().staysUninstalled()
00586                && doesObsoleteItem (split_candidate, installed))
00587           {
00588             probably_dropped = false;
00589           }
00590         }
00591         addSplitted[installed] = toadd;
00592       }
00593       // count stats later
00594     }
00595 
00597     // now handle dropped package
00599 
00600     if ( probably_dropped ) {
00601       if ( opt_stats_r.delete_unmaintained ) {
00602         installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00603       }
00604       ++opt_stats_r.chk_dropped;
00605       _update_items.push_back( installed );
00606     }
00607 
00608   } // pass 1 end
00609 
00611   // Now check the remembered packages and check non unique provided.
00612   // Maybe one of them was somehow selected. Otherwise we have to guess
00613   // one.
00615   MIL << "doUpgrade pass 2..." << endl;
00616 
00617   // look at the ones with a single provide first
00618 
00619   for ( TodoMap::iterator it = addProvided.begin(); it != addProvided.end(); ++it ) {
00620 
00621     PoolItemOrderSet & tset( it->second );              // these are the providers (well, just one)
00622 
00623     for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
00624       PoolItem_Ref provider (*sit);
00625 
00626       if (provider.status().setToBeInstalled( ResStatus::APPL_HIGH )) {
00627         ++opt_stats_r.chk_replaced;
00628       }
00629 
00630       // needs installed
00631 
00632       if ( doesObsoleteItem (provider, it->first ) ) {
00633         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00634       }
00635     }
00636 
00637   }
00638 
00639   // look at the split providers
00640 
00641   for ( TodoMap::iterator it = addSplitted.begin(); it != addSplitted.end(); ++it ) {
00642 
00643     PoolItemOrderSet & tset( it->second );
00644     PoolItem_Ref lastItem = PoolItem_Ref();
00645 
00646     for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
00647         if (!lastItem
00648             || compareByN ( lastItem.resolvable(), sit->resolvable()) != 0) // do not install packages with the same NVR and other architecture
00649         {
00650             PoolItem_Ref item( *sit );
00651 
00652             // only install split if its actually a different edition
00653 
00654             PoolItem_Ref already_installed = Helper::findInstalledItem( _pool, item );
00655             if (!already_installed
00656                 || already_installed->edition().compare( item->edition() ) != 0 )
00657             {
00658                 if (item.status().setToBeInstalled( ResStatus::APPL_HIGH )) {
00659                     ++opt_stats_r.chk_add_split;
00660                 }
00661             }
00662         }
00663         lastItem = *sit;
00664     }
00665 
00666   }
00667 
00668   // look at the ones with multiple providers
00669 
00670   for ( TodoMap::iterator it = addMultiProvided.begin(); it != addMultiProvided.end(); ++it ) {
00671     MIL << "GET ONE OUT OF " << it->second.size() << " for " << it->first << endl;
00672 
00673     PoolItem_Ref guess;
00674     PoolItemOrderSet & gset( it->second );
00675 
00676     for ( PoolItemOrderSet::iterator git = gset.begin(); git != gset.end(); ++git ) {
00677       PoolItem_Ref item (*git);
00678 
00679       if (git == gset.begin())          // default to first of set; the set is ordered, first is the best
00680         guess = item;
00681 
00682       if ( item.status().isToBeInstalled()) {
00683         MIL << " ==> (pass 2: meanwhile set to install): " << item << endl;
00684         if ( ! doesObsoleteItem (item, it->first ) ) {
00685           it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00686         }
00687         guess = PoolItem_Ref();
00688         break;
00689       } else {
00690         // Be prepared to guess.
00691         // Most common situation for guessing is something like:
00692         //   qt-devel
00693         //   qt-devel-experimental
00694         //   qt-devel-japanese
00695         // That's why currently the shortest package name wins.
00696         if ( !guess || guess->name().size() > item->name().size() ) {
00697           guess = item;
00698         }
00699       }
00700     }
00701 
00702     if ( guess ) {
00703       guess.status().setToBeInstalled( ResStatus::APPL_HIGH );
00704       MIL << " ==> REPLACED by: (pass 2: guessed): " << guess << endl;
00705       if ( ! doesObsoleteItem (guess, it->first ) ) {
00706         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00707       }
00708       ++opt_stats_r.chk_replaced_guessed;
00709     }
00710   }
00711 
00713   // done
00715   MIL << opt_stats_r << endl;
00716 
00717   // Setting Resolver to upgrade mode
00718   _upgradeMode = true;
00719 }
00720 
00722     };// namespace detail
00725   };// namespace solver
00728 };// namespace zypp
00730 
00731 

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