Resolver.cc

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /* Resolver.cc
00003  *
00004  * Copyright (C) 2000-2002 Ximian, Inc.
00005  * Copyright (C) 2005 SUSE Linux Products GmbH
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019  * 02111-1307, USA.
00020  */
00021 
00022 #include "zypp/solver/detail/Resolver.h"
00023 #include "zypp/solver/detail/Helper.h"
00024 
00025 #include "zypp/CapSet.h"
00026 #include "zypp/base/Logger.h"
00027 #include "zypp/base/String.h"
00028 #include "zypp/base/Gettext.h"
00029 
00030 #include "zypp/base/Algorithm.h"
00031 #include "zypp/ResPool.h"
00032 #include "zypp/ResFilters.h"
00033 #include "zypp/CapFilters.h"
00034 #include "zypp/ZYppFactory.h"
00035 #include "zypp/SystemResObject.h"
00036 
00037 
00039 namespace zypp
00040 { 
00041 
00042   namespace zypp_detail
00043   { 
00044     Arch defaultArchitecture();
00046   } // namespace zypp_detail
00048 
00050   namespace solver
00051   { 
00052 
00053     namespace detail
00054     { 
00055 
00056 using namespace std;
00057 
00058 IMPL_PTR_TYPE(Resolver);
00059 
00060 static const unsigned MAX_SECOND_RUNS( 3 );
00061 static const unsigned MAX_VALID_SOLUTIONS( 50 );        
00062 static const unsigned TIMOUT_SECOND_RUN( 30 );
00063 
00064 //---------------------------------------------------------------------------
00065 
00066 std::ostream &
00067 Resolver::dumpOn( std::ostream & os ) const
00068 {
00069     return os << "<resolver/>";
00070 }
00071 
00072 // Generating a system resolvable in the pool in order to trigger
00073 // modaliases and hals
00074 void assertSystemResObjectInPool()
00075 {
00076   ResPool pool( getZYpp()->pool() );
00077   if ( pool.byKindBegin<SystemResObject>()
00078        == pool.byKindEnd<SystemResObject>() )
00079     {
00080       // SystemResObject is missing in the pool ==> insert
00081       ResStore store;
00082       store.insert( SystemResObject::instance() );
00083       getZYpp()->addResolvables( store, true ); // true = is installed
00084     }
00085 
00086   // set lock
00087   if ( ! pool.byKindBegin<SystemResObject>()
00088          ->status().setLock( true, ResStatus::USER ) )
00089     {
00090       WAR << "Unable to set SystemResObject to lock" << endl;
00091     }
00092 }
00093 
00094 //---------------------------------------------------------------------------
00095 
00096 Resolver::Resolver (const ResPool & pool)
00097     : _pool (pool)
00098     , _timeout_seconds (0)
00099     , _maxSolverPasses (0)
00100     , _verifying (false)
00101     , _testing (false)
00102     , _tryAllPossibilities (false)
00103     , _skippedPossibilities (false)
00104     , _valid_solution_count (0)
00105     , _best_context (NULL)
00106     , _establish_context (NULL)
00107     , _timed_out (false)
00108     , _architecture( zypp_detail::defaultArchitecture() )
00109     , _forceResolve (false)
00110     , _upgradeMode (false)
00111     , _preferHighestVersion (true)
00112       
00113 {}
00114 
00115 
00116 Resolver::~Resolver()
00117 {
00118 }
00119 
00120 //---------------------------------------------------------------------------
00121 
00122 ResPool
00123 Resolver::pool (void) const
00124 {
00125     return _pool;
00126 }
00127 
00128 void
00129 Resolver::reset (void)
00130 {
00131     _verifying = false;
00132 
00133     _initial_items.clear();
00134 
00135     _items_to_install.clear();
00136     _items_to_remove.clear();
00137     _items_to_verify.clear();
00138     _items_to_establish.clear();
00139 
00140     _extra_caps.clear();
00141     _extra_conflicts.clear();
00142 
00143     _pending_queues.clear();
00144     _pruned_queues.clear();
00145     _complete_queues.clear();
00146     _deferred_queues.clear();
00147     _invalid_queues.clear();
00148 
00149     _valid_solution_count = 0;
00150 
00151     _best_context = NULL;
00152     _timed_out = false;
00153     
00154     _tryAllPossibilities = false;
00155     _skippedPossibilities = false;
00156     
00157 }
00158 
00159 
00160 ResolverContext_Ptr
00161 Resolver::context (void) const
00162 {
00163     if (_best_context) return _best_context;
00164     if (_invalid_queues.empty()) return NULL;
00165     ResolverQueue_Ptr invalid = _invalid_queues.front();
00166     return invalid->context();
00167 }
00168 
00169 //---------------------------------------------------------------------------
00170 
00171 void
00172 Resolver::addSubscribedSource (Source_Ref source)
00173 {
00174     _subscribed.insert(source);
00175 }
00176 
00177 void
00178 Resolver::addPoolItemToInstall (PoolItem_Ref item)
00179 {
00180     bool found = false;
00181     for (PoolItemList::const_iterator iter = _items_to_remove.begin();
00182          iter != _items_to_remove.end(); iter++) {
00183         if (*iter == item) {
00184             _items_to_remove.remove(*iter);
00185             found = true;
00186             break;
00187         }
00188     }
00189     if (!found)
00190         _items_to_install.push_back (item);
00191 }
00192 
00193 
00194 void
00195 Resolver::addPoolItemsToInstallFromList (PoolItemList & rl)
00196 {
00197     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00198         addPoolItemToInstall (*iter);
00199     }
00200 }
00201 
00202 
00203 void
00204 Resolver::addPoolItemToRemove (PoolItem_Ref item)
00205 {
00206     bool found = false;
00207     for (PoolItemList::const_iterator iter = _items_to_install.begin();
00208          iter != _items_to_install.end(); iter++) {
00209         if (*iter == item) {
00210             _items_to_install.remove(*iter);
00211             found = true;
00212             break;
00213         }
00214     }
00215     if (!found)
00216         _items_to_remove.push_back (item);
00217 }
00218 
00219 
00220 void
00221 Resolver::addPoolItemsToRemoveFromList (PoolItemList & rl)
00222 {
00223     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00224         addPoolItemToRemove (*iter);
00225     }
00226 }
00227 
00228 
00229 void
00230 Resolver::addPoolItemToEstablish (PoolItem_Ref item)
00231 {
00232     _items_to_establish.push_back (item);
00233 }
00234 
00235 
00236 void
00237 Resolver::addPoolItemsToEstablishFromList (PoolItemList & rl)
00238 {
00239     for (PoolItemList::const_iterator iter = rl.begin(); iter != rl.end(); iter++) {
00240         addPoolItemToEstablish (*iter);
00241     }
00242 }
00243 
00244 
00245 void
00246 Resolver::addPoolItemToVerify (PoolItem_Ref item)
00247 {
00248 #if 0
00249 
00250   struct {
00252     bool operator()( PoolItem_Ref lhs, PoolItem_Ref rhs ) const
00253     {
00254       int res = lhs->name().compare( rhs->name() );
00255       if ( res )
00256         return res == -1; // lhs < rhs ?
00257       // here: lhs == rhs, so compare edition:
00258       return lhs->edition() < rhs->edition();
00259     }
00260   } order;
00261 #endif
00262 
00263     _items_to_verify.push_back (item);
00264 
00265 #warning Should order by name (and probably edition since with zypp we could have multiple editions installed in parallel)
00266 //    _items_to_verify.sort (order);                    //(GCompareFunc) rc_item_compare_name);
00267 }
00268 
00269 
00270 void
00271 Resolver::addExtraCapability (const Capability & capability)
00272 {
00273     _extra_caps.insert (capability);
00274 }
00275 
00276 
00277 void
00278 Resolver::addExtraConflict (const Capability & capability)
00279 {
00280     _extra_conflicts.insert (capability);
00281 }
00282 
00283 
00284 void
00285 Resolver::addIgnoreConflict (const PoolItem_Ref item,
00286                    const Capability & capability)
00287 {
00288     _ignoreConflicts.insert(make_pair(item, capability));
00289 }
00290 
00291 
00292 void
00293 Resolver::addIgnoreRequires (const PoolItem_Ref item,
00294                              const Capability & capability)
00295 {
00296     _ignoreRequires.insert(make_pair(item, capability));
00297 }
00298 
00299 void
00300 Resolver::addIgnoreObsoletes (const PoolItem_Ref item,
00301                               const Capability & capability)
00302 {
00303     _ignoreObsoletes.insert(make_pair(item, capability));
00304 }
00305 
00306 void
00307 Resolver::addIgnoreInstalledItem (const PoolItem_Ref item)
00308 {
00309     _ignoreInstalledItem.push_back (item);
00310 }
00311 
00312 void
00313 Resolver::addIgnoreArchitectureItem (const PoolItem_Ref item)
00314 {
00315     _ignoreArchitectureItem.push_back (item);
00316 }
00317 
00318 
00319 //---------------------------------------------------------------------------
00320 
00321 struct UndoTransact : public resfilter::PoolItemFilterFunctor
00322 {
00323     ResStatus::TransactByValue resStatus;
00324     UndoTransact ( const ResStatus::TransactByValue &status)
00325         :resStatus(status)
00326     { }
00327 
00328     bool operator()( PoolItem_Ref item )                // only transacts() items go here
00329     {
00330         item.status().resetTransact( resStatus );// clear any solver/establish transactions
00331         return true;
00332     }
00333 };
00334 
00335 
00336 struct DoTransact : public resfilter::PoolItemFilterFunctor
00337 {
00338     ResStatus::TransactByValue resStatus;
00339     DoTransact ( const ResStatus::TransactByValue &status)
00340         :resStatus(status)
00341     { }
00342 
00343     bool operator()( PoolItem_Ref item )                // only transacts() items go here
00344     {
00345         item.status().setTransact( true, resStatus );
00346         return true;
00347     }
00348 };
00349 
00350 
00351 struct VerifySystem : public resfilter::PoolItemFilterFunctor
00352 {
00353     Resolver & resolver;
00354 
00355     VerifySystem (Resolver & r)
00356         : resolver (r)
00357     { }
00358 
00359     bool operator()( PoolItem_Ref provider )
00360     {
00361         resolver.addPoolItemToVerify (provider);
00362         return true;
00363     }
00364 };
00365 
00366 bool
00367 Resolver::verifySystem (bool considerNewHardware)
00368 {
00369     UndoTransact resetting (ResStatus::APPL_HIGH);
00370     
00371     _DEBUG ("Resolver::verifySystem() " << (considerNewHardware ? "consider new hardware":""));
00372 
00373     invokeOnEach ( _pool.begin(), _pool.end(),
00374                    resfilter::ByTransact( ),                    // Resetting all transcations
00375                    functor::functorRef<bool,PoolItem>(resetting) );
00376 
00377     VerifySystem info (*this);
00378 
00379     invokeOnEach( pool().byKindBegin( ResTraits<Package>::kind ),
00380                   pool().byKindEnd( ResTraits<Package>::kind ),
00381                   resfilter::ByInstalled ( ),
00382                   functor::functorRef<bool,PoolItem>(info) );
00383 
00384     invokeOnEach( pool().byKindBegin( ResTraits<Pattern>::kind ),
00385                   pool().byKindEnd( ResTraits<Pattern>::kind ),
00386                   resfilter::ByInstalled ( ),
00387                   functor::functorRef<bool,PoolItem>(info) );    
00388 
00389 
00390     _verifying = true;
00391 
00392     bool success = false;
00393 
00394     if (considerNewHardware) {
00395         // evaluate all Freshens/Supplements and solve
00396         success = freshenPool(false) && bestContext() && bestContext()->isValid();
00397     }
00398     else {
00399         success = resolveDependencies (); // do solve only
00400     }
00401 
00402     DoTransact setting (ResStatus::APPL_HIGH);
00403 
00404     invokeOnEach ( _pool.begin(), _pool.end(),
00405                    resfilter::ByTransact( ),                    
00406                    functor::functorRef<bool,PoolItem>(setting) );    
00407     
00408     return success;
00409 }
00410 
00411 
00412 //---------------------------------------------------------------------------
00413 
00414 // copy marked item from solution back to pool
00415 // if data != NULL, set as APPL_LOW (from establishPool())
00416 
00417 static void
00418 solution_to_pool (PoolItem_Ref item, const ResStatus & status, void *data)
00419 {
00420     bool r;
00421 
00422     if (status.isToBeInstalled()) {
00423         r = item.status().setToBeInstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00424         _XDEBUG("solution_to_pool(" << item << ", " << status << ") install !" << r);
00425     }
00426     else if (status.isToBeUninstalledDueToUpgrade()) {
00427         r = item.status().setToBeUninstalledDueToUpgrade( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00428         _XDEBUG("solution_to_pool(" << item << ", " << status << ") upgrade !" << r);
00429     }
00430     else if (status.isToBeUninstalled()) {
00431         r = item.status().setToBeUninstalled( (data != NULL) ? ResStatus::APPL_LOW : ResStatus::SOLVER );
00432         _XDEBUG("solution_to_pool(" << item << ", " << status << ") remove !" << r);
00433     }
00434     else if (status.isIncomplete()
00435              || status.isNeeded()) {
00436         r = item.status().setIncomplete();
00437         _XDEBUG("solution_to_pool(" << item << ", " << status << ") incomplete !" << r);
00438     }
00439     else if (status.isUnneeded()) {
00440         r = item.status().setUnneeded();
00441         _XDEBUG("solution_to_pool(" << item << ", " << status << ") unneeded !" << r);
00442     }
00443     else if (status.isSatisfied()) {
00444         r = item.status().setSatisfied();
00445         _XDEBUG("solution_to_pool(" << item << ", " << status << ") satisfied !" << r);
00446     } else {
00447         _XDEBUG("solution_to_pool(" << item << ", " << status << ") unchanged !");
00448     }
00449     return;
00450 }
00451 
00452 
00453 //---------------------------------------------------------------------------
00454 // establish state
00455 
00456 struct EstablishState
00457 {
00458     Resolver & resolver;
00459 
00460     EstablishState (Resolver & r)
00461         : resolver (r)
00462     { }
00463 
00464     bool operator()( PoolItem_Ref provider )
00465     {
00466         resolver.addPoolItemToEstablish (provider);
00467         return true;
00468     }
00469 };
00470 
00471 
00472 void
00473 Resolver::establishState( ResolverContext_Ptr context )
00474 {
00475     _DEBUG( "Resolver::establishState ()" );
00476     typedef list<Resolvable::Kind> KindList;
00477     static KindList ordered;
00478     if (ordered.empty()) {
00479         ordered.push_back (ResTraits<zypp::Atom>::kind);
00480         ordered.push_back (ResTraits<zypp::Message>::kind);
00481         ordered.push_back (ResTraits<zypp::Script>::kind);
00482         ordered.push_back (ResTraits<zypp::Patch>::kind);
00483         ordered.push_back (ResTraits<zypp::Pattern>::kind);
00484         ordered.push_back (ResTraits<zypp::Product>::kind);
00485     }
00486 
00487     if (context == NULL)
00488         context = new ResolverContext(_pool, _architecture);
00489 
00490     context->setEstablishing (true);
00491     context->setIgnoreCababilities (_ignoreConflicts,
00492                                     _ignoreRequires,
00493                                     _ignoreObsoletes,
00494                                     _ignoreInstalledItem,
00495                                     _ignoreArchitectureItem);
00496     context->setForceResolve( _forceResolve );
00497     context->setEstablishContext( _establish_context );    
00498     context->setPreferHighestVersion ( _preferHighestVersion );
00499     context->setUpgradeMode( _upgradeMode );
00500 
00501     for (KindList::const_iterator iter = ordered.begin(); iter != ordered.end(); iter++) {
00502         const Resolvable::Kind kind = *iter;
00503 
00504         _XDEBUG( "establishing state for kind " << kind.asString() );
00505 
00506         //world()->foreachResItemByKind (kind, trial_establish_cb, this);
00507 
00508         EstablishState info (*this);
00509 
00510         invokeOnEach( pool().byKindBegin( kind ),
00511                       pool().byKindEnd( kind ),
00512                       functor::functorRef<bool,PoolItem>(info) );
00513 
00514         // process the queue
00515         resolveDependencies( context );
00516 
00517         reset();
00518     }
00519 
00520     context->setEstablishing (false);
00521 
00522     _best_context = context;
00523     _establish_context = context;
00524 
00525     return;
00526 }
00527 
00528 
00529 bool
00530 Resolver::establishPool ()
00531 {
00532     MIL << "Resolver::establishPool()" << endl;
00533 
00534     establishState ();                                          // establish !
00535     ResolverContext_Ptr solution = bestContext();
00536 
00537     if (solution) {                                             // copy solution back to pool
00538         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
00539     }
00540     else {
00541         ERR << "establishState did not return a bestContext" << endl;
00542         return false;
00543     }
00544 
00545     return true;
00546 }
00547 
00548 
00549 //---------------------------------------------------------------------------
00550 // freshen state
00551 
00552 typedef map<string, PoolItem_Ref> FreshenMap;
00553 
00554 // add item to itemmap
00555 //  check for item with same name and only keep
00556 //  best architecture, best version
00557 
00558 static void
00559 addToFreshen( PoolItem_Ref item, FreshenMap & itemmap )
00560 {
00561     FreshenMap::iterator it = itemmap.find( item->name() );
00562     if (it != itemmap.end()) {                                  // item with same name found
00563         int cmp = it->second->arch().compare( item->arch() );
00564         if (cmp < 0) {                                          // new item has better arch
00565             it->second = item;
00566         }
00567         else if (cmp == 0) {                                    // new item has equal arch
00568             if (it->second->edition().compare( item->edition() ) < 0) {
00569                 it->second = item;                              // new item has better edition
00570             }
00571         }
00572     }
00573     else {
00574         itemmap[item->name()] = item;
00575     }
00576     return;
00577 }
00578 
00579 
00580 struct FreshenState
00581 {
00582     FreshenMap itemmap;
00583 
00584     FreshenState()
00585     { }
00586 
00587     bool operator()( PoolItem_Ref item)
00588     {
00589         CapSet freshens( item->dep( Dep::FRESHENS ) );
00590         if (!freshens.empty()) {
00591             addToFreshen( item, itemmap );
00592         }
00593         else {                                  // if no freshens, look at supplements
00594             // Also regarding supplements e.g. in order to recognize
00595             // modalias dependencies. Bug #163140
00596             CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
00597             if (!supplements.empty()) {
00598                 addToFreshen( item, itemmap );
00599             }
00600         }
00601         return true;
00602     }
00603 };
00604 
00605 
00606 void
00607 Resolver::freshenState( ResolverContext_Ptr context,
00608                         bool resetAfterSolve )
00609 {
00610     _DEBUG( "Resolver::freshenState ()" );
00611 
00612     if (context == NULL)
00613         context = new ResolverContext( _pool, _architecture );
00614 
00615     context->setEstablishing( true );
00616     context->setIgnoreCababilities( _ignoreConflicts,
00617                                     _ignoreRequires,
00618                                     _ignoreObsoletes,
00619                                     _ignoreInstalledItem,
00620                                     _ignoreArchitectureItem );
00621     context->setForceResolve( _forceResolve );
00622     context->setEstablishContext( _establish_context );        
00623     context->setPreferHighestVersion( _preferHighestVersion );
00624     context->setUpgradeMode( _upgradeMode );
00625 
00626     FreshenState info;
00627 
00628     // collect items to be established
00629 
00630     invokeOnEach( pool().byKindBegin( ResTraits<zypp::Package>::kind ),
00631                       pool().byKindEnd( ResTraits<zypp::Package>::kind ),
00632                       functor::functorRef<bool,PoolItem>(info) );
00633 
00634     // schedule all collected items for establish
00635 
00636     for (FreshenMap::iterator it = info.itemmap.begin(); it != info.itemmap.end(); ++it) {
00637         addPoolItemToEstablish( it->second );
00638     }
00639 
00640     // process the queue
00641     resolveDependencies( context );
00642     
00643     if (resetAfterSolve) {
00644         reset();
00645         context->setEstablishing( false );
00646         _best_context = context;
00647     }
00648 
00649     return;
00650 }
00651 
00652 
00653 bool
00654 Resolver::freshenPool (bool resetAfterSolve)
00655 {
00656     MIL << "Resolver::freshenPool()" << endl;
00657 
00658     freshenState (NULL, resetAfterSolve);       // establish all packages with freshens; (NULL)= no initial context
00659     ResolverContext_Ptr solution = bestContext();
00660 
00661     if (solution) {                                             // copy solution back to pool
00662         solution->foreachMarked (solution_to_pool, (void *)1);  // as APPL_LOW
00663     }
00664     else {
00665         ERR << "freshenState did not return a bestContext" << endl;
00666         return false;
00667     }
00668 
00669     return true;
00670 }
00671 
00672 //---------------------------------------------------------------------------
00673 
00674 bool
00675 Resolver::resolveDependencies (const ResolverContext_Ptr context)
00676 {
00677 
00678     time_t t_start, t_now;
00679 
00680     MIL << "Resolver::resolveDependencies()" << endl;
00681 
00682     _pending_queues.clear();
00683     _pruned_queues.clear();
00684     _complete_queues.clear();
00685     _deferred_queues.clear();
00686     _invalid_queues.clear();
00687     _valid_solution_count = 0;
00688     _best_context = NULL;
00689 
00690 #warning local items disabled
00691 #if 0
00692     bool have_local_items = false;
00693 
00694     /* Walk through are list of to-be-installed packages and see if any of them are local. */
00695 
00696     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00697         if ((*iter)->local()) {
00698             have_local_items = true;
00699             break;
00700         }
00701     }
00702 
00703     World_Ptr the_world = world();
00704     StoreWorld_Ptr local_world = NULL;
00705     MultiWorld_Ptr local_multiworld = NULL;
00706 
00707     Channel_Ptr local_channel = NULL;
00708 
00709     if (have_local_items) {
00710         local_multiworld = new MultiWorld();
00711         local_world = new StoreWorld();
00712 
00713         local_channel = new Channel ("", "Local ResItems", "@local", "");
00714 
00715         local_world->addChannel (local_channel);
00716 
00717         local_multiworld->addSubworld (local_world);
00718         local_multiworld->addSubworld (the_world);
00719 
00720         the_world = local_multiworld;
00721     }
00722 #endif
00723 
00724     // create initial_queue
00725 
00726     ResolverQueue_Ptr initial_queue = new ResolverQueue(_pool, _architecture, context);
00727 
00728     // adding "external" provides, the the requirements will be ignored
00729     IgnoreMap ignoreRequires = _ignoreRequires;
00730     ResPool::AdditionalCapSet additionalCapSet = pool().additionaProvide();
00731     for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
00732          it != additionalCapSet.end(); it++) {
00733         CapSet cset = it->second;
00734         for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00735             ignoreRequires.insert(make_pair(PoolItem_Ref(), *cit));
00736         }
00737     }
00738     
00739     // Initialize all ignoring dependencies
00740     initial_queue->context()->setIgnoreCababilities (_ignoreConflicts,
00741                                                      ignoreRequires,
00742                                                      _ignoreObsoletes,
00743                                                      _ignoreInstalledItem,
00744                                                      _ignoreArchitectureItem);
00745     initial_queue->context()->setForceResolve( _forceResolve );
00746     initial_queue->context()->setEstablishContext( _establish_context );       
00747     initial_queue->context()->setPreferHighestVersion( _preferHighestVersion );
00748     initial_queue->context()->setUpgradeMode( _upgradeMode );
00749     initial_queue->context()->setTryAllPossibilities( _tryAllPossibilities );
00750     initial_queue->context()->setScippedPossibilities( _skippedPossibilities );
00751 
00752     /* If this is a verify, we do a "soft resolution" */
00753 
00754     initial_queue->context()->setVerifying( _verifying );
00755 
00756     /* Add extra items. */
00757 
00758     for (QueueItemList::const_iterator iter = _initial_items.begin(); iter != _initial_items.end(); iter++) {
00759         initial_queue->addItem (*iter);
00760     }
00761 
00762     for (PoolItemList::const_iterator iter = _items_to_install.begin(); iter != _items_to_install.end(); iter++) {
00763         PoolItem_Ref r = *iter;
00764 
00765 #warning local items disabled
00766 #if 0
00767         /* Add local packages to our dummy channel. */
00768         if (r->local()) {
00769             assert (local_channel != NULL);
00770             ResItem_Ptr r1 = const_pointer_cast<ResItem>(r);
00771             r1->setChannel (local_channel);
00772             local_world->addPoolItem_Ref (r);
00773         }
00774 #endif
00775         initial_queue->addPoolItemToInstall (r);
00776     }
00777 
00778     for (PoolItemList::const_iterator iter = _items_to_remove.begin(); iter != _items_to_remove.end(); iter++) {
00779         if (!_upgradeMode)
00780             initial_queue->addPoolItemToRemove (*iter, true /* remove-only mode */);
00781         else
00782             //   Checking old dependencies for packages which will be updated.
00783             //   E.g. foo provides a dependecy which foo-new does not provides anymore.
00784             //   So check, if there is a packages installed which requires foo.
00785             //   Testcase exercise-bug150844-test.xml
00786             //   Testcase Bug156439-test.xml
00787             initial_queue->addPoolItemToRemove (*iter, false /* no remove-only mode */);
00788     }
00789 
00790     for (PoolItemList::const_iterator iter = _items_to_verify.begin(); iter != _items_to_verify.end(); iter++) {
00791         initial_queue->addPoolItemToVerify (*iter);
00792     }
00793 
00794     for (PoolItemList::const_iterator iter = _items_to_establish.begin(); iter != _items_to_establish.end(); iter++) {
00795         initial_queue->addPoolItemToEstablish (*iter);
00796     }
00797 
00798     for (CapSet::const_iterator iter = _extra_caps.begin(); iter != _extra_caps.end(); iter++) {
00799         initial_queue->addExtraCapability (*iter);
00800     }
00801     
00802     // adding "external" requires
00803     additionalCapSet = pool().additionalRequire();
00804     for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
00805          it != additionalCapSet.end(); it++) {
00806         CapSet cset = it->second;
00807         for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00808             initial_queue->addExtraCapability (*cit);       
00809         }
00810     }
00811 
00812     for (CapSet::const_iterator iter = _extra_conflicts.begin(); iter != _extra_conflicts.end(); iter++) {
00813         initial_queue->addExtraConflict (*iter);
00814     }
00815 
00816     // adding "external" conflicts
00817     additionalCapSet = pool().additionaConflict();
00818     for (ResPool::AdditionalCapSet::const_iterator it = additionalCapSet.begin();
00819          it != additionalCapSet.end(); it++) {
00820         CapSet cset = it->second;
00821         for (CapSet::const_iterator cit = cset.begin(); cit != cset.end(); ++cit) {
00822             initial_queue->addExtraConflict (*cit);         
00823         }
00824     }
00825 
00826     // Adding System resolvable
00827     assertSystemResObjectInPool();
00828 
00829     _XDEBUG( "Initial Queue: [" << *initial_queue << "]" );
00830 
00831     if (initial_queue->isEmpty()) {
00832         INT << "Empty Queue, nothing to resolve" << endl;
00833 
00834         return true;
00835     }
00836 
00837     _best_context = NULL;
00838 
00839     _pending_queues.push_front (initial_queue);
00840 
00841     time (&t_start);
00842 
00843     while (!_pending_queues.empty()) {
00844 
00845         _DEBUG( "Pend " << (long) _pending_queues.size()
00846                 << " / Cmpl " << (long) _complete_queues.size()
00847                 << " / Prun " << (long) _pruned_queues.size()
00848                 << " / Defr " << (long) _deferred_queues.size()
00849                 << " / Invl " << (long) _invalid_queues.size() );
00850 
00851         if (_timeout_seconds > 0) {
00852             time (&t_now);
00853             if (difftime (t_now, t_start) > _timeout_seconds) {
00854                 _timed_out = true;
00855                 MIL << "Timeout " << _timeout_seconds << " seconds reached"
00856                     << " -> exit" << endl;
00857                 break;
00858             }
00859         }
00860         if (_maxSolverPasses > 0) {
00861             if (_maxSolverPasses <= _complete_queues.size() +
00862                 _pruned_queues.size() +
00863                 _deferred_queues.size() +
00864                 _invalid_queues.size()) {
00865                 _timed_out = true;
00866                 MIL << "Max solver runs ( " << _maxSolverPasses
00867                     << " ) reached -> exit" << endl;
00868                 break;
00869             }
00870         }
00871 
00872         if (_best_context != NULL
00873             && _complete_queues.size() >= MAX_VALID_SOLUTIONS) {
00874                 MIL << "Max VALID solver runs ( " << MAX_VALID_SOLUTIONS
00875                     << " ) reached -> exit" << endl;
00876                 break;
00877         }
00878               
00879         ResolverQueue_Ptr queue = _pending_queues.front();
00880         _pending_queues.pop_front();
00881         ResolverContext_Ptr context = queue->context();
00882 
00883         queue->process();
00884 
00885         if (queue->isInvalid ()) {
00886 
00887             _XDEBUG( "Invalid Queue\n" );
00888             _invalid_queues.push_back(queue);
00889 
00890         } else if (queue->isEmpty ()) {
00891 
00892             _XDEBUG( "Empty Queue\n" );
00893 
00894             _complete_queues.push_back(queue);
00895 
00896             ++_valid_solution_count;
00897 
00898             /* Compare this solution to our previous favorite.  In the case of a tie,
00899                the first solution wins --- yeah, I know this is lame, but it shouldn't
00900                be an issue too much of the time. */
00901 
00902             if (_best_context == NULL
00903                 || _best_context->compare (context) < 0)
00904             {
00905                 _best_context = context;
00906             }
00907 
00908         } else if (_best_context != NULL
00909                    && _best_context->partialCompare (context) > 0) {
00910 
00911             /* If we aren't currently as good as our previous best complete solution,
00912                this solution gets pruned. */
00913 
00914             _XDEBUG( "PRUNED!" );
00915 
00916             _pruned_queues.push_back(queue);
00917 
00918         } else {
00919 
00920             /* If our queue is isn't empty and isn't invalid, that can only mean
00921                one thing: we are down to nothing but branches. */
00922 
00923             queue->splitFirstBranch (_pending_queues, _deferred_queues);
00924         }
00925 
00926         /* If we have run out of pending queues w/o finding any solutions,
00927            and if we have deferred queues, make the first deferred queue
00928            pending. */
00929 
00930         if (_pending_queues.empty()
00931             && _complete_queues.empty()
00932             && !_deferred_queues.empty()) {
00933             _pending_queues.push_back(_deferred_queues.front());
00934         }
00935     }
00936     _DEBUG("Pend " << (long) _pending_queues.size()
00937            << " / Cmpl " << (long) _complete_queues.size()
00938            << " / Prun " << (long) _pruned_queues.size()
00939            << " / Defr " << (long) _deferred_queues.size()
00940            << " / Invl " << (long) _invalid_queues.size() );
00941     
00942     
00943     if ( !(_best_context && _best_context->isValid()) // no valid solution
00944          && !_tryAllPossibilities ) { // a second run with ALL possibilities has not been tried
00945 
00946         for (ResolverQueueList::iterator iter = _invalid_queues.begin();
00947              iter != _invalid_queues.end(); iter++) {
00948             // evaluate if there are other possibilities which have not been regarded
00949             ResolverQueue_Ptr invalid = *iter;              
00950             if (invalid->context()->skippedPossibilities()) {
00951                 _skippedPossibilities = true;
00952                 break;
00953             }
00954         }
00955         
00956         if (_skippedPossibilities) { // possible other solutions skipped         
00957             // lets try a second run with ALL possibilities
00958             _tryAllPossibilities = true;
00959             MIL << "================================================================"
00960                 << endl;
00961             MIL << "No valid solution, lets try a second run with ALL possibilities"
00962                 << endl;
00963             if (_maxSolverPasses <= 0) 
00964                 _maxSolverPasses = MAX_SECOND_RUNS;         
00965             if (_timeout_seconds <= 0) 
00966                 _timeout_seconds = TIMOUT_SECOND_RUN;
00967 
00968             MIL << "But no longer than " << MAX_SECOND_RUNS << " runs or "
00969                 << TIMOUT_SECOND_RUN << " seconds" << endl;
00970             MIL << "================================================================"
00971                 << endl;
00972             // saving invalid queue
00973             ResolverQueueList   save_queues = _invalid_queues;
00974             resolveDependencies ();
00975             if (!(_best_context && _best_context->isValid()))
00976                 _invalid_queues = save_queues; // take the old
00977         }
00978     }
00979 
00980     return _best_context && _best_context->isValid();
00981 }
00982 
00983 
00984 //----------------------------------------------------------------------------
00985 // undo
00986 
00987 
00988 void
00989 Resolver::undo(void)
00990 {
00991     UndoTransact info(ResStatus::APPL_LOW);
00992     MIL << "*** undo ***" << endl;
00993     invokeOnEach ( _pool.begin(), _pool.end(),
00994                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
00995                    functor::functorRef<bool,PoolItem>(info) );
00996     // These conflict should be ignored of the concering item
00997     _ignoreConflicts.clear();
00998     // These requires should be ignored of the concering item
00999     _ignoreRequires.clear();
01000     // These obsoletes should be ignored of the concering item
01001     _ignoreObsoletes.clear();
01002     // Ignore architecture of the item
01003     _ignoreArchitecture.clear();
01004     // Ignore the status "installed" of the item
01005     _ignoreInstalledItem.clear();
01006     // Ignore the architecture of the item
01007     _ignoreArchitectureItem.clear();
01008 
01009 
01010     return;
01011 }
01012 
01013 //----------------------------------------------------------------------------
01014 // resolvePool
01015 
01016 struct CollectTransact : public resfilter::PoolItemFilterFunctor
01017 {
01018     Resolver & resolver;
01019 
01020     CollectTransact (Resolver & r)
01021         : resolver (r)
01022     { }
01023 
01024     bool operator()( PoolItem_Ref item )                // only transacts() items go here
01025     {
01026         ResStatus status = item.status();
01027         _XDEBUG( "CollectTransact(" << item << ")" );
01028         bool by_solver = (status.isBySolver() || status.isByApplLow());
01029 
01030         if (by_solver) {
01031             item.status().resetTransact( ResStatus::APPL_LOW );// clear any solver/establish transactions
01032             return true;                                // back out here, dont re-queue former solver result
01033         }
01034 
01035         if (status.isToBeInstalled()) {
01036             resolver.addPoolItemToInstall(item);        // -> install!
01037         }
01038         if (status.isToBeUninstalled()) {
01039             resolver.addPoolItemToRemove(item);         // -> remove !
01040         }
01041         if (status.isIncomplete()) {                    // incomplete (re-install needed)
01042             PoolItem_Ref reinstall = Helper::findReinstallItem (resolver.pool(), item);
01043             if (reinstall) {
01044                 MIL << "Reinstall " << reinstall << " for incomplete " << item << endl;
01045                 resolver.addPoolItemToInstall(reinstall);       // -> install!
01046             }
01047             else {
01048                 WAR << "Can't find " << item << " for re-installation" << endl;
01049             }
01050         }
01051         return true;
01052     }
01053 };
01054 
01055 
01056 static void
01057 show_pool( ResPool pool )
01058 {
01059     int count = 1;
01060     static bool full_pool_shown = true;
01061 
01062     _XDEBUG( "---------------------------------------" );
01063     for (ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it, ++count) {
01064 
01065         if (!full_pool_shown                                    // show item if not shown all before
01066             || it->status().transacts()                         // or transacts
01067             || !it->status().isUndetermined())                  // or established status
01068         {
01069             _DEBUG( count << ": " << *it );
01070         }
01071     }
01072     _XDEBUG( "---------------------------------------" );
01073     full_pool_shown = true;
01074 }
01075 
01076 //  This function loops over the pool and grabs
01077 //  all item.status().transacts() and item.status().byUser()
01078 //  It clears all previous bySolver() states also
01079 //
01080 //  Every toBeInstalled is passed to zypp::solver:detail::Resolver.addPoolItemToInstall()
01081 //  Every toBeUninstalled is passed to zypp::solver:detail::Resolver.addPoolItemToRemove()
01082 //
01083 //  Then zypp::solver:detail::Resolver.resolveDependencies() is called.
01084 //
01085 //  zypp::solver:detail::Resolver then returns a ResolverContext via bestContext() which
01086 //  describes the best solution. If bestContext() is NULL, no solution was found.
01087 //
01088 //  ResolverContext has a foreachMarked() iterator function which loops over all
01089 //  items of the solutions. These must be written back to the pool.
01090 
01091 
01092 bool
01093 Resolver::resolvePool( bool tryAllPossibilities )
01094 {
01095     ResolverContext_Ptr context = NULL;
01096 
01097     CollectTransact info (*this);
01098 
01099     // cleanup before next run
01100     reset();
01101 
01102     if (tryAllPossibilities) {
01103         _tryAllPossibilities = tryAllPossibilities;
01104         context = new ResolverContext( _pool, _architecture );
01105         context->setTryAllPossibilities( true );
01106     }
01107 
01108 #if 1
01109 
01110     MIL << "Resolver::resolvePool()" << endl;
01111     _XDEBUG( "Pool before resolve" );
01112     show_pool( _pool );
01113 
01114 #endif
01115     invokeOnEach ( _pool.begin(), _pool.end(),
01116                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
01117                    functor::functorRef<bool,PoolItem>(info) );
01118 
01119     bool have_solution = resolveDependencies( context );        // resolve !
01120 
01121     if (have_solution) {                                        // copy solution back to pool
01122         MIL << "Have solution, copying back to pool" << endl;
01123         ResolverContext_Ptr solution = bestContext();
01124         solution->foreachMarked (solution_to_pool, NULL);
01125 #if 1
01126         _XDEBUG( "Pool after resolve" );
01127         show_pool( _pool );
01128 #endif
01129     }
01130     else {
01131         MIL << "!!! Have NO solution !!! Additional solver information:" << endl;
01132         int counter = 0;
01133         for (ResolverQueueList::iterator iter = _invalid_queues.begin();
01134              iter != _invalid_queues.end(); iter++) {
01135             counter++;
01136             MIL << "-----------------------------------------------------------------" << endl;
01137             MIL << counter++ << ". failed queue:" << endl;
01138             ResolverQueue_Ptr invalid = *iter;    
01139             invalid->context()->spewInfo ();
01140             MIL << *invalid->context() << endl;
01141             MIL << "-----------------------------------------------------------------" << endl;         
01142         }
01143     }
01144     return have_solution;
01145 }
01146 
01147 
01148 static void
01149 get_info_foreach_cb (ResolverInfo_Ptr info, void *data)
01150 {
01151     list<string> *stringList = (list<string> *)data;
01152     stringList->push_back (info->message());
01153 }
01154 
01155 
01156 // returns a string list of ResolverInfo of the LAST not valid solution
01157 std::list<std::string> Resolver::problemDescription( void ) const
01158 {
01159     list<string> retList;
01160     if (_invalid_queues.empty()) return retList;
01161     ResolverQueue_Ptr invalid = _invalid_queues.front();
01162     invalid->context()->foreachInfo (PoolItem_Ref(), -1, get_info_foreach_cb, (void *)&retList);;
01163     return retList;
01164 }
01165 
01166 
01167 //-----------------------------------------------------------------------------
01168 
01169 //
01170 // UI Helper
01171 // do a single (install/uninstall) transaction
01172 //  if a previously uninstalled item was just set to-be-installed, return it as 'added'
01173 
01174 static bool
01175 transactItems( PoolItem_Ref installed, PoolItem_Ref uninstalled, bool install, bool soft, PoolItem_Ref & added )
01176 {
01177         if (install) {
01178             if (compareByNVRA (installed.resolvable(), uninstalled.resolvable()) != 0) { // do not update itself Bug 174290
01179                 if (uninstalled
01180                     && !uninstalled.status().isLocked())
01181                 {
01182                     bool adding;        // check if we're succeeding with transaction
01183                     if (soft)
01184                         adding = uninstalled.status().setSoftTransact( true, ResStatus::APPL_LOW );
01185                     else
01186                         adding = uninstalled.status().setTransact( true, ResStatus::APPL_LOW );
01187                     if (adding) // if succeeded, return it as 'just added'
01188                         added = uninstalled;
01189                 }
01190                 if (installed
01191                     && !installed.status().isLocked())
01192                 {
01193                     installed.status().resetTransact( ResStatus::APPL_LOW );
01194                 }
01195             }
01196         } else {
01197             // uninstall
01198             if (uninstalled
01199                 && !uninstalled.status().isLocked())
01200             {
01201                 uninstalled.status().resetTransact( ResStatus::APPL_LOW );
01202             }
01203             if (installed
01204                 && !installed.status().isLocked())
01205             {
01206                 if (soft)
01207                     installed.status().setSoftTransact( true, ResStatus::APPL_LOW );
01208                 else
01209                     installed.status().setTransact( true, ResStatus::APPL_LOW );
01210             }
01211         }
01212         if (!uninstalled
01213             && !installed)
01214         {
01215             return false;
01216         }
01217     return true;
01218 }
01219 
01220 
01221 typedef struct { PoolItem_Ref installed; PoolItem_Ref uninstalled; } IandU;
01222 typedef map<string, IandU> IandUMap;
01223 
01224 // find best available providers for requested capability index
01225 // (use capability index instead of name in order to find e.g. ccb vs. x11)
01226 
01227 struct FindIandU
01228 {
01229     IandUMap iandu;             // install, and best uninstalled
01230 
01231     FindIandU ()
01232     { }
01233 
01234     bool operator()( const CapAndItem & cai )
01235     {
01236         PoolItem item( cai.item );
01237         string idx = cai.cap.index();
01238 
01239         if ( item.status().staysInstalled() ) {
01240             iandu[idx].installed = item;
01241         }
01242         else if ( item.status().isToBeInstalled() ) {                   // prefer already to-be-installed
01243             iandu[idx].uninstalled = item;
01244         }
01245         else if ( item.status().staysUninstalled() ) {                  // only look at uninstalled
01246             IandUMap::iterator it = iandu.find( idx );
01247 
01248             if (it != iandu.end()
01249                 && it->second.uninstalled)
01250             {                                                           // uninstalled with same name found
01251                 int cmp = it->second.uninstalled->arch().compare( item->arch() );
01252                 if (cmp < 0) {                                          // new item has better arch
01253                     it->second.uninstalled = item;
01254                 }
01255                 else if (cmp == 0) {                                    // new item has equal arch
01256                     if (it->second.uninstalled->edition().compare( item->edition() ) < 0) {
01257                         it->second.uninstalled = item;                  // new item has better edition
01258                     }
01259                 }
01260             }
01261             else {
01262                 iandu[idx].uninstalled = item;
01263             }
01264         }
01265         return true;
01266     }
01267 };
01268 
01269 
01270 //
01271 // transact list of capabilities (requires or recommends)
01272 //  return false if one couldn't be matched
01273 //
01274 // see Resolver::transactResObject
01275 //
01276 
01277 static bool
01278 transactCaps( const ResPool & pool, const CapSet & caps, bool install, bool soft, std::set<PoolItem_Ref> & added_items )
01279 {
01280     bool result = true;
01281 
01282     // loop over capabilities and find (best) matching provider
01283 
01284     for (CapSet::const_iterator cit = caps.begin(); cit != caps.end(); ++cit) {
01285 
01286         // find best providers of requested capability
01287 
01288         FindIandU callback;
01289         Dep dep( Dep::PROVIDES );
01290         invokeOnEach( pool.byCapabilityIndexBegin( cit->index(), dep ),
01291                       pool.byCapabilityIndexEnd( cit->index(), dep ),
01292                       resfilter::ByCapMatch( *cit ) ,
01293                       functor::functorRef<bool,CapAndItem>(callback) );
01294 
01295         // loop through providers and transact them accordingly
01296 
01297         for (IandUMap::const_iterator it = callback.iandu.begin(); it !=  callback.iandu.end(); ++it) {
01298             PoolItem_Ref just_added;
01299             just_added = PoolItem_Ref();
01300             if (!transactItems( it->second.installed, it->second.uninstalled, install, soft, just_added )) {
01301                 result = false;
01302             }
01303             else if (just_added) {
01304                 // transactItems just selected an item of the same kind we're currently processing
01305                 // add it to the list and handle it equivalent to the origin item
01306                 added_items.insert( just_added );
01307             }
01308         }
01309 
01310     }
01311     return result;
01312 }
01313 
01314 
01315 struct TransactSupplements : public resfilter::PoolItemFilterFunctor
01316 {
01317     const Resolvable::Kind &_kind;
01318     bool valid;
01319 
01320     TransactSupplements( const Resolvable::Kind & kind )
01321         : _kind( kind )
01322         , valid( false )
01323     { }
01324 
01325     bool operator()( PoolItem_Ref item )
01326     {
01327 //      MIL << "TransactSupplements(" << item << ")" << endl;
01328         if (item->kind() == _kind
01329             && (item.status().staysInstalled()
01330                 || item.status().isToBeInstalled()))
01331         {
01332             valid = true;
01333             return false;               // end search here
01334         }
01335         return true;
01336     }
01337 };
01338 
01339 //
01340 // transact due to a language dependency
01341 // -> look through the pool and run transactResObject() accordingly
01342 
01343 struct TransactLanguage : public resfilter::PoolItemFilterFunctor
01344 {
01345     Resolver & _resolver;
01346     ResObject::constPtr _langObj;
01347     bool _install;
01348 
01349     TransactLanguage( Resolver & r, ResObject::constPtr langObj, bool install )
01350         : _resolver( r )
01351         , _langObj( langObj )
01352         , _install( install )
01353     { }
01354 
01355     /* item has a freshens on _langObj
01356         _langObj just transacted to _install (true == to-be-installed, false == to-be-uninstalled)
01357     */
01358     bool operator()( const CapAndItem & cai )
01359     {
01360         /* check for supplements, if the item has supplements these also must match  */
01361 
01362         PoolItem_Ref item( cai.item );
01363 //      MIL << "TransactLanguage " << item << ", install " << _install << endl;
01364         CapSet supplements( item->dep( Dep::SUPPLEMENTS ) );
01365         if (!supplements.empty()) {
01366 //          MIL << "has supplements" << endl;
01367             bool valid = false;
01368             for (CapSet::const_iterator it = supplements.begin(); it != supplements.end(); ++it) {
01369 //              MIL << "Checking " << *it << endl;
01370                 TransactSupplements callback( it->refers() );
01371                 invokeOnEach( _resolver.pool().byNameBegin( it->index() ),
01372                               _resolver.pool().byNameEnd( it->index() ),
01373                               functor::functorRef<bool,PoolItem>( callback ) );
01374                 if (callback.valid) {
01375                     valid = true;               // found a supplements match
01376                     break;
01377                 }
01378             }
01379             if (!valid) {
01380 //              MIL << "All supplements false" << endl;
01381                 return true;                    // no supplements matched, we're done
01382             }
01383         }
01384 
01385         PoolItem_Ref dummy;
01386         if (_install) {
01387             if (item.status().staysUninstalled()) {
01388                 transactItems( PoolItem_Ref(), item, _install, true, dummy );
01389             }
01390         }
01391         else {
01392             if (item.status().staysInstalled()) {
01393                 transactItems( item, PoolItem_Ref(), _install, true, dummy );
01394             }
01395         }
01396         return true;
01397     }
01398 };
01399 
01400 
01401 
01402 //
01403 // transact a single object
01404 // -> do a 'single step' resolving either installing or removing
01405 //    required and recommended PoolItems
01406 
01407 bool
01408 Resolver::transactResObject( ResObject::constPtr robj, bool install,
01409                              bool recursive)
01410 {
01411     static std::set<PoolItem_Ref> alreadyTransactedObjects;
01412 
01413     if (!recursive) {
01414         alreadyTransactedObjects.clear(); // first call
01415     }
01416     
01417     if (robj == NULL) {
01418         ERR << "NULL ResObject" << endl;
01419     }
01420     _XDEBUG ( "transactResObject(" << *robj << ", " << (install?"install":"remove") << ")");
01421 
01422     if (robj->kind() == ResTraits<Language>::kind) {
01423         TransactLanguage callback( *this, robj, install );
01424         Dep dep( Dep::FRESHENS );
01425         invokeOnEach( pool().byCapabilityIndexBegin( robj->name(), dep ),
01426                       pool().byCapabilityIndexEnd( robj->name(), dep ),
01427                       functor::functorRef<bool,CapAndItem>( callback ) );
01428 
01429     }
01430     std::set<PoolItem_Ref> added;
01431 
01432     // loop over 'recommends' and 'requires' of this item and collect additional
01433     //  items of the same kind on the way
01434 
01435     transactCaps( _pool, robj->dep( Dep::RECOMMENDS ), install, true, added );
01436     transactCaps( _pool, robj->dep( Dep::REQUIRES ), install, false, added );
01437 
01438     // if any additional items were collected, call this functions again recursively
01439     //   This is guaranteed to finish since additional items are those which were not selected before
01440     //   and this function is only called for already selected items. So added really only contains
01441     //   'new' items.
01442 
01443     for (std::set<PoolItem_Ref>::const_iterator it = added.begin(); it != added.end(); ++it) {
01444         if ((*it)->kind() == robj->kind()) {
01445             std::set<PoolItem_Ref>::const_iterator itCmp = alreadyTransactedObjects.find (*it);
01446             if (itCmp == alreadyTransactedObjects.end())
01447             {
01448                 // not already transacted
01449                 alreadyTransactedObjects.insert (*it);
01450                 transactResObject( it->resolvable(), install,
01451                                    true //recursive
01452                                    );
01453             }
01454         }
01455     }
01456 
01457     // not used anyway
01458     return true;
01459 }
01460 
01461 //
01462 // helper to transact all objects of a specific kind
01463 //  see Resolver::transactResKind
01464 // item is to-be-installed (install == true) or to-be-uninstalled
01465 // -> run transactResObject() accordingly
01466 
01467 struct TransactKind : public resfilter::PoolItemFilterFunctor
01468 {
01469     Resolver & _resolver;
01470     bool install;               // true if to-be-installed, else to-be-uninstalled
01471     bool result;
01472 
01473     TransactKind( Resolver & r )
01474         : _resolver( r )
01475         , result( true )
01476     { }
01477 
01478     bool operator()( PoolItem_Ref item )
01479     {
01480         result = _resolver.transactResObject( item.resolvable(), install );
01481         return true;
01482     }
01483 };
01484 
01485 
01486 bool
01487 Resolver::transactResKind( Resolvable::Kind kind )
01488 {
01489     TransactKind callback (*this);
01490     _XDEBUG( "transactResKind(" << kind << ")" );
01491 
01492     // check all uninstalls
01493     callback.install = false;
01494     invokeOnEach( pool().byKindBegin( kind ),
01495                   pool().byKindEnd( kind ),
01496                   functor::chain( resfilter::ByTransact(), resfilter::ByInstalled ()),
01497                   functor::functorRef<bool,PoolItem>( callback ) );
01498 
01499     // check all installs
01500     callback.install = true;
01501     invokeOnEach( pool().byKindBegin( kind ),
01502                   pool().byKindEnd( kind ),
01503                   functor::chain( resfilter::ByTransact(), resfilter::ByUninstalled ()),
01504                   functor::functorRef<bool,PoolItem>( callback ) );
01505 
01506     return callback.result;
01507 }
01508 
01509 
01510 struct TransactReset : public resfilter::PoolItemFilterFunctor
01511 {
01512     ResStatus::TransactByValue _causer;
01513     TransactReset( ResStatus::TransactByValue causer )
01514         : _causer( causer )
01515     { }
01516 
01517     bool operator()( PoolItem_Ref item )                // only transacts() items go here
01518     {
01519         item.status().resetTransact( _causer );
01520         return true;
01521     }
01522 };
01523 
01524 
01525 void
01526 Resolver::transactReset( ResStatus::TransactByValue causer )
01527 {
01528     TransactReset info( causer );
01529     MIL << "transactReset(" << causer << ")" << endl;
01530     invokeOnEach ( _pool.begin(), _pool.end(),
01531                    resfilter::ByTransact( ),
01532                    functor::functorRef<bool,PoolItem>(info) );
01533     return;
01534 }
01535 
01537     };// namespace detail
01540   };// namespace solver
01543 };// namespace zypp
01545 

Generated on Fri Jul 4 16:57:58 2008 for zypp by  doxygen 1.5.0