1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
4 * Copyright (C) 2000-2002 Ximian, Inc.
5 * Copyright (C) 2005 SUSE Linux Products GmbH
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 #include <boost/static_assert.hpp>
23 #include "zypp/solver/detail/Resolver.h"
24 #include "zypp/solver/detail/Helper.h"
25 #include "zypp/solver/detail/Testcase.h"
26 #include "zypp/solver/detail/SATResolver.h"
28 #include "zypp/Capabilities.h"
29 #include "zypp/ZConfig.h"
30 #include "zypp/base/Logger.h"
31 #include "zypp/base/String.h"
32 #include "zypp/base/Gettext.h"
33 #include "zypp/base/Algorithm.h"
34 #include "zypp/ResPool.h"
35 #include "zypp/ResFilters.h"
36 #include "zypp/sat/Pool.h"
37 #include "zypp/sat/Solvable.h"
39 #define MAXSOLVERRUNS 5
41 /////////////////////////////////////////////////////////////////////////
43 { ///////////////////////////////////////////////////////////////////////
44 ///////////////////////////////////////////////////////////////////////
46 { /////////////////////////////////////////////////////////////////////
47 /////////////////////////////////////////////////////////////////////
49 { ///////////////////////////////////////////////////////////////////
53 IMPL_PTR_TYPE(Resolver);
56 //---------------------------------------------------------------------------
60 Resolver::dumpOn( std::ostream & os ) const
62 return os << "<resolver/>";
66 //---------------------------------------------------------------------------
68 Resolver::Resolver (const ResPool & pool)
71 , _poolchanged(_pool.serial() )
73 , _forceResolve(false)
76 , _onlyRequires(indeterminate)
77 , _ignorealreadyrecommended(false)
80 sat::Pool satPool( sat::Pool::instance() );
81 _satResolver = new SATResolver(_pool, satPool.get());
89 //---------------------------------------------------------------------------
92 Resolver::pool (void) const
98 Resolver::reset (bool keepExtras )
103 _extra_requires.clear();
104 _extra_conflicts.clear();
107 _isInstalledBy.clear();
109 _satifiedByInstalled.clear();
110 _installedSatisfied.clear();
116 return _satResolver->doUpdate();
120 Resolver::addExtraRequire (const Capability & capability)
122 _extra_requires.insert (capability);
126 Resolver::removeExtraRequire (const Capability & capability)
128 _extra_requires.erase (capability);
132 Resolver::addExtraConflict (const Capability & capability)
134 _extra_conflicts.insert (capability);
138 Resolver::removeExtraConflict (const Capability & capability)
140 _extra_conflicts.erase (capability);
143 void Resolver::removeQueueItem (const SolverQueueItem_Ptr item)
146 for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
147 iter != _added_queue_items.end(); iter++) {
149 _added_queue_items.remove(*iter);
155 _removed_queue_items.push_back (item);
156 _removed_queue_items.unique ();
159 void Resolver::addQueueItem (const SolverQueueItem_Ptr item)
162 for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
163 iter != _removed_queue_items.end(); iter++) {
165 _removed_queue_items.remove(*iter);
171 _added_queue_items.push_back (item);
172 _added_queue_items.unique ();
177 Resolver::addWeak (const PoolItem item)
179 _addWeak.push_back (item);
182 //---------------------------------------------------------------------------
184 struct UndoTransact : public resfilter::PoolItemFilterFunctor
186 ResStatus::TransactByValue resStatus;
187 UndoTransact ( const ResStatus::TransactByValue &status)
191 bool operator()( PoolItem item ) // only transacts() items go here
193 item.status().resetTransact( resStatus );// clear any solver/establish transactions
199 struct DoTransact : public resfilter::PoolItemFilterFunctor
201 ResStatus::TransactByValue resStatus;
202 DoTransact ( const ResStatus::TransactByValue &status)
206 bool operator()( PoolItem item ) // only transacts() items go here
208 item.status().setTransact( true, resStatus );
215 Resolver::verifySystem ()
217 UndoTransact resetting (ResStatus::APPL_HIGH);
219 _DEBUG ("Resolver::verifySystem() ");
223 invokeOnEach ( _pool.begin(), _pool.end(),
224 resfilter::ByTransact( ), // Resetting all transcations
225 functor::functorRef<bool,PoolItem>(resetting) );
227 return resolvePool();
231 //----------------------------------------------------------------------------
237 UndoTransact info(ResStatus::APPL_LOW);
238 MIL << "*** undo ***" << endl;
239 invokeOnEach ( _pool.begin(), _pool.end(),
240 resfilter::ByTransact( ), // collect transacts from Pool to resolver queue
241 functor::functorRef<bool,PoolItem>(info) );
242 // Regard dependencies of the item weak onl
246 _noObsoletesCapability.clear();
247 _noObsoletesItem.clear();
248 _noObsoletesString.clear();
250 // Additional QueueItems which has to be regarded by the solver
251 _removed_queue_items.clear();
252 _added_queue_items.clear();
258 Resolver::solverInit()
260 // Solving with the satsolver
261 static bool poolDumped = false;
262 MIL << "-------------- Calling SAT Solver -------------------" << endl;
263 if ( getenv("ZYPP_FULLLOG") ) {
264 Testcase testcase("/var/log/YaST2/autoTestcase");
266 testcase.createTestcase (*this, true, false); // dump pool
269 testcase.createTestcase (*this, false, false); // write control file only
273 _satResolver->setFixsystem(false);
274 _satResolver->setIgnorealreadyrecommended(false);
275 _satResolver->setAllowdowngrade(false);
276 _satResolver->setAllowarchchange(false);
277 _satResolver->setAllowvendorchange(false);
278 _satResolver->setAllowuninstall(false);
279 _satResolver->setUpdatesystem(false);
280 _satResolver->setAllowvirtualconflicts(false);
281 _satResolver->setNoupdateprovide(true);
282 _satResolver->setDosplitprovides(false);
285 _satResolver->setAllowdowngrade(true);
286 _satResolver->setUpdatesystem(false); // not needed cause packages has already been evaluteted by distupgrade
287 _satResolver->setDosplitprovides(true);
291 _satResolver->setAllowuninstall(true);
293 if (_onlyRequires == indeterminate)
294 _satResolver->setOnlyRequires(ZConfig::instance().solver_onlyRequires());
295 else if (_onlyRequires)
296 _satResolver->setOnlyRequires(true);
298 _satResolver->setOnlyRequires(false);
301 _satResolver->setFixsystem(true);
303 if (_ignorealreadyrecommended)
304 _satResolver->setIgnorealreadyrecommended(true);
306 // Resetting additional solver information
307 _isInstalledBy.clear();
309 _satifiedByInstalled.clear();
310 _installedSatisfied.clear();
314 Resolver::resolvePool()
317 return _satResolver->resolvePool(_extra_requires, _extra_conflicts, _addWeak,
318 _noObsoletesCapability, _noObsoletesItem, _noObsoletesString
323 Resolver::resolveQueue(solver::detail::SolverQueueItemList & queue)
327 // add/remove additional SolverQueueItems
328 for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
329 iter != _removed_queue_items.end(); iter++) {
330 for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
331 if ( (*iterQueue)->cmp(*iter) == 0) {
332 MIL << "remove from queue" << *iter;
333 queue.remove(*iterQueue);
339 for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
340 iter != _added_queue_items.end(); iter++) {
342 for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
343 if ( (*iterQueue)->cmp(*iter) == 0) {
349 MIL << "add to queue" << *iter;
350 queue.push_back(*iter);
354 // The application has to take care to write these solutions back to e.g. selectables in order
355 // give the user a chance for changing these decisions again.
356 _removed_queue_items.clear();
357 _added_queue_items.clear();
359 return _satResolver->resolveQueue(queue, _addWeak,
360 _noObsoletesCapability, _noObsoletesItem, _noObsoletesString);
365 ///////////////////////////////////////////////////////////////////
368 // METHOD NAME : Resolver::checkUnmaintainedItems
371 // DESCRIPTION : Unmaintained packages which does not fit to
372 // the updated system (broken dependencies) will be
374 // returns true if solving was successful
376 bool Resolver::checkUnmaintainedItems () {
378 bool solverRet = resolvePool();
379 MIL << "Checking unmaintained items....." << endl;
381 while (!solverRet && solverRuns++ < MAXSOLVERRUNS) {
382 ResolverProblemList problemList = problems();
383 ProblemSolutionList solutionList;
384 PoolItemList problemItemList;
386 for (ResolverProblemList::iterator iter = problemList.begin(); iter != problemList.end(); ++iter) {
387 ResolverProblem problem = **iter;
388 DBG << "Problem:" << endl;
389 DBG << problem.description() << endl;
390 DBG << problem.details() << endl;
392 ProblemSolutionList solutions = problem.solutions();
393 for (ProblemSolutionList::const_iterator iterSolution = solutions.begin();
394 iterSolution != solutions.end(); ++iterSolution) {
395 ProblemSolution_Ptr solution = *iterSolution;
396 DBG << " Solution:" << endl;
397 DBG << " " << solution->description() << endl;
398 DBG << " " << solution->details() << endl;
399 solver::detail::CSolutionActionList actionList = solution->actions();
400 bool fitUnmaintained = false;
401 PoolItemList deletedItems;
402 for (CSolutionActionList::const_iterator iterActions = actionList.begin();
403 iterActions != actionList.end(); ++iterActions) {
404 TransactionSolutionAction_constPtr transactionAction = dynamic_pointer_cast<const TransactionSolutionAction>(*iterActions);
405 if (transactionAction &&
406 transactionAction->action() == REMOVE
407 && _unmaintained_items.find(transactionAction->item()) != _unmaintained_items.end()) {
408 // The solution contains unmaintained items ONLY which will be deleted. So take this solution
409 fitUnmaintained = true;
410 deletedItems.push_back (transactionAction->item());
412 fitUnmaintained = false;
415 if (fitUnmaintained) {
416 MIL << "Problem:" << endl;
417 MIL << problem.description() << endl;
418 MIL << problem.details() << endl;
419 MIL << "Will be solved by removing unmaintained package(s)............" << endl;
420 MIL << " Solution:" << endl;
421 MIL << " " << solution->description() << endl;
422 MIL << " " << solution->details() << endl;
423 solutionList.push_back (solution);
424 problemItemList.insert (problemItemList.end(), deletedItems.begin(), deletedItems.end() );
425 break; // not regarding the other solutions
430 if (!solutionList.empty()) {
431 applySolutions (solutionList);
432 // list of problematic items after doUpgrade() which is show to the user
433 _problem_items.insert (_problem_items.end(), problemItemList.begin(), problemItemList.end());
434 _problem_items.unique();
436 // break cause there is no other solution available by the next run
437 solverRuns = MAXSOLVERRUNS;
440 solverRet = resolvePool();
446 //----------------------------------------------------------------------------
447 // Getting more information about the solve results
451 Resolver::collectResolverInfo(void)
454 && _isInstalledBy.empty()
455 && _installs.empty()) {
458 PoolItemList itemsToInstall = _satResolver->resultItemsToInstall();
460 for (PoolItemList::const_iterator instIter = itemsToInstall.begin();
461 instIter != itemsToInstall.end(); instIter++) {
463 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::REQUIRES).begin(); capIt != (*instIter)->dep (Dep::REQUIRES).end(); ++capIt)
465 sat::WhatProvides possibleProviders(*capIt);
466 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
467 PoolItem provider = ResPool::instance().find( *iter );
469 // searching if this provider will already be installed
471 bool alreadySetForInstallation = false;
472 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
473 while (pos != _isInstalledBy.end()
474 && pos->first == provider
476 alreadySetForInstallation = true;
477 ItemCapKind capKind = pos->second;
478 if (capKind.item == *instIter) found = true;
483 && provider.status().isToBeInstalled()) {
484 if (provider.status().isBySolver()) {
485 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
486 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
488 // no initial installation cause it has been set be e.g. user
489 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, false );
490 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
492 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
493 _installs.insert (make_pair( *instIter, capKindisInstalledBy));
496 if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
497 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, false );
498 _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
500 ItemCapKind installedSatisfied( *instIter, *capIt, Dep::REQUIRES, false );
501 _installedSatisfied.insert (make_pair( provider, installedSatisfied));
506 if (!(_satResolver->onlyRequires())) {
508 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::RECOMMENDS).begin(); capIt != (*instIter)->dep (Dep::RECOMMENDS).end(); ++capIt)
510 sat::WhatProvides possibleProviders(*capIt);
511 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
512 PoolItem provider = ResPool::instance().find( *iter );
514 // searching if this provider will already be installed
516 bool alreadySetForInstallation = false;
517 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
518 while (pos != _isInstalledBy.end()
519 && pos->first == provider
521 alreadySetForInstallation = true;
522 ItemCapKind capKind = pos->second;
523 if (capKind.item == *instIter) found = true;
528 && provider.status().isToBeInstalled()) {
529 if (provider.status().isBySolver()) {
530 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
531 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
533 // no initial installation cause it has been set be e.g. user
534 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, false );
535 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
537 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
538 _installs.insert (make_pair( *instIter, capKindisInstalledBy));
541 if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
542 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, false );
543 _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
545 ItemCapKind installedSatisfied( *instIter, *capIt, Dep::RECOMMENDS, false );
546 _installedSatisfied.insert (make_pair( provider, installedSatisfied));
552 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::SUPPLEMENTS).begin(); capIt != (*instIter)->dep (Dep::SUPPLEMENTS).end(); ++capIt)
554 sat::WhatProvides possibleProviders(*capIt);
555 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
556 PoolItem provider = ResPool::instance().find( *iter );
557 // searching if this item will already be installed
559 bool alreadySetForInstallation = false;
560 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(*instIter);
561 while (pos != _isInstalledBy.end()
562 && pos->first == *instIter
564 alreadySetForInstallation = true;
565 ItemCapKind capKind = pos->second;
566 if (capKind.item == provider) found = true;
571 && instIter->status().isToBeInstalled()) {
572 if (instIter->status().isBySolver()) {
573 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
574 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
576 // no initial installation cause it has been set be e.g. user
577 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, false );
578 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
580 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
581 _installs.insert (make_pair( provider, capKindisInstalledBy));
584 if (instIter->status().staysInstalled()) { // Is already satisfied by an item which is installed
585 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
586 _satifiedByInstalled.insert (make_pair( provider, capKindisInstalledBy));
588 ItemCapKind installedSatisfied( provider, *capIt, Dep::SUPPLEMENTS, false );
589 _installedSatisfied.insert (make_pair( *instIter, installedSatisfied));
599 const ItemCapKindList Resolver::isInstalledBy (const PoolItem item) {
601 collectResolverInfo();
603 for (ItemCapKindMap::const_iterator iter = _isInstalledBy.find(item); iter != _isInstalledBy.end();) {
604 ItemCapKind info = iter->second;
605 PoolItem iterItem = iter->first;
606 if (iterItem == item) {
611 iter = _isInstalledBy.end();
617 const ItemCapKindList Resolver::installs (const PoolItem item) {
619 collectResolverInfo();
621 for (ItemCapKindMap::const_iterator iter = _installs.find(item); iter != _installs.end();) {
622 ItemCapKind info = iter->second;
623 PoolItem iterItem = iter->first;
624 if (iterItem == item) {
629 iter = _installs.end();
635 const ItemCapKindList Resolver::satifiedByInstalled (const PoolItem item) {
637 collectResolverInfo();
639 for (ItemCapKindMap::const_iterator iter = _satifiedByInstalled.find(item); iter != _satifiedByInstalled.end();) {
640 ItemCapKind info = iter->second;
641 PoolItem iterItem = iter->first;
642 if (iterItem == item) {
647 iter = _satifiedByInstalled.end();
653 const ItemCapKindList Resolver::installedSatisfied (const PoolItem item) {
655 collectResolverInfo();
657 for (ItemCapKindMap::const_iterator iter = _installedSatisfied.find(item); iter != _installedSatisfied.end();) {
658 ItemCapKind info = iter->second;
659 PoolItem iterItem = iter->first;
660 if (iterItem == item) {
665 iter = _installedSatisfied.end();
672 ///////////////////////////////////////////////////////////////////
673 };// namespace detail
674 /////////////////////////////////////////////////////////////////////
675 /////////////////////////////////////////////////////////////////////
676 };// namespace solver
677 ///////////////////////////////////////////////////////////////////////
678 ///////////////////////////////////////////////////////////////////////
680 /////////////////////////////////////////////////////////////////////////