libzypp  10.5.0
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 #include <boost/static_assert.hpp>
00022 
00023 #include "zypp/solver/detail/Resolver.h"
00024 #include "zypp/solver/detail/Helper.h"
00025 #include "zypp/solver/detail/Testcase.h"
00026 #include "zypp/solver/detail/SATResolver.h"
00027 
00028 #include "zypp/Capabilities.h"
00029 #include "zypp/ZConfig.h"
00030 #include "zypp/base/Logger.h"
00031 #include "zypp/base/String.h"
00032 #include "zypp/base/Gettext.h"
00033 #include "zypp/base/Algorithm.h"
00034 #include "zypp/ResPool.h"
00035 #include "zypp/ResFilters.h"
00036 #include "zypp/sat/Pool.h"
00037 #include "zypp/sat/Solvable.h"
00038 #include "zypp/sat/Transaction.h"
00039 #include "zypp/ResolverProblem.h"
00040 
00041 #define MAXSOLVERRUNS 5
00042 
00044 namespace zypp
00045 { 
00046 
00047   namespace solver
00048   { 
00049 
00050     namespace detail
00051     { 
00052 
00053 using namespace std;
00054 
00055 IMPL_PTR_TYPE(Resolver);
00056 
00057 
00058 //---------------------------------------------------------------------------
00059 
00060 
00061 std::ostream & Resolver::dumpOn( std::ostream & os ) const
00062 {
00063   os << "<resolver>" << endl;
00064   #define OUTS(t) os << "  " << #t << ":\t" << t << endl;
00065   OUTS( _forceResolve );
00066   OUTS( _upgradeMode );
00067   OUTS( _updateMode );
00068   OUTS( _verifying );
00069   OUTS( _onlyRequires );
00070   OUTS( _allowVendorChange );
00071   OUTS( _solveSrcPackages );
00072   OUTS( _cleandepsOnRemove );
00073   OUTS( _ignoreAlreadyRecommended );
00074   #undef OUT
00075   return os << "<resolver/>";
00076 }
00077 
00078 
00079 //---------------------------------------------------------------------------
00080 
00081 Resolver::Resolver (const ResPool & pool)
00082     : _pool(pool)
00083     , _satResolver(NULL)
00084     , _poolchanged(_pool.serial() )
00085     , _forceResolve             (false)
00086     , _upgradeMode              (false)
00087     , _updateMode               (false)
00088     , _verifying                (false)
00089     , _onlyRequires             ( ZConfig::instance().solver_onlyRequires() )
00090     , _allowVendorChange        ( ZConfig::instance().solver_allowVendorChange() )
00091     , _solveSrcPackages         ( false )
00092     , _cleandepsOnRemove        ( ZConfig::instance().solver_cleandepsOnRemove() )
00093     , _ignoreAlreadyRecommended ( false )
00094 
00095 {
00096     sat::Pool satPool( sat::Pool::instance() );
00097     _satResolver = new SATResolver(_pool, satPool.get());
00098 }
00099 
00100 
00101 Resolver::~Resolver()
00102 {
00103   delete _satResolver;
00104 }
00105 
00106 //---------------------------------------------------------------------------
00107 
00108 void Resolver::setAllowVendorChange( TriBool state_r )
00109 {
00110   _allowVendorChange = indeterminate(state_r) ? ZConfig::instance().solver_allowVendorChange() : bool(state_r);
00111 }
00112 
00113 void Resolver::setOnlyRequires( TriBool state_r )
00114 {
00115   _onlyRequires = indeterminate(state_r) ? ZConfig::instance().solver_onlyRequires() : bool(state_r);
00116 }
00117 
00118 void Resolver::setCleandepsOnRemove( TriBool state_r )
00119 {
00120   _cleandepsOnRemove = indeterminate(state_r) ? ZConfig::instance().solver_cleandepsOnRemove() : bool(state_r);
00121 }
00122 
00123 //---------------------------------------------------------------------------
00124 
00125 ResPool Resolver::pool() const
00126 { return _pool; }
00127 
00128 void Resolver::reset( bool keepExtras )
00129 {
00130     _verifying = false;
00131 
00132     if (!keepExtras) {
00133       _extra_requires.clear();
00134       _extra_conflicts.clear();
00135     }
00136 
00137     _isInstalledBy.clear();
00138     _installs.clear();
00139     _satifiedByInstalled.clear();
00140     _installedSatisfied.clear();
00141 }
00142 
00143 bool Resolver::doUpgrade()
00144 {
00145   // Setting Resolver to upgrade mode. SAT solver will do the update
00146   _upgradeMode = true;
00147   return resolvePool();
00148 }
00149 
00150 void Resolver::doUpdate()
00151 {
00152     _updateMode = true;
00153     return _satResolver->doUpdate();
00154 }
00155 
00156 PoolItemList Resolver::problematicUpdateItems() const
00157 { return _satResolver->problematicUpdateItems(); }
00158 
00159 void Resolver::addExtraRequire( const Capability & capability )
00160 { _extra_requires.insert (capability); }
00161 
00162 void Resolver::removeExtraRequire( const Capability & capability )
00163 { _extra_requires.erase (capability); }
00164 
00165 void Resolver::addExtraConflict( const Capability & capability )
00166 { _extra_conflicts.insert (capability); }
00167 
00168 void Resolver::removeExtraConflict( const Capability & capability )
00169 { _extra_conflicts.erase (capability); }
00170 
00171 void Resolver::removeQueueItem( SolverQueueItem_Ptr item )
00172 {
00173     bool found = false;
00174     for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
00175          iter != _added_queue_items.end(); iter++) {
00176         if (*iter == item) {
00177             _added_queue_items.remove(*iter);
00178             found = true;
00179             break;
00180         }
00181     }
00182     if (!found) {
00183         _removed_queue_items.push_back (item);
00184         _removed_queue_items.unique ();
00185     }
00186 }
00187 
00188 void Resolver::addQueueItem( SolverQueueItem_Ptr item )
00189 {
00190     bool found = false;
00191     for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
00192          iter != _removed_queue_items.end(); iter++) {
00193         if (*iter == item) {
00194             _removed_queue_items.remove(*iter);
00195             found = true;
00196             break;
00197         }
00198     }
00199     if (!found) {
00200         _added_queue_items.push_back (item);
00201         _added_queue_items.unique ();
00202     }
00203 }
00204 
00205 void Resolver::addWeak( const PoolItem & item )
00206 { _addWeak.push_back( item ); }
00207 
00208 //---------------------------------------------------------------------------
00209 
00210 struct UndoTransact : public resfilter::PoolItemFilterFunctor
00211 {
00212     ResStatus::TransactByValue resStatus;
00213     UndoTransact ( const ResStatus::TransactByValue &status)
00214         :resStatus(status)
00215     { }
00216 
00217     bool operator()( PoolItem item )            // only transacts() items go here
00218     {
00219         item.status().resetTransact( resStatus );// clear any solver/establish transactions
00220         return true;
00221     }
00222 };
00223 
00224 
00225 struct DoTransact : public resfilter::PoolItemFilterFunctor
00226 {
00227     ResStatus::TransactByValue resStatus;
00228     DoTransact ( const ResStatus::TransactByValue &status)
00229         :resStatus(status)
00230     { }
00231 
00232     bool operator()( PoolItem item )            // only transacts() items go here
00233     {
00234         item.status().setTransact( true, resStatus );
00235         return true;
00236     }
00237 };
00238 
00239 
00240 bool Resolver::verifySystem()
00241 {
00242     UndoTransact resetting (ResStatus::APPL_HIGH);
00243 
00244     _DEBUG ("Resolver::verifySystem() ");
00245 
00246     _verifying = true;
00247 
00248     invokeOnEach ( _pool.begin(), _pool.end(),
00249                    resfilter::ByTransact( ),                    // Resetting all transcations
00250                    functor::functorRef<bool,PoolItem>(resetting) );
00251 
00252     return resolvePool();
00253 }
00254 
00255 
00256 //----------------------------------------------------------------------------
00257 // undo
00258 
00259 void Resolver::undo()
00260 {
00261     UndoTransact info(ResStatus::APPL_LOW);
00262     MIL << "*** undo ***" << endl;
00263     invokeOnEach ( _pool.begin(), _pool.end(),
00264                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
00265                    functor::functorRef<bool,PoolItem>(info) );
00266     //  Regard dependencies of the item weak onl
00267     _addWeak.clear();
00268 
00269     // Additional QueueItems which has to be regarded by the solver
00270     _removed_queue_items.clear();
00271     _added_queue_items.clear();
00272 
00273     return;
00274 }
00275 
00276 void Resolver::solverInit()
00277 {
00278     // Solving with libsolv
00279     static bool poolDumped = false;
00280     MIL << "-------------- Calling SAT Solver -------------------" << endl;
00281     if ( getenv("ZYPP_FULLLOG") ) {
00282         Testcase testcase("/var/log/YaST2/autoTestcase");
00283         if (!poolDumped) {
00284             testcase.createTestcase (*this, true, false); // dump pool
00285             poolDumped = true;
00286         } else {
00287             testcase.createTestcase (*this, false, false); // write control file only
00288         }
00289     }
00290 
00291     _satResolver->setFixsystem                  ( isVerifyingMode() );
00292     _satResolver->setIgnorealreadyrecommended   ( ignoreAlreadyRecommended() );
00293     _satResolver->setOnlyRequires               ( onlyRequires() );
00294     _satResolver->setAllowdowngrade             (false);
00295     _satResolver->setAllowarchchange            (false);
00296     _satResolver->setAllowvendorchange          ( allowVendorChange() );
00297     _satResolver->setAllowuninstall             ( forceResolve() );
00298     _satResolver->setUpdatesystem               (false);
00299     _satResolver->setNoupdateprovide            (false);
00300     _satResolver->setDosplitprovides            (false);
00301     _satResolver->setSolveSrcPackages           ( solveSrcPackages() );
00302     _satResolver->setCleandepsOnRemove          ( cleandepsOnRemove() );
00303 
00304     _satResolver->setDistupgrade                (_upgradeMode);
00305     if (_upgradeMode) {
00306       // may overwrite some settings
00307       _satResolver->setDistupgrade_removeunsupported    (false);
00308       _satResolver->setUpdatesystem                     (true);
00309       _satResolver->setAllowdowngrade                   (true);
00310       _satResolver->setAllowarchchange                  (true);
00311       _satResolver->setAllowvendorchange                (true);
00312       _satResolver->setDosplitprovides                  (true);
00313     }
00314 
00315     // Resetting additional solver information
00316     _isInstalledBy.clear();
00317     _installs.clear();
00318     _satifiedByInstalled.clear();
00319     _installedSatisfied.clear();
00320 }
00321 
00322 bool Resolver::resolvePool()
00323 {
00324     solverInit();
00325     return _satResolver->resolvePool(_extra_requires, _extra_conflicts, _addWeak, _upgradeRepos );
00326 }
00327 
00328 bool Resolver::resolveQueue( solver::detail::SolverQueueItemList & queue )
00329 {
00330     solverInit();
00331 
00332     // add/remove additional SolverQueueItems
00333     for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
00334          iter != _removed_queue_items.end(); iter++) {
00335         for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
00336             if ( (*iterQueue)->cmp(*iter) == 0) {
00337                 MIL << "remove from queue" << *iter;
00338                 queue.remove(*iterQueue);
00339                 break;
00340             }
00341         }
00342     }
00343 
00344     for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
00345          iter != _added_queue_items.end(); iter++) {
00346         bool found = false;
00347         for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
00348             if ( (*iterQueue)->cmp(*iter) == 0) {
00349                 found = true;
00350                 break;
00351             }
00352         }
00353         if (!found) {
00354             MIL << "add to queue" << *iter;
00355             queue.push_back(*iter);
00356         }
00357     }
00358 
00359     // The application has to take care to write these solutions back to e.g. selectables in order
00360     // give the user a chance for changing these decisions again.
00361     _removed_queue_items.clear();
00362     _added_queue_items.clear();
00363 
00364     return _satResolver->resolveQueue(queue, _addWeak);
00365 }
00366 
00367 sat::Transaction Resolver::getTransaction()
00368 { return _satResolver->getTransaction(); }
00369 
00370 //----------------------------------------------------------------------------
00371 // Getting more information about the solve results
00372 
00373 ResolverProblemList Resolver::problems() const
00374 {
00375   MIL << "Resolver::problems()" << endl;
00376   return _satResolver->problems();
00377 }
00378 
00379 void Resolver::applySolutions( const ProblemSolutionList & solutions )
00380 {
00381   for_( iter, solutions.begin(), solutions.end() )
00382   {
00383     ProblemSolution_Ptr solution = *iter;
00384     if ( !solution->apply( *this ) )
00385       break;
00386   }
00387 }
00388 
00389 void Resolver::collectResolverInfo()
00390 {
00391     if ( _satResolver
00392          && _isInstalledBy.empty()
00393          && _installs.empty()) {
00394 
00395         // generating new
00396         PoolItemList itemsToInstall = _satResolver->resultItemsToInstall();
00397 
00398         for (PoolItemList::const_iterator instIter = itemsToInstall.begin();
00399              instIter != itemsToInstall.end(); instIter++) {
00400             // Requires
00401             for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::REQUIRES).begin(); capIt != (*instIter)->dep (Dep::REQUIRES).end(); ++capIt)
00402             {
00403                 sat::WhatProvides possibleProviders(*capIt);
00404                 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
00405                     PoolItem provider = ResPool::instance().find( *iter );
00406 
00407                     // searching if this provider will already be installed
00408                     bool found = false;
00409                     bool alreadySetForInstallation = false;
00410                     ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
00411                     while (pos != _isInstalledBy.end()
00412                            && pos->first == provider
00413                            && !found) {
00414                         alreadySetForInstallation = true;
00415                         ItemCapKind capKind = pos->second;
00416                         if (capKind.item == *instIter)  found = true;
00417                         pos++;
00418                     }
00419 
00420                     if (!found
00421                         && provider.status().isToBeInstalled()) {
00422                         if (provider.status().isBySolver()) {
00423                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
00424                             _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
00425                         } else {
00426                             // no initial installation cause it has been set be e.g. user
00427                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, false );
00428                             _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
00429                         }
00430                         ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
00431                         _installs.insert (make_pair( *instIter, capKindisInstalledBy));
00432                     }
00433 
00434                     if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
00435                         ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, false );
00436                         _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
00437 
00438                         ItemCapKind installedSatisfied( *instIter, *capIt, Dep::REQUIRES, false );
00439                         _installedSatisfied.insert (make_pair( provider, installedSatisfied));
00440                     }
00441                 }
00442             }
00443 
00444             if (!(_satResolver->onlyRequires())) {
00445                 //Recommends
00446                 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::RECOMMENDS).begin(); capIt != (*instIter)->dep (Dep::RECOMMENDS).end(); ++capIt)
00447                 {
00448                     sat::WhatProvides possibleProviders(*capIt);
00449                     for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
00450                         PoolItem provider = ResPool::instance().find( *iter );
00451 
00452                         // searching if this provider will already be installed
00453                         bool found = false;
00454                         bool alreadySetForInstallation = false;
00455                         ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
00456                         while (pos != _isInstalledBy.end()
00457                                && pos->first == provider
00458                                && !found) {
00459                             alreadySetForInstallation = true;
00460                             ItemCapKind capKind = pos->second;
00461                             if (capKind.item == *instIter)  found = true;
00462                             pos++;
00463                         }
00464 
00465                         if (!found
00466                             && provider.status().isToBeInstalled()) {
00467                             if (provider.status().isBySolver()) {
00468                                 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
00469                                 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
00470                             } else {
00471                                 // no initial installation cause it has been set be e.g. user
00472                                 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, false );
00473                                 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
00474                             }
00475                             ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
00476                             _installs.insert (make_pair( *instIter, capKindisInstalledBy));
00477                         }
00478 
00479                         if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
00480                             ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, false );
00481                             _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
00482 
00483                             ItemCapKind installedSatisfied( *instIter, *capIt, Dep::RECOMMENDS, false );
00484                             _installedSatisfied.insert (make_pair( provider, installedSatisfied));
00485                         }
00486                     }
00487                 }
00488 
00489                 //Supplements
00490                 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::SUPPLEMENTS).begin(); capIt != (*instIter)->dep (Dep::SUPPLEMENTS).end(); ++capIt)
00491                 {
00492                     sat::WhatProvides possibleProviders(*capIt);
00493                     for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
00494                         PoolItem provider = ResPool::instance().find( *iter );
00495                         // searching if this item will already be installed
00496                         bool found = false;
00497                         bool alreadySetForInstallation = false;
00498                         ItemCapKindMap::const_iterator pos = _isInstalledBy.find(*instIter);
00499                         while (pos != _isInstalledBy.end()
00500                                && pos->first == *instIter
00501                                && !found) {
00502                             alreadySetForInstallation = true;
00503                             ItemCapKind capKind = pos->second;
00504                             if (capKind.item == provider)  found = true;
00505                             pos++;
00506                         }
00507 
00508                         if (!found
00509                             && instIter->status().isToBeInstalled()) {
00510                             if (instIter->status().isBySolver()) {
00511                                 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
00512                                 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
00513                             } else {
00514                                 // no initial installation cause it has been set be e.g. user
00515                                 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, false );
00516                                 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
00517                             }
00518                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
00519                             _installs.insert (make_pair( provider, capKindisInstalledBy));
00520                         }
00521 
00522                         if (instIter->status().staysInstalled()) { // Is already satisfied by an item which is installed
00523                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
00524                             _satifiedByInstalled.insert (make_pair( provider, capKindisInstalledBy));
00525 
00526                             ItemCapKind installedSatisfied( provider, *capIt, Dep::SUPPLEMENTS, false );
00527                             _installedSatisfied.insert (make_pair( *instIter, installedSatisfied));
00528                         }
00529                     }
00530                 }
00531             }
00532         }
00533     }
00534 }
00535 
00536 
00537 ItemCapKindList Resolver::isInstalledBy( const PoolItem & item )
00538 {
00539     ItemCapKindList ret;
00540     collectResolverInfo();
00541 
00542     for (ItemCapKindMap::const_iterator iter = _isInstalledBy.find(item); iter != _isInstalledBy.end();) {
00543         ItemCapKind info = iter->second;
00544         PoolItem iterItem = iter->first;
00545         if (iterItem == item) {
00546             ret.push_back(info);
00547             iter++;
00548         } else {
00549             // exit
00550             iter = _isInstalledBy.end();
00551         }
00552     }
00553     return ret;
00554 }
00555 
00556 ItemCapKindList Resolver::installs( const PoolItem & item )
00557 {
00558     ItemCapKindList ret;
00559     collectResolverInfo();
00560 
00561     for (ItemCapKindMap::const_iterator iter = _installs.find(item); iter != _installs.end();) {
00562         ItemCapKind info = iter->second;
00563         PoolItem iterItem = iter->first;
00564         if (iterItem == item) {
00565             ret.push_back(info);
00566             iter++;
00567         } else {
00568             // exit
00569             iter = _installs.end();
00570         }
00571     }
00572     return ret;
00573 }
00574 
00575 ItemCapKindList Resolver::satifiedByInstalled( const PoolItem & item )
00576 {
00577     ItemCapKindList ret;
00578     collectResolverInfo();
00579 
00580     for (ItemCapKindMap::const_iterator iter = _satifiedByInstalled.find(item); iter != _satifiedByInstalled.end();) {
00581         ItemCapKind info = iter->second;
00582         PoolItem iterItem = iter->first;
00583         if (iterItem == item) {
00584             ret.push_back(info);
00585             iter++;
00586         } else {
00587             // exit
00588             iter = _satifiedByInstalled.end();
00589         }
00590     }
00591     return ret;
00592 }
00593 
00594 ItemCapKindList Resolver::installedSatisfied( const PoolItem & item )
00595 {
00596     ItemCapKindList ret;
00597     collectResolverInfo();
00598 
00599     for (ItemCapKindMap::const_iterator iter = _installedSatisfied.find(item); iter != _installedSatisfied.end();) {
00600         ItemCapKind info = iter->second;
00601         PoolItem iterItem = iter->first;
00602         if (iterItem == item) {
00603             ret.push_back(info);
00604             iter++;
00605         } else {
00606             // exit
00607             iter = _installedSatisfied.end();
00608         }
00609     }
00610     return ret;
00611 }
00612 
00613 
00615     };// namespace detail
00618   };// namespace solver
00621 };// namespace zypp
00623