libzypp
10.5.0
|
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