00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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 #include "zypp/VendorAttr.h"
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
00088
00089
00090
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
00102
00103
00104 return lhs.resolvable() < rhs.resolvable();
00105 }
00106 };
00107
00108 typedef std::set<PoolItem_Ref, AVOrder> PoolItemOrderSet;
00109
00110
00111
00112
00113
00114
00115
00116
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() ) {
00142 MIL << "allowed downgrade " << installed << " to " << candidate << endl;
00143 return true;
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;
00162 return false;
00163 }
00164 };
00165
00166
00167
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 typedef map<string, PoolItem_Ref> FindMap;
00200
00201 struct FindProviders
00202 {
00203 FindMap providers;
00204 PoolItem forItem;
00205 bool otherVendorFound;
00206 FindProviders (PoolItem item)
00207 :forItem(item),
00208 otherVendorFound(false)
00209 { }
00210
00211 bool operator()( const CapAndItem & cai )
00212 {
00213 PoolItem provider( cai.item );
00214 if ( !VendorAttr::instance().equivalent(provider->vendor(), forItem->vendor()) )
00215 {
00216 MIL << "Discarding '" << provider << "' from vendor '"
00217 << provider->vendor() << "' different to uninstalled '"
00218 << forItem->vendor() << "' vendor." << endl;
00219 otherVendorFound = true;
00220 } else if ( provider.status().isToBeUninstalled() ) {
00221 MIL << " IGNORE relation match (package is tagged to delete): " << cai.cap << " ==> " << provider << endl;
00222 }
00223 else {
00224 FindMap::iterator it = providers.find( provider->name() );
00225
00226 if (it != providers.end()) {
00227 if (provider.status().isToBeInstalled()
00228 || it->second.status().isToBeInstalled()) {
00229
00230 if (provider.status().isToBeInstalled()
00231 && it->second.status().isToBeInstalled()) {
00232 ERR << "only one should be set for installation: " << it->second << "; " << provider << endl;
00233 } else {
00234 if (provider.status().isToBeInstalled()) {
00235 it->second = provider;
00236 }
00237 }
00238 } else {
00239
00240 int cmp = it->second->arch().compare( provider->arch() );
00241 if (cmp < 0) {
00242 it->second = provider;
00243 }
00244 else if (cmp == 0) {
00245 if (it->second->edition().compare( provider->edition() ) < 0) {
00246 it->second = provider;
00247 }
00248 }
00249 }
00250 }
00251 else {
00252 providers[provider->name()] = provider;
00253 }
00254 }
00255 return true;
00256 }
00257 };
00258
00259
00260
00261
00262
00263
00264 class LookForSelected : public resfilter::PoolItemFilterFunctor
00265 {
00266 public:
00267 bool found;
00268 PoolItem_Ref candidate;
00269
00270 LookForSelected (PoolItem_Ref can)
00271 : candidate (can),
00272 found (false)
00273 { }
00274
00275 bool operator()( PoolItem_Ref item )
00276 {
00277 if (item.status().isToBeInstalled()
00278 && item->edition() == candidate->edition()
00279 && item->arch() == candidate->arch()) {
00280 MIL << item << " is already selected for installation --> ignoring" << endl;
00281 found = true;
00282 return false;
00283 }
00284 return true;
00285 }
00286 };
00287
00288 bool setForInstallation (const ResPool &pool, PoolItem_Ref item) {
00289 LookForSelected info(item);
00290
00291 invokeOnEach( pool.byNameBegin (item->name()),
00292 pool.byNameEnd (item->name()),
00293 functor::chain (resfilter::ByUninstalled (),
00294 resfilter::ByKind (item->kind())),
00295 functor::functorRef<bool,PoolItem> (info) );
00296 if (info.found) {
00297 MIL << " ---> " << item << " will be ignoring" << endl;
00298 return true;
00299 } else {
00300 return item.status().setToBeInstalled( ResStatus::APPL_HIGH );
00301 }
00302 }
00303
00304
00305
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 void
00317 Resolver::doUpgrade( UpgradeStatistics & opt_stats_r )
00318 {
00319 typedef map<PoolItem_Ref,PoolItem_Ref> CandidateMap;
00320 typedef intrusive_ptr<const SplitCap> SplitCapPtr;
00321 typedef map<PoolItem_Ref,PoolItemOrderSet> SplitMap;
00322 typedef map<PoolItem_Ref,PoolItemOrderSet> TodoMap;
00323
00324 CandidateMap candidatemap;
00325
00326 SplitMap splitmap;
00327 TodoMap applyingSplits;
00328 TodoMap addSplitted;
00329 TodoMap addProvided;
00330 TodoMap addMultiProvided;
00331
00332 Target_Ptr target;
00333 try {
00334 target = getZYpp()->target();
00335 }
00336 catch( const Exception & excpt_r) {
00337 ERR << "Huh, no target ?";
00338 ZYPP_CAUGHT(excpt_r);
00339 if (!_testing) return;
00340 MIL << "Running in test mode, continuing without target" << endl;
00341 }
00342 MIL << "target at " << target << endl;
00343
00344 MIL << "doUpgrade start... "
00345 << "(delete_unmaintained:" << (opt_stats_r.delete_unmaintained?"yes":"no") << ")"
00346 << "(silent_downgrades:" << (opt_stats_r.silent_downgrades?"yes":"no") << ")"
00347 << "(keep_installed_patches:" << (opt_stats_r.keep_installed_patches?"yes":"no") << ")"
00348 << endl;
00349
00350 _update_items.clear();
00351 {
00352 UpgradeOptions opts( opt_stats_r );
00353 opt_stats_r = UpgradeStatistics();
00354 (UpgradeOptions&)opt_stats_r = opts;
00355 }
00356
00358
00359
00360
00361
00362
00364 PoolItemOrderSet available;
00365
00366 for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00367 PoolItem_Ref item = *it;
00368 PoolItem_Ref candidate;
00369 PoolItem_Ref installed;
00370
00371 if ( item.status().isToBeUninstalled() ) {
00372 MIL << "doUpgrade available: SKIP to delete " << item << endl;
00373 ++opt_stats_r.pre_todel;
00374 continue;
00375 }
00376 if ( item.status().isLocked() ) {
00377 MIL << "doUpgrade available: SKIP locked " << item << endl;
00378 if ( item.status().staysInstalled() ) {
00379 ++opt_stats_r.pre_nocand;
00380 }
00381 continue;
00382 }
00383
00384 if ( item.status().staysInstalled() ) {
00385 installed = item;
00386 CandidateMap::const_iterator cand_it = candidatemap.find( installed );
00387 if (cand_it != candidatemap.end()) {
00388 candidate = cand_it->second;
00389 }
00390 else {
00391 candidate = Helper::findUpdateItem( _pool, installed );
00392 }
00393 if (!candidate) {
00394 MIL << "doUpgrade available: SKIP no candidate for " << installed << endl;
00395 ++opt_stats_r.pre_nocand;
00396 continue;
00397 }
00398 MIL << "item " << item << " is installed, candidate is " << candidate << endl;
00399 if (candidate.status().isSeen()) {
00400 candidate.status().setSeen(true);
00401 continue;
00402 }
00403 candidate.status().setSeen(true);
00404 candidatemap[installed] = candidate;
00405 }
00406 else {
00407 if (item.status().isSeen()) {
00408 item.status().setSeen(true);
00409 continue;
00410 }
00411 candidate = item;
00412 candidate.status().setSeen(true);
00413 installed = Helper::findInstalledItem( _pool, candidate );
00414 if (installed) {
00415 if ( installed.status().isLocked() ) {
00416 MIL << "doUpgrade available: SKIP candidate " << candidate << ", locked " << installed << endl;
00417 continue;
00418 }
00419
00420 if ( !VendorAttr::instance().equivalent(installed->vendor(), candidate->vendor()) )
00421 {
00422 MIL << "Discarding '" << candidate << "' from vendor '"
00423 << candidate->vendor() << "' different to uninstalled '"
00424 << installed->vendor() << "' vendor." << endl;
00425 continue;
00426 }
00427
00428 MIL << "found installed " << installed << " for item " << candidate << endl;
00429 CandidateMap::const_iterator cand_it = candidatemap.find( installed );
00430 if (cand_it == candidatemap.end()
00431 || (cand_it->second->arch().compare( candidate->arch() ) < 0)
00432 || ((cand_it->second->arch().compare( candidate->arch() ) == 0)
00433 && (cand_it->second->edition().compare( candidate->edition() ) < 0))
00434 )
00435 {
00436 candidatemap[installed] = candidate;
00437 }
00438 }
00439 }
00440
00441 ++opt_stats_r.pre_avcand;
00442 available.insert( candidate );
00443
00444 MIL << "installed " << installed << ", candidate " << candidate << endl;
00445
00446
00447 CapSet caps = candidate->dep (Dep::PROVIDES);
00448 for (CapSet::iterator cit = caps.begin(); cit != caps.end(); ++cit ) {
00449 if (isKind<capability::SplitCap>( *cit ) ) {
00450
00451 capability::CapabilityImpl::SplitInfo splitinfo = capability::CapabilityImpl::getSplitInfo( *cit );
00452
00453 PoolItem splititem = Helper::findInstalledByNameAndKind (_pool, splitinfo.name, ResTraits<zypp::Package>::kind);
00454 MIL << "has split cap " << splitinfo.name << ":" << splitinfo.path << ", splititem:" << splititem << endl;
00455 if (splititem) {
00456 if (target) {
00457 ResObject::constPtr robj = target->whoOwnsFile( splitinfo.path );
00458 if (robj)
00459 MIL << "whoOwnsFile(): " << *robj << endl;
00460 if (robj
00461 && robj->name() == splitinfo.name)
00462 {
00463 MIL << "split matched !" << endl;
00464 splitmap[splititem].insert( candidate );
00465 }
00466 }
00467 }
00468 }
00469 }
00470
00471 }
00472
00473
00474 for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00475 it->status().setSeen( false );
00476 }
00477
00478 MIL << "doUpgrade: " << opt_stats_r.pre_todel << " packages tagged to delete" << endl;
00479 MIL << "doUpgrade: " << opt_stats_r.pre_nocand << " packages without candidate (foreign, replaced or dropped)" << endl;
00480 MIL << "doUpgrade: " << opt_stats_r.pre_avcand << " packages available for update" << endl;
00481
00482 MIL << "doUpgrade: going to check " << splitmap.size() << " probably splitted packages" << endl;
00483 {
00485
00486
00487
00488
00489
00490
00492
00493 PoolItem_Ref citem;
00494
00495 for ( SplitMap::iterator it = splitmap.begin(); it != splitmap.end(); ++it ) {
00496 applyingSplits[it->first].insert( it->second.begin(), it->second.end() );
00497 _DEBUG(" split count for " << it->first->name() << " now " << applyingSplits[it->first].size());
00498 }
00499 splitmap.clear();
00500 }
00501
00503
00504
00505
00506
00508 MIL << "doUpgrade pass 1..." << endl;
00509
00510 for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
00511
00512 PoolItem_Ref installed(*it);
00513 ResStatus status (installed.status());
00514
00515 if ( ! status.staysInstalled() ) {
00516 continue;
00517 }
00518 ++opt_stats_r.chk_installed_total;
00519
00520 if ( status.transacts() ) {
00521 MIL << "SKIP to delete: " << installed.resolvable() << endl;
00522 ++opt_stats_r.chk_already_todel;
00523 continue;
00524 }
00525
00526 if ( installed.status().isLocked() ) {
00527 MIL << "SKIP taboo: " << installed << endl;
00528 ++opt_stats_r.chk_is_taboo;
00529 _update_items.push_back( installed );
00530 continue;
00531 }
00532
00533 if ( isKind<Patch>(installed.resolvable())
00534 || isKind<Atom>(installed.resolvable())
00535 || isKind<Script>(installed.resolvable())
00536 || isKind<Message>(installed.resolvable()) )
00537 {
00538 if ( ! opt_stats_r.keep_installed_patches )
00539 {
00540 if ( isKind<Patch>(installed.resolvable()) )
00541 MIL << "OUTDATED Patch: " << installed << endl;
00542 installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00543 }
00544 else
00545 {
00546 if ( isKind<Patch>(installed.resolvable()) )
00547 MIL << "SKIP Patch: " << installed << endl;
00548 }
00549 continue;
00550 }
00551
00552 CandidateMap::iterator cand_it = candidatemap.find( installed );
00553
00554 bool probably_dropped = false;
00555
00556 MIL << "REPLACEMENT FOR " << installed << endl;
00558
00560 if ( cand_it != candidatemap.end() ) {
00561
00562 PoolItem_Ref candidate (cand_it->second);
00563
00564 if ( ! candidate.status().isToBeInstalled() ) {
00565 int cmp = installed->edition().compare( candidate->edition() );
00566 if ( cmp < 0 ) {
00567 setForInstallation (_pool,candidate);
00568 MIL << " ==> INSTALL (new version): " << candidate << endl;
00569 ++opt_stats_r.chk_to_update;
00570 } else {
00571
00572
00573 if (cmp == 0
00574 || !downgrade_allowed( installed, candidate,
00575 opt_stats_r.silent_downgrades) )
00576 {
00577 MIL << " ==> (keep installed)" << candidate << endl;
00578 ++opt_stats_r.chk_to_keep_installed;
00579 } else {
00580 setForInstallation (_pool, candidate);
00581 MIL << " ==> INSTALL (SuSE version downgrade): " << candidate << endl;
00582 ++opt_stats_r.chk_to_downgrade;
00583 }
00584 }
00585 } else {
00586 MIL << " ==> INSTALL (preselected): " << candidate << endl;
00587 ++opt_stats_r.chk_already_toins;
00588 }
00589
00590 }
00591 else {
00592
00593
00594
00595
00596
00597 Dep dep (Dep::PROVIDES);
00598 CapFactory factory;
00599 Capability installedCap = factory.parse( installed->kind(), installed->name(), Rel::GE, installed->edition() );
00600
00601 FindProviders info(installed);
00602
00603 invokeOnEach( _pool.byCapabilityIndexBegin( installed->name(), dep ),
00604 _pool.byCapabilityIndexEnd( installed->name(), dep ),
00605 functor::chain( resfilter::ByCaIUninstalled(),
00606 resfilter::ByCapMatch( installedCap ) ) ,
00607 functor::functorRef<bool,CapAndItem>(info) );
00608
00609 int num_providers = info.providers.size();
00610
00611 _DEBUG("lookup " << num_providers << " provides for installed " << installedCap);
00612
00613
00614 PoolItemOrderSet providers;
00615 for (FindMap::const_iterator mapit = info.providers.begin(); mapit != info.providers.end(); ++mapit) {
00616 providers.insert( mapit->second );
00617 }
00618
00619 switch ( info.providers.size() ) {
00620 case 0:
00621 if (info.otherVendorFound) {
00622 MIL << " only resolvable with other vendor found ==> do nothing" << endl;
00623 } else {
00624 MIL << " ==> (dropped)" << endl;
00625
00626
00627
00628 probably_dropped = true;
00629 }
00630 break;
00631 case 1:
00632 addProvided[installed] = providers;
00633 MIL << " ==> REPLACED by: " << (*providers.begin()) << endl;
00634
00635
00636 break;
00637 default:
00638 addMultiProvided[installed] = providers;
00639 MIL << " ==> pass 2 (" << providers.size() << " times provided)" << endl;
00640
00641
00642 break;
00643 }
00644
00645 }
00646
00648
00650
00651 TodoMap::iterator sit = applyingSplits.find( installed );
00652 if ( sit != applyingSplits.end() ) {
00653 PoolItemOrderSet & toadd( sit->second );
00654 if ( !toadd.size() ) {
00655 INT << "Empty SplitPkgMap entry for " << installed << endl;
00656 } else {
00657 FindMap candidate;
00658 for ( PoolItemOrderSet::iterator ait = toadd.begin(); ait != toadd.end(); ++ait ) {
00659 PoolItem_Ref split_candidate = *ait;
00660 if ( probably_dropped
00661 && split_candidate.status().staysUninstalled()
00662 && doesObsoleteItem (split_candidate, installed))
00663 {
00664 probably_dropped = false;
00665 }
00666
00667 FindMap::iterator itcandidate = candidate.find( split_candidate->name() );
00668
00669 if (itcandidate != candidate.end()) {
00670 if (split_candidate.status().isToBeInstalled()
00671 || itcandidate->second.status().isToBeInstalled()) {
00672
00673 if (split_candidate.status().isToBeInstalled()
00674 && itcandidate->second.status().isToBeInstalled()) {
00675 ERR << "only one should be set for installation: " << itcandidate->second << "; " << split_candidate << endl;
00676 } else {
00677 if (split_candidate.status().isToBeInstalled()) {
00678 itcandidate->second = split_candidate;
00679 }
00680 }
00681 } else {
00682
00683 if (itcandidate->second->arch() != installed->arch()
00684 && split_candidate->arch() == installed->arch() ) {
00685
00686 itcandidate->second = split_candidate;
00687 } else {
00688 int cmp = itcandidate->second->arch().compare( split_candidate->arch() );
00689 if (cmp < 0) {
00690 itcandidate->second = split_candidate;
00691 }
00692 else if (cmp == 0) {
00693 if (itcandidate->second->edition().compare( split_candidate->edition() ) < 0) {
00694 itcandidate->second = split_candidate;
00695 }
00696 }
00697 }
00698 }
00699 }
00700 else {
00701 candidate[split_candidate->name()] = split_candidate;
00702 }
00703 }
00704
00705 PoolItemOrderSet addcandidate;
00706 for (FindMap::iterator itcandidate = candidate.begin() ; itcandidate != candidate.end(); itcandidate++) {
00707 addcandidate.insert(itcandidate->second);
00708 MIL << " ==> ADD (splitted): " << itcandidate->second << endl;
00709 }
00710
00711 addSplitted[installed] = addcandidate;
00712 }
00713
00714 }
00715
00717
00719
00720 if ( probably_dropped ) {
00721 if ( opt_stats_r.delete_unmaintained
00722 && VendorAttr::instance().equivalent( installed->vendor(), "suse" ) ) {
00723 installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00724 }
00725 ++opt_stats_r.chk_dropped;
00726 _update_items.push_back( installed );
00727 }
00728
00729 }
00730
00732
00733
00734
00736 MIL << "doUpgrade pass 2..." << endl;
00737
00738
00739
00740 for ( TodoMap::iterator it = addProvided.begin(); it != addProvided.end(); ++it ) {
00741
00742 PoolItemOrderSet & tset( it->second );
00743
00744 for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
00745 PoolItem_Ref provider (*sit);
00746
00747 if (setForInstallation (_pool, provider)) {
00748 ++opt_stats_r.chk_replaced;
00749 }
00750
00751
00752
00753 if ( doesObsoleteItem (provider, it->first ) ) {
00754 it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00755 }
00756 }
00757
00758 }
00759
00760
00761
00762 for ( TodoMap::iterator it = addSplitted.begin(); it != addSplitted.end(); ++it ) {
00763
00764 PoolItemOrderSet & tset( it->second );
00765 PoolItem_Ref lastItem = PoolItem_Ref();
00766
00767 for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
00768 if (!lastItem
00769 || compareByN ( lastItem.resolvable(), sit->resolvable()) != 0)
00770 {
00771 PoolItem_Ref item( *sit );
00772
00773
00774
00775 PoolItem_Ref already_installed = Helper::findInstalledItem( _pool, item );
00776 if (!already_installed
00777 || already_installed->edition().compare( item->edition() ) != 0 )
00778 {
00779 if (setForInstallation (_pool, item)) {
00780 ++opt_stats_r.chk_add_split;
00781 }
00782 }
00783 }
00784 lastItem = *sit;
00785 }
00786
00787 }
00788
00789
00790
00791 for ( TodoMap::iterator it = addMultiProvided.begin(); it != addMultiProvided.end(); ++it ) {
00792 MIL << "GET ONE OUT OF " << it->second.size() << " for " << it->first << endl;
00793
00794 PoolItem_Ref guess;
00795 PoolItemOrderSet & gset( it->second );
00796
00797 for ( PoolItemOrderSet::iterator git = gset.begin(); git != gset.end(); ++git ) {
00798 PoolItem_Ref item (*git);
00799
00800 if (git == gset.begin())
00801 guess = item;
00802
00803 if ( item.status().isToBeInstalled()) {
00804 MIL << " ==> (pass 2: meanwhile set to install): " << item << endl;
00805 if ( ! doesObsoleteItem (item, it->first ) ) {
00806 it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00807 }
00808 guess = PoolItem_Ref();
00809 break;
00810 } else {
00811
00812
00813
00814
00815
00816
00817 if ( !guess || guess->name().size() > item->name().size() ) {
00818 guess = item;
00819 }
00820 }
00821 }
00822
00823 if ( guess ) {
00824
00825
00826 bool requested_locale_match = false;
00827 CapSet freshens( guess->dep( Dep::FRESHENS ) );
00828
00829
00830 for (CapSet::const_iterator cit = freshens.begin(); cit != freshens.end(); ++cit) {
00831 if (cit->refers() == ResTraits<Language>::kind) {
00832 requested_locale_match = true;
00833 break;
00834 }
00835 }
00836
00837 if (requested_locale_match) {
00838
00839 PoolItemOrderSet & gset( it->second );
00840 requested_locale_match = false;
00841
00842 for ( PoolItemOrderSet::iterator git = gset.begin(); git != gset.end(); ++git ) {
00843 PoolItem_Ref item (*git);
00844
00845 if ( item.status().isToBeInstalled()) {
00846 MIL << " ==> (pass 2: meanwhile set to install): " << item << endl;
00847 if ( ! doesObsoleteItem (item, it->first ) ) {
00848 it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00849 }
00850 guess = PoolItem_Ref();
00851 break;
00852 } else {
00853 freshens = item->dep( Dep::FRESHENS );
00854 ZYpp::Ptr z = zypp::getZYpp();
00855 ZYpp::LocaleSet requested_locales = z->getRequestedLocales();
00856
00857
00858
00859 for (CapSet::const_iterator cit = freshens.begin(); cit != freshens.end(); ++cit) {
00860 if (cit->refers() == ResTraits<Language>::kind) {
00861 string loc = cit->index();
00862 MIL << "Look for language fallback " << loc << ":" << item << endl;
00863 if (requested_locales.find( Locale( loc ) ) != requested_locales.end()) {
00864 MIL << "Locale '" << loc << "' is requested" << endl;
00865 requested_locale_match = true;
00866 guess = item;
00867 break;
00868 }
00869 }
00870 }
00871 }
00872 if (requested_locale_match) break;
00873 }
00874 }
00875 }
00876
00877 if ( guess ) {
00878 setForInstallation (_pool, guess);
00879 MIL << " ==> REPLACED by: (pass 2: guessed): " << guess << endl;
00880 if ( ! doesObsoleteItem (guess, it->first ) ) {
00881 it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
00882 }
00883 ++opt_stats_r.chk_replaced_guessed;
00884 }
00885 }
00886
00888
00890 MIL << opt_stats_r << endl;
00891
00892
00893 _upgradeMode = true;
00894 }
00895
00897 };
00900 };
00903 };
00905
00906