00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <sys/utsname.h>
00023
00024 #include "zypp/solver/detail/Resolver.h"
00025 #include "zypp/solver/detail/Helper.h"
00026
00027 #include "zypp/CapSet.h"
00028 #include "zypp/base/Logger.h"
00029 #include "zypp/base/String.h"
00030 #include "zypp/base/Gettext.h"
00031
00032 #include "zypp/base/Algorithm.h"
00033 #include "zypp/ResPool.h"
00034 #include "zypp/ResFilters.h"
00035 #include "zypp/CapFilters.h"
00036 #include "zypp/ZYppFactory.h"
00037 #include "zypp/SystemResObject.h"
00038
00039
00040
00042 namespace zypp
00043 {
00044
00045 namespace solver
00046 {
00047
00048 namespace detail
00049 {
00050
00051 using namespace std;
00052
00053 IMPL_PTR_TYPE(Resolver);
00054
00055
00056
00057 std::ostream &
00058 Resolver::dumpOn( std::ostream & os ) const
00059 {
00060 return os << "<resolver/>";
00061 }
00062
00063
00064
00065 void assertSystemResObjectInPool()
00066 {
00067 ResPool pool( getZYpp()->pool() );
00068 if ( pool.byKindBegin<SystemResObject>()
00069 == pool.byKindEnd<SystemResObject>() )
00070 {
00071
00072 ResStore store;
00073 store.insert( SystemResObject::instance() );
00074 getZYpp()->addResolvables( store, true );
00075 }
00076
00077
00078 if ( ! pool.byKindBegin<SystemResObject>()
00079 ->status().setLock( true, ResStatus::USER ) )
00080 {
00081 WAR << "Unable to set SystemResObject to lock" << endl;
00082 }
00083 }
00084
00085
00086
00087 Resolver::Resolver (const ResPool & pool)
00088 : _pool (pool)
00089 , _timeout_seconds (0)
00090 , _verifying (false)
00091 , _testing (false)
00092 , _valid_solution_count (0)
00093 , _best_context (NULL)
00094 , _timed_out (false)
00095 , _forceResolve (false)
00096 , _upgradeMode (false)
00097 {
00098 struct utsname buf;
00099 if (uname (&buf) < 0) {
00100 ERR << "Can't determine system architecture" << endl;
00101 }
00102 else {
00103 MIL << "System architecture is '" << buf.machine << "'" << endl;
00104 _architecture = Arch(buf.machine);
00105 }
00106 }
00107
00108
00109 Resolver::~Resolver()
00110 {
00111 }
00112
00113
00114
00115 ResPool
00116 Resolver::pool (void) const
00117 {
00118 return _pool;
00119 }
00120
00121 void
00122 Resolver::reset (void)
00123 {
00124 _timeout_seconds = 0;
00125 _verifying = false;
00126
00127 _initial_items.clear();
00128
00129 _items_to_install.clear();
00130 _items_to_remove.clear();
00131 _items_to_verify.clear();
00132 _items_to_establish.clear();
00133
00134 _extra_caps.clear();
00135 _extra_conflicts.clear();
00136
00137 _pending_queues.clear();
00138 _pruned_queues.clear();
00139 _complete_queues.clear();
00140 _deferred_queues.clear();
00141 _invalid_queues.clear();
00142
00143 _valid_solution_count = 0;
00144
00145 _best_context = NULL;
00146 _timed_out = false;
00147 }
00148
00149
00150 ResolverContext_Ptr
00151 Resolver::context (void) const
00152 {
00153 if (_best_context) return _best_context;
00154 if (_invalid_queues.empty()) return NULL;
00155 ResolverQueue_Ptr invalid = _invalid_queues.front();
00156 return invalid->context();
00157 }
00158
00159
00160
00161 void
00162 Resolver::addSubscribedSource (Source_Ref source)
00163 {
00164 _subscribed.insert(source);
00165 }
00166
00167 void
00168 Resolver::addPoolItemToInstall (PoolItem_Ref item)
00169 {
00170 bool found = false;
00171 for (PoolItemList::const_iterator iter = _items_to_remove.begin();
00172 iter != _items_to_remove.end(); iter++) {
00173 if (*iter == item) {
00174 _items_to_remove.remove(*iter);
00175 found = true;
00176 break;
00177 }
00178 }
00179 if (!found)
00180 _items_to_install.push_back (item);
00181 }
00182
00183
00184 void
00185 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
00186 {
00187 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00188 addPoolItemToInstall (*iter);
00189 }
00190 }
00191
00192
00193 void
00194 Resolver::addPoolItemToRemove (PoolItem_Ref item)
00195 {
00196 bool found = false;
00197 for (PoolItemList::const_iterator iter = _items_to_install.begin();
00198 iter != _items_to_install.end(); iter++) {
00199 if (*iter == item) {
00200 _items_to_install.remove(*iter);
00201 found = true;
00202 break;
00203 }
00204 }
00205 if (!found)
00206 _items_to_remove.push_back (item);
00207 }
00208
00209
00210 void
00211 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
00212 {
00213 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00214 addPoolItemToRemove (*iter);
00215 }
00216 }
00217
00218
00219 void
00220 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
00221 {
00222 _items_to_establish.push_back (item);
00223 }
00224
00225
00226 void
00227 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
00228 {
00229 for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00230 addPoolItemToEstablish (*iter);
00231 }
00232 }
00233
00234
00235 void
00236 Resolver::addPoolItemToVerify (PoolItem_Ref item)
00237 {
00238 #if 0
00239
00240 struct {
00242 bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
00243 {
00244 int res = lhs->name().compare( rhs->name() );
00245 if ( res )
00246 return res == -1;
00247
00248 return lhs->edition() < rhs->edition();
00249 }
00250 } order;
00251 #endif
00252
00253 _items_to_verify.push_back (item);
00254
00255 #warning Should order by name (and probably edition since with zypp we could have multiple editions installed in parallel)
00256
00257 }
00258
00259
00260 void
00261 Resolver::addExtraCapability (const Capability & capability)
00262 {
00263 _extra_caps.insert (capability);
00264 }
00265
00266
00267 void
00268 Resolver::addExtraConflict (const Capability & capability)
00269 {
00270 _extra_conflicts.insert (capability);
00271 }
00272
00273
00274 void
00275 Resolver::addIgnoreConflict (const PoolItem_Ref item,
00276 const Capability & capability)
00277 {
00278 _ignoreConflicts.insert(make_pair(item, capability));
00279 }
00280
00281
00282 void
00283 Resolver::addIgnoreRequires (const PoolItem_Ref item,
00284 const Capability & capability)
00285 {
00286 _ignoreRequires.insert(make_pair(item, capability));
00287 }
00288
00289 void
00290 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
00291 const Capability & capability)
00292 {
00293 _ignoreObsoletes.insert(make_pair(item, capability));
00294 }
00295
00296 void
00297 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
00298 {
00299 _ignoreInstalledItem.push_back (item);
00300 }
00301
00302 void
00303 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
00304 {
00305 _ignoreArchitectureItem.push_back (item);
00306 }
00307
00308
00309
00310
00311 struct VerifySystem : public resfilter::PoolItemFilterFunctor
00312 {
00313 Resolver & resolver;
00314
00315 VerifySystem (Resolver & r)
00316 : resolver (r)
00317 { }
00318
00319 bool operator()( PoolItem_Ref provider )
00320 {
00321 resolver.addPoolItemToVerify (provider);
00322 return true;
00323 }
00324 };
00325
00326
00327 bool
00328 Resolver::verifySystem (void)
00329 {
00330 _DEBUG( "Resolver::verifySystem()" );
00331
00332 VerifySystem info (*this);
00333
00334 invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
00335 pool().byKindEnd( ResTraits<Package>::kind ),
00336 resfilter::ByInstalled ( ),
00337 functor::functorRef<bool,PoolItem>(info) );
00338
00339
00340 _verifying = true;
00341
00342 return resolveDependencies ();
00343 }
00344
00345
00346
00347
00348
00349
00350
00351 static void
00352 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
00353 {
00354 bool r;
00355
00356 if (status.isToBeInstalled()) {
00357 r = item.status().setToBeInstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00358 _XDEBUG("solution_to_pool(" << item << ", " << status << ") install !" << r);
00359 }
00360 else if (status.isToBeUninstalledDueToUpgrade()) {
00361 r = item.status().setToBeUninstalledDueToUpgrade( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00362 _XDEBUG("solution_to_pool(" << item << ", " << status << ") upgrade !" << r);
00363 }
00364 else if (status.isToBeUninstalled()) {
00365 r = item.status().setToBeUninstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00366 _XDEBUG("solution_to_pool(" << item << ", " << status << ") remove !" << r);
00367 }
00368 else if (status.isIncomplete()
00369 || status.isNeeded()) {
00370 r = item.status().setIncomplete();
00371 _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
00372 }
00373 else if (status.isUnneeded()) {
00374 r = item.status().setUnneeded();
00375 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
00376 }
00377 else if (status.isSatisfied()) {
00378 r = item.status().setSatisfied();
00379 _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
00380 } else {
00381 _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
00382 }
00383 return;
00384 }
00385
00386
00387
00388
00389
00390 struct EstablishState
00391 {
00392 Resolver & resolver;
00393
00394 EstablishState (Resolver & r)
00395 : resolver (r)
00396 { }
00397
00398 bool operator()( PoolItem_Ref provider )
00399 {
00400 resolver.addPoolItemToEstablish (provider);
00401 return true;
00402 }
00403 };
00404
00405
00406 void
00407 Resolver::establishState( ResolverContext_Ptr context )
00408 {
00409 _DEBUG( "Resolver::establishState ()" );
00410 typedef list<Resolvable::Kind> KindList;
00411 static KindList ordered;
00412 if (ordered.empty()) {
00413 ordered.push_back (ResTraits<zypp::Atom>::kind);
00414 ordered.push_back (ResTraits<zypp::Message>::kind);
00415 ordered.push_back (ResTraits<zypp::Script>::kind);
00416 ordered.push_back (ResTraits<zypp::Patch>::kind);
00417 ordered.push_back (ResTraits<zypp::Pattern>::kind);
00418 ordered.push_back (ResTraits<zypp::Product>::kind);
00419 }
00420
00421 if (context == NULL)
00422 context = new ResolverContext(_pool, _architecture);
00423
00424 context->setEstablishing (true);
00425 context->setIgnoreCababilities (_ignoreConflicts,
00426 _ignoreRequires,
00427 _ignoreObsoletes,
00428 _ignoreInstalledItem,
00429 _ignoreArchitectureItem);
00430 context->setForceResolve( _forceResolve );
00431 context->setUpgradeMode( _upgradeMode );
00432
00433 for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
00434 const Resolvable::Kind kind = *iter;
00435
00436 _XDEBUG( "establishing state for kind " << kind.asString() );
00437
00438
00439
00440 EstablishState info (*this);
00441
00442 invokeOnEach( pool().byKindBegin( kind ),
00443 pool().byKindEnd( kind ),
00444 functor::functorRef<bool,PoolItem>(info) );
00445
00446
00447 resolveDependencies( context );
00448
00449 reset();
00450 }
00451
00452 context->setEstablishing (false);
00453
00454 _best_context = context;
00455
00456 return;
00457 }
00458
00459
00460 bool
00461 Resolver::establishPool ()
00462 {
00463 MIL << "Resolver::establishPool()" << endl;
00464
00465 establishState ();
00466 ResolverContext_Ptr solution = bestContext();
00467
00468 if (solution) {
00469 solution->foreachMarked (solution_to_pool, (void *)1);
00470 }
00471 else {
00472 ERR << "establishState did not return a bestContext" << endl;
00473 return false;
00474 }
00475
00476 return true;
00477 }
00478
00479
00480
00481
00482
00483 typedef map<string, PoolItem_Ref> FreshenMap;
00484
00485
00486
00487
00488
00489 static void
00490 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
00491 {
00492 FreshenMap::iterator it = itemmap.find( item->name() );
00493 if (it != itemmap.end()) {
00494 int cmp = it->second->arch().compare( item->arch() );
00495 if (cmp < 0) {
00496 it->second = item;
00497 }
00498 else if (cmp == 0) {
00499 if (it->second->edition().compare( item->edition() ) < 0) {
00500 it->second = item;
00501 }
00502 }
00503 }
00504 else {
00505 itemmap[item->name()] = item;
00506 }
00507 return;
00508 }
00509
00510
00511 struct FreshenState
00512 {
00513 FreshenMap itemmap;
00514
00515 FreshenState()
00516 { }
00517
00518 bool operator()( PoolItem_Ref item)
00519 {
00520 CapSet freshens( item->dep( Dep::FRESHENS ) );
00521 if (!freshens.empty()) {
00522 addToFreshen( item, itemmap );
00523 }
00524 else {
00525
00526
00527 CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
00528 if (!supplements.empty()) {
00529 addToFreshen( item, itemmap );
00530 }
00531 }
00532 return true;
00533 }
00534 };
00535
00536
00537 void
00538 Resolver::freshenState( ResolverContext_Ptr context )
00539 {
00540 _DEBUG( "Resolver::freshenState ()" );
00541
00542 if (context == NULL)
00543 context = new ResolverContext( _pool, _architecture );
00544
00545 context->setEstablishing( true );
00546 context->setIgnoreCababilities( _ignoreConflicts,
00547 _ignoreRequires,
00548 _ignoreObsoletes,
00549 _ignoreInstalledItem,
00550 _ignoreArchitectureItem );
00551 context->setForceResolve( _forceResolve );
00552 context->setUpgradeMode( _upgradeMode );
00553
00554 FreshenState info;
00555
00556
00557
00558 invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
00559 pool().byKindEnd( ResTraits<zypp::Package>::kind ),
00560 functor::functorRef<bool,PoolItem>(info) );
00561
00562
00563
00564 for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
00565 addPoolItemToEstablish( it->second );
00566 }
00567
00568
00569 resolveDependencies( context );
00570
00571 reset();
00572
00573 context->setEstablishing( false );
00574
00575 _best_context = context;
00576
00577 return;
00578 }
00579
00580
00581 bool
00582 Resolver::freshenPool ()
00583 {
00584 MIL << "Resolver::freshenPool()" << endl;
00585
00586 freshenState ();
00587 ResolverContext_Ptr solution = bestContext();
00588
00589 if (solution) {
00590 solution->foreachMarked (solution_to_pool, (void *)1);
00591 }
00592 else {
00593 ERR << "freshenState did not return a bestContext" << endl;
00594 return false;
00595 }
00596
00597 return true;
00598 }
00599
00600
00601
00602 bool
00603 Resolver::resolveDependencies (const ResolverContext_Ptr context)
00604 {
00605
00606 time_t t_start, t_now;
00607
00608 MIL << "Resolver::resolveDependencies()" << endl;
00609
00610 _pending_queues.clear();
00611 _pruned_queues.clear();
00612 _complete_queues.clear();
00613 _deferred_queues.clear();
00614 _invalid_queues.clear();
00615 _valid_solution_count = 0;
00616 _best_context = NULL;
00617
00618 #warning local items disabled
00619 #if 0
00620 bool have_local_items = false;
00621
00622
00623
00624 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00625 if ((*iter)->local()) {
00626 have_local_items = true;
00627 break;
00628 }
00629 }
00630
00631 World_Ptr the_world = world();
00632 StoreWorld_Ptr local_world = NULL;
00633 MultiWorld_Ptr local_multiworld = NULL;
00634
00635 Channel_Ptr local_channel = NULL;
00636
00637 if (have_local_items) {
00638 local_multiworld = new MultiWorld();
00639 local_world = new StoreWorld();
00640
00641 local_channel = new Channel ("", "Local ResItems", "@local", "");
00642
00643 local_world->addChannel (local_channel);
00644
00645 local_multiworld->addSubworld (local_world);
00646 local_multiworld->addSubworld (the_world);
00647
00648 the_world = local_multiworld;
00649 }
00650 #endif
00651
00652
00653
00654 ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
00655
00656
00657 initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
00658 _ignoreRequires,
00659 _ignoreObsoletes,
00660 _ignoreInstalledItem,
00661 _ignoreArchitectureItem);
00662 initial_queue->context()->setForceResolve( _forceResolve );
00663 initial_queue->context()->setUpgradeMode( _upgradeMode );
00664
00665
00666
00667 initial_queue->context()->setVerifying( _verifying );
00668
00669
00670
00671 for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
00672 initial_queue->addItem (*iter);
00673 }
00674
00675 for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00676 PoolItem_Ref r = *iter;
00677
00678 #warning local items disabled
00679 #if 0
00680
00681 if (r->local()) {
00682 assert (local_channel != NULL);
00683 ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
00684 r1->setChannel (local_channel);
00685 local_world->addPoolItem_Ref (r);
00686 }
00687 #endif
00688 initial_queue->addPoolItemToInstall (r);
00689 }
00690
00691 for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
00692 if (!_upgradeMode)
00693 initial_queue->addPoolItemToRemove (*iter, true );
00694 else
00695
00696
00697
00698
00699
00700 initial_queue->addPoolItemToRemove (*iter, false );
00701 }
00702
00703 for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
00704 initial_queue->addPoolItemToVerify (*iter);
00705 }
00706
00707 for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
00708 initial_queue->addPoolItemToEstablish (*iter);
00709 }
00710
00711 for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
00712 initial_queue->addExtraCapability (*iter);
00713 }
00714
00715 for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
00716 initial_queue->addExtraConflict (*iter);
00717 }
00718
00719
00720 assertSystemResObjectInPool();
00721
00722 _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
00723
00724 if (initial_queue->isEmpty()) {
00725 INT << "Empty Queue, nothing to resolve" << endl;
00726
00727 return true;
00728 }
00729
00730 _best_context = NULL;
00731
00732 _pending_queues.push_front (initial_queue);
00733
00734 time (&t_start);
00735
00736 while (!_pending_queues.empty()) {
00737
00738 _DEBUG( "Pend " << (long) _pending_queues.size()
00739 << " / Cmpl " << (long) _complete_queues.size()
00740 << " / Prun " << (long) _pruned_queues.size()
00741 << " / Defr " << (long) _deferred_queues.size()
00742 << " / Invl " << (long) _invalid_queues.size() );
00743
00744 if (_timeout_seconds > 0) {
00745 time (&t_now);
00746 if (difftime (t_now, t_start) > _timeout_seconds) {
00747 _timed_out = true;
00748 break;
00749 }
00750 }
00751
00752 ResolverQueue_Ptr queue = _pending_queues.front();
00753 _pending_queues.pop_front();
00754 ResolverContext_Ptr context = queue->context();
00755
00756 queue->process();
00757
00758 if (queue->isInvalid ()) {
00759
00760 _XDEBUG( "Invalid Queue\n" );
00761 _invalid_queues.push_back(queue);
00762
00763 } else if (queue->isEmpty ()) {
00764
00765 _XDEBUG( "Empty Queue\n" );
00766
00767 _complete_queues.push_back(queue);
00768
00769 ++_valid_solution_count;
00770
00771
00772
00773
00774
00775 if (_best_context == NULL
00776 || _best_context->compare (context) < 0)
00777 {
00778 _best_context = context;
00779 }
00780
00781 } else if (_best_context != NULL
00782 && _best_context->partialCompare (context) > 0) {
00783
00784
00785
00786
00787 _XDEBUG( "PRUNED!" );
00788
00789 _pruned_queues.push_back(queue);
00790
00791 } else {
00792
00793
00794
00795
00796 queue->splitFirstBranch (_pending_queues, _deferred_queues);
00797 }
00798
00799
00800
00801
00802
00803 if (_pending_queues.empty()
00804 && _complete_queues.empty()
00805 && !_deferred_queues.empty()) {
00806 _pending_queues.push_back(_deferred_queues.front());
00807 }
00808 }
00809 _DEBUG("Pend " << (long) _pending_queues.size()
00810 << " / Cmpl " << (long) _complete_queues.size()
00811 << " / Prun " << (long) _pruned_queues.size()
00812 << " / Defr " << (long) _deferred_queues.size()
00813 << " / Invl " << (long) _invalid_queues.size() );
00814
00815 return _best_context && _best_context->isValid();
00816 }
00817
00818
00819
00820
00821
00822 struct UndoTransact : public resfilter::PoolItemFilterFunctor
00823 {
00824 UndoTransact ()
00825 { }
00826
00827 bool operator()( PoolItem_Ref item )
00828 {
00829 item.status().resetTransact( ResStatus::APPL_LOW );
00830 return true;
00831 }
00832 };
00833
00834 void
00835 Resolver::undo(void)
00836 {
00837 UndoTransact info;
00838 MIL << "*** undo ***" << endl;
00839 invokeOnEach ( _pool.begin(), _pool.end(),
00840 resfilter::ByTransact( ),
00841 functor::functorRef<bool,PoolItem>(info) );
00842
00843 _ignoreConflicts.clear();
00844
00845 _ignoreRequires.clear();
00846
00847 _ignoreObsoletes.clear();
00848
00849 _ignoreArchitecture.clear();
00850
00851 _ignoreInstalledItem.clear();
00852
00853 _ignoreArchitectureItem.clear();
00854
00855
00856 return;
00857 }
00858
00859
00860
00861
00862 struct CollectTransact : public resfilter::PoolItemFilterFunctor
00863 {
00864 Resolver & resolver;
00865
00866 CollectTransact (Resolver & r)
00867 : resolver (r)
00868 { }
00869
00870 bool operator()( PoolItem_Ref item )
00871 {
00872 ResStatus status = item.status();
00873 _XDEBUG( "CollectTransact(" << item << ")" );
00874 bool by_solver = (status.isBySolver() || status.isByApplLow());
00875
00876 if (by_solver) {
00877 item.status().resetTransact( ResStatus::APPL_LOW );
00878 return true;
00879 }
00880
00881 if (status.isToBeInstalled()) {
00882 resolver.addPoolItemToInstall(item);
00883 }
00884 if (status.isToBeUninstalled()) {
00885 resolver.addPoolItemToRemove(item);
00886 }
00887 if (status.isIncomplete()) {
00888 PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
00889 if (reinstall) {
00890 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
00891 resolver.addPoolItemToInstall(reinstall);
00892 }
00893 else {
00894 WAR << "Can't find " << item << " for re-installation" << endl;
00895 }
00896 }
00897 return true;
00898 }
00899 };
00900
00901
00902 static void
00903 show_pool( ResPool pool )
00904 {
00905 int count = 1;
00906 static bool full_pool_shown = true;
00907
00908 _XDEBUG( "---------------------------------------" );
00909 for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
00910
00911 if (!full_pool_shown
00912 || it->status().transacts()
00913 || !it->status().isUndetermined())
00914 {
00915 _DEBUG( count << ": " << *it );
00916 }
00917 }
00918 _XDEBUG( "---------------------------------------" );
00919 full_pool_shown = true;
00920 }
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 bool
00939 Resolver::resolvePool ()
00940 {
00941
00942 CollectTransact info (*this);
00943
00944
00945 reset();
00946
00947 #if 1
00948
00949 MIL << "Resolver::resolvePool()" << endl;
00950 _XDEBUG( "Pool before resolve" );
00951 show_pool( _pool );
00952
00953 #endif
00954 invokeOnEach ( _pool.begin(), _pool.end(),
00955 resfilter::ByTransact( ),
00956 functor::functorRef<bool,PoolItem>(info) );
00957
00958 bool have_solution = resolveDependencies ();
00959
00960 if (have_solution) {
00961 MIL << "Have solution, copying back to pool" << endl;
00962 ResolverContext_Ptr solution = bestContext();
00963 solution->foreachMarked (solution_to_pool, NULL);
00964 #if 1
00965 _XDEBUG( "Pool after resolve" );
00966 show_pool( _pool );
00967 #endif
00968 }
00969 else {
00970 MIL << "!!! Have NO solution !!!" << endl;
00971 }
00972 return have_solution;
00973 }
00974
00975
00976
00977
00978
00979
00980
00981
00982 static bool
00983 transactItems( PoolItem_Ref installed, PoolItem_Ref uninstalled, bool install, bool soft, PoolItem_Ref & added )
00984 {
00985 if (install) {
00986 if (compareByNVRA (installed.resolvable(), uninstalled.resolvable()) != 0) {
00987 if (uninstalled
00988 && !uninstalled.status().isLocked())
00989 {
00990 bool adding;
00991 if (soft)
00992 adding = uninstalled.status().setSoftTransact( true, ResStatus::APPL_LOW );
00993 else
00994 adding = uninstalled.status().setTransact( true, ResStatus::APPL_LOW );
00995 if (adding)
00996 added = uninstalled;
00997 }
00998 if (installed
00999 && !installed.status().isLocked())
01000 {
01001 installed.status().resetTransact( ResStatus::APPL_LOW );
01002 }
01003 }
01004 } else {
01005
01006 if (uninstalled
01007 && !uninstalled.status().isLocked())
01008 {
01009 uninstalled.status().resetTransact( ResStatus::APPL_LOW );
01010 }
01011 if (installed
01012 && !installed.status().isLocked())
01013 {
01014 if (soft)
01015 installed.status().setSoftTransact( true, ResStatus::APPL_LOW );
01016 else
01017 installed.status().setTransact( true, ResStatus::APPL_LOW );
01018 }
01019 }
01020 if (!uninstalled
01021 && !installed)
01022 {
01023 return false;
01024 }
01025 return true;
01026 }
01027
01028
01029 typedef struct { PoolItem_Ref installed; PoolItem_Ref uninstalled; } IandU;
01030 typedef map<string, IandU> IandUMap;
01031
01032
01033
01034
01035 struct FindIandU
01036 {
01037 IandUMap iandu;
01038
01039 FindIandU ()
01040 { }
01041
01042 bool operator()( const CapAndItem & cai )
01043 {
01044 PoolItem item( cai.item );
01045 string idx = cai.cap.index();
01046
01047 if ( item.status().staysInstalled() ) {
01048 iandu[idx].installed = item;
01049 }
01050 else if ( item.status().isToBeInstalled() ) {
01051 iandu[idx].uninstalled = item;
01052 }
01053 else if ( item.status().staysUninstalled() ) {
01054 IandUMap::iterator it = iandu.find( idx );
01055
01056 if (it != iandu.end()
01057 && it->second.uninstalled)
01058 {
01059 int cmp = it->second.uninstalled->arch().compare( item->arch() );
01060 if (cmp < 0) {
01061 it->second.uninstalled = item;
01062 }
01063 else if (cmp == 0) {
01064 if (it->second.uninstalled->edition().compare( item->edition() ) < 0) {
01065 it->second.uninstalled = item;
01066 }
01067 }
01068 }
01069 else {
01070 iandu[idx].uninstalled = item;
01071 }
01072 }
01073 return true;
01074 }
01075 };
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085 static bool
01086 transactCaps( const ResPool & pool, const CapSet & caps, bool install, bool soft, std::list<PoolItem_Ref> & added_items )
01087 {
01088 bool result = true;
01089
01090
01091
01092 for (CapSet::const_iterator cit = caps.begin(); cit != caps.end(); ++cit) {
01093
01094
01095
01096 FindIandU callback;
01097 Dep dep( Dep::PROVIDES );
01098 invokeOnEach( pool.byCapabilityIndexBegin( cit->index(), dep ),
01099 pool.byCapabilityIndexEnd( cit->index(), dep ),
01100 resfilter::ByCapMatch( *cit ) ,
01101 functor::functorRef<bool,CapAndItem>(callback) );
01102
01103
01104
01105 for (IandUMap::const_iterator it = callback.iandu.begin(); it != callback.iandu.end(); ++it) {
01106 PoolItem_Ref just_added;
01107 just_added = PoolItem_Ref();
01108 if (!transactItems( it->second.installed, it->second.uninstalled, install, soft, just_added )) {
01109 result = false;
01110 }
01111 else if (just_added) {
01112
01113
01114 added_items.push_back( just_added );
01115 }
01116 }
01117
01118 }
01119 return result;
01120 }
01121
01122
01123 struct TransactSupplements : public resfilter::PoolItemFilterFunctor
01124 {
01125 const Resolvable::Kind &_kind;
01126 bool valid;
01127
01128 TransactSupplements( const Resolvable::Kind & kind )
01129 : _kind( kind )
01130 , valid( false )
01131 { }
01132
01133 bool operator()( PoolItem_Ref item )
01134 {
01135
01136 if (item->kind() == _kind
01137 && (item.status().staysInstalled()
01138 || item.status().isToBeInstalled()))
01139 {
01140 valid = true;
01141 return false;
01142 }
01143 return true;
01144 }
01145 };
01146
01147
01148
01149
01150
01151 struct TransactLanguage : public resfilter::PoolItemFilterFunctor
01152 {
01153 Resolver & _resolver;
01154 ResObject::constPtr _langObj;
01155 bool _install;
01156
01157 TransactLanguage( Resolver & r, ResObject::constPtr langObj, bool install )
01158 : _resolver( r )
01159 , _langObj( langObj )
01160 , _install( install )
01161 { }
01162
01163
01164
01165
01166 bool operator()( const CapAndItem & cai )
01167 {
01168
01169
01170 PoolItem_Ref item( cai.item );
01171
01172 CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
01173 if (!supplements.empty()) {
01174
01175 bool valid = false;
01176 for (CapSet::const_iterator it = supplements.begin(); it != supplements.end(); ++it) {
01177
01178 TransactSupplements callback( it->refers() );
01179 invokeOnEach( _resolver.pool().byNameBegin( it->index() ),
01180 _resolver.pool().byNameEnd( it->index() ),
01181 functor::functorRef<bool,PoolItem>( callback ) );
01182 if (callback.valid) {
01183 valid = true;
01184 break;
01185 }
01186 }
01187 if (!valid) {
01188
01189 return true;
01190 }
01191 }
01192
01193 PoolItem_Ref dummy;
01194 if (_install) {
01195 if (item.status().staysUninstalled()) {
01196 transactItems( PoolItem_Ref(), item, _install, true, dummy );
01197 }
01198 }
01199 else {
01200 if (item.status().staysInstalled()) {
01201 transactItems( item, PoolItem_Ref(), _install, true, dummy );
01202 }
01203 }
01204 return true;
01205 }
01206 };
01207
01208
01209
01210
01211
01212
01213
01214
01215 bool
01216 Resolver::transactResObject( ResObject::constPtr robj, bool install)
01217 {
01218 if (robj == NULL) {
01219 ERR << "NULL ResObject" << endl;
01220 }
01221 _XDEBUG( "transactResObject(" << *robj << ", " << (install?"install":"remove") << ")" );
01222
01223 if (robj->kind() == ResTraits<Language>::kind) {
01224 TransactLanguage callback( *this, robj, install );
01225 Dep dep( Dep::FRESHENS );
01226 invokeOnEach( pool().byCapabilityIndexBegin( robj->name(), dep ),
01227 pool().byCapabilityIndexEnd( robj->name(), dep ),
01228 functor::functorRef<bool,CapAndItem>( callback ) );
01229
01230 }
01231 std::list<PoolItem_Ref> added;
01232
01233
01234
01235
01236 transactCaps( _pool, robj->dep( Dep::RECOMMENDS ), install, true, added );
01237 transactCaps( _pool, robj->dep( Dep::REQUIRES ), install, false, added );
01238
01239
01240
01241
01242
01243
01244 for (std::list<PoolItem_Ref>::const_iterator it = added.begin(); it != added.end(); ++it) {
01245 if ((*it)->kind() == robj->kind()) {
01246 transactResObject( it->resolvable(), install );
01247 }
01248 }
01249
01250
01251 return true;
01252 }
01253
01254
01255
01256
01257
01258
01259
01260 struct TransactKind : public resfilter::PoolItemFilterFunctor
01261 {
01262 Resolver & _resolver;
01263 bool install;
01264 bool result;
01265
01266 TransactKind( Resolver & r )
01267 : _resolver( r )
01268 , result( true )
01269 { }
01270
01271 bool operator()( PoolItem_Ref item )
01272 {
01273 result = _resolver.transactResObject( item.resolvable(), install );
01274 return true;
01275 }
01276 };
01277
01278
01279 bool
01280 Resolver::transactResKind( Resolvable::Kind kind )
01281 {
01282 TransactKind callback (*this);
01283
01284 _XDEBUG( "transactResKind(" << kind << ")" );
01285
01286
01287 callback.install = false;
01288 invokeOnEach( pool().byKindBegin( kind ),
01289 pool().byKindEnd( kind ),
01290 functor::chain( resfilter::ByTransact(), resfilter::ByInstalled ()),
01291 functor::functorRef<bool,PoolItem>( callback ) );
01292
01293
01294 callback.install = true;
01295 invokeOnEach( pool().byKindBegin( kind ),
01296 pool().byKindEnd( kind ),
01297 functor::chain( resfilter::ByTransact(), resfilter::ByUninstalled ()),
01298 functor::functorRef<bool,PoolItem>( callback ) );
01299
01300 return callback.result;
01301 }
01302
01303
01304 struct TransactReset : public resfilter::PoolItemFilterFunctor
01305 {
01306 ResStatus::TransactByValue _causer;
01307 TransactReset( ResStatus::TransactByValue causer )
01308 : _causer( causer )
01309 { }
01310
01311 bool operator()( PoolItem_Ref item )
01312 {
01313 item.status().resetTransact( _causer );
01314 return true;
01315 }
01316 };
01317
01318
01319 void
01320 Resolver::transactReset( ResStatus::TransactByValue causer )
01321 {
01322 TransactReset info( causer );
01323 MIL << "transactReset(" << causer << ")" << endl;
01324 invokeOnEach ( _pool.begin(), _pool.end(),
01325 resfilter::ByTransact( ),
01326 functor::functorRef<bool,PoolItem>(info) );
01327 return;
01328 }
01329
01331 };
01334 };
01337 };
01339