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 #define ZYPP_USE_RESOLVER_INTERNALS
25 #include "zypp/solver/detail/Resolver.h"
26 #include "zypp/solver/detail/Testcase.h"
27 #include "zypp/solver/detail/SATResolver.h"
28 #include "zypp/solver/detail/ItemCapKind.h"
29 #include "zypp/solver/detail/SolutionAction.h"
30 #include "zypp/solver/detail/SolverQueueItem.h"
32 #include "zypp/Capabilities.h"
33 #include "zypp/ZConfig.h"
34 #include "zypp/base/Logger.h"
35 #include "zypp/base/String.h"
36 #include "zypp/base/Gettext.h"
37 #include "zypp/base/Algorithm.h"
38 #include "zypp/ResPool.h"
39 #include "zypp/ResFilters.h"
40 #include "zypp/sat/Pool.h"
41 #include "zypp/sat/Solvable.h"
42 #include "zypp/sat/Transaction.h"
43 #include "zypp/ResolverProblem.h"
45 #define MAXSOLVERRUNS 5
50 /////////////////////////////////////////////////////////////////////////
52 { ///////////////////////////////////////////////////////////////////////
53 ///////////////////////////////////////////////////////////////////////
55 { /////////////////////////////////////////////////////////////////////
56 /////////////////////////////////////////////////////////////////////
58 { ///////////////////////////////////////////////////////////////////
60 //using namespace std;
62 //---------------------------------------------------------------------------
65 std::ostream & Resolver::dumpOn( std::ostream & os ) const
67 os << "<resolver>" << endl;
68 #define OUTS(t) os << " " << #t << ":\t" << t << endl;
69 OUTS( _forceResolve );
73 OUTS( _onlyRequires );
74 OUTS( _allowVendorChange );
75 OUTS( _solveSrcPackages );
76 OUTS( _cleandepsOnRemove );
77 OUTS( _ignoreAlreadyRecommended );
79 return os << "<resolver/>";
83 //---------------------------------------------------------------------------
85 Resolver::Resolver (const ResPool & pool)
88 , _poolchanged(_pool.serial() )
89 , _forceResolve (false)
90 , _upgradeMode (false)
93 , _onlyRequires ( ZConfig::instance().solver_onlyRequires() )
94 , _allowVendorChange ( ZConfig::instance().solver_allowVendorChange() )
95 , _solveSrcPackages ( false )
96 , _cleandepsOnRemove ( ZConfig::instance().solver_cleandepsOnRemove() )
97 , _ignoreAlreadyRecommended ( true )
100 sat::Pool satPool( sat::Pool::instance() );
101 _satResolver = new SATResolver(_pool, satPool.get());
105 Resolver::~Resolver()
110 //---------------------------------------------------------------------------
111 // forward flags too SATResolver
112 #define ZOLV_FLAG_TRIBOOL( ZSETTER, ZGETTER, ZVARNAME, ZVARDEFAULT ) \
113 void Resolver::ZSETTER( TriBool state_r ) \
114 { _satResolver->ZVARNAME = indeterminate(state_r) ? ZVARDEFAULT : bool(state_r); } \
115 bool Resolver::ZGETTER() const \
116 { return _satResolver->ZVARNAME; } \
118 ZOLV_FLAG_TRIBOOL( dupSetAllowDowngrade, dupAllowDowngrade, _dup_allowdowngrade, ZConfig::instance().solver_dupAllowDowngrade() )
119 ZOLV_FLAG_TRIBOOL( dupSetAllowNameChange, dupAllowNameChange, _dup_allownamechange, ZConfig::instance().solver_dupAllowNameChange() )
120 ZOLV_FLAG_TRIBOOL( dupSetAllowArchChange, dupAllowArchChange, _dup_allowarchchange, ZConfig::instance().solver_dupAllowArchChange() )
121 ZOLV_FLAG_TRIBOOL( dupSetAllowVendorChange, dupAllowVendorChange, _dup_allowvendorchange, ZConfig::instance().solver_dupAllowVendorChange() )
123 #undef ZOLV_FLAG_TRIBOOL
124 //---------------------------------------------------------------------------
126 void Resolver::setAllowVendorChange( TriBool state_r )
128 _allowVendorChange = indeterminate(state_r) ? ZConfig::instance().solver_allowVendorChange() : bool(state_r);
131 void Resolver::setOnlyRequires( TriBool state_r )
133 _onlyRequires = indeterminate(state_r) ? ZConfig::instance().solver_onlyRequires() : bool(state_r);
136 void Resolver::setCleandepsOnRemove( TriBool state_r )
138 _cleandepsOnRemove = indeterminate(state_r) ? ZConfig::instance().solver_cleandepsOnRemove() : bool(state_r);
141 //---------------------------------------------------------------------------
143 ResPool Resolver::pool() const
146 void Resolver::reset( bool keepExtras )
151 _extra_requires.clear();
152 _extra_conflicts.clear();
155 _isInstalledBy.clear();
157 _satifiedByInstalled.clear();
158 _installedSatisfied.clear();
161 bool Resolver::doUpgrade()
163 // Setting Resolver to upgrade mode. SAT solver will do the update
165 return resolvePool();
168 void Resolver::doUpdate()
171 return _satResolver->doUpdate();
174 PoolItemList Resolver::problematicUpdateItems() const
175 { return _satResolver->problematicUpdateItems(); }
177 void Resolver::addExtraRequire( const Capability & capability )
178 { _extra_requires.insert (capability); }
180 void Resolver::removeExtraRequire( const Capability & capability )
181 { _extra_requires.erase (capability); }
183 void Resolver::addExtraConflict( const Capability & capability )
184 { _extra_conflicts.insert (capability); }
186 void Resolver::removeExtraConflict( const Capability & capability )
187 { _extra_conflicts.erase (capability); }
189 void Resolver::removeQueueItem( SolverQueueItem_Ptr item )
192 for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
193 iter != _added_queue_items.end(); iter++) {
195 _added_queue_items.remove(*iter);
201 _removed_queue_items.push_back (item);
202 _removed_queue_items.unique ();
206 void Resolver::addQueueItem( SolverQueueItem_Ptr item )
209 for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
210 iter != _removed_queue_items.end(); iter++) {
212 _removed_queue_items.remove(*iter);
218 _added_queue_items.push_back (item);
219 _added_queue_items.unique ();
223 void Resolver::addWeak( const PoolItem & item )
224 { _addWeak.push_back( item ); }
226 //---------------------------------------------------------------------------
228 struct UndoTransact : public resfilter::PoolItemFilterFunctor
230 ResStatus::TransactByValue resStatus;
231 UndoTransact ( const ResStatus::TransactByValue &status)
235 bool operator()( PoolItem item ) // only transacts() items go here
237 item.status().resetTransact( resStatus );// clear any solver/establish transactions
243 struct DoTransact : public resfilter::PoolItemFilterFunctor
245 ResStatus::TransactByValue resStatus;
246 DoTransact ( const ResStatus::TransactByValue &status)
250 bool operator()( PoolItem item ) // only transacts() items go here
252 item.status().setTransact( true, resStatus );
258 bool Resolver::verifySystem()
260 UndoTransact resetting (ResStatus::APPL_HIGH);
262 DBG << "Resolver::verifySystem()" << endl;
266 invokeOnEach ( _pool.begin(), _pool.end(),
267 resfilter::ByTransact( ), // Resetting all transcations
268 functor::functorRef<bool,PoolItem>(resetting) );
270 return resolvePool();
274 //----------------------------------------------------------------------------
276 void Resolver::undo()
278 UndoTransact info(ResStatus::APPL_LOW);
279 MIL << "*** undo ***" << endl;
280 invokeOnEach ( _pool.begin(), _pool.end(),
281 resfilter::ByTransact( ), // collect transacts from Pool to resolver queue
282 functor::functorRef<bool,PoolItem>(info) );
283 // Regard dependencies of the item weak onl
286 // Additional QueueItems which has to be regarded by the solver
287 _removed_queue_items.clear();
288 _added_queue_items.clear();
293 void Resolver::solverInit()
295 // Solving with libsolv
296 static bool poolDumped = false;
297 MIL << "-------------- Calling SAT Solver -------------------" << endl;
298 if ( getenv("ZYPP_FULLLOG") ) {
299 Testcase testcase("/var/log/YaST2/autoTestcase");
301 testcase.createTestcase (*this, true, false); // dump pool
304 testcase.createTestcase (*this, false, false); // write control file only
308 _satResolver->setFixsystem ( isVerifyingMode() );
309 _satResolver->setIgnorealreadyrecommended ( ignoreAlreadyRecommended() );
310 _satResolver->setOnlyRequires ( onlyRequires() );
311 _satResolver->setAllowdowngrade (false);
312 _satResolver->setAllowarchchange (false);
313 _satResolver->setAllowvendorchange ( allowVendorChange() );
314 _satResolver->setAllowuninstall ( forceResolve() );
315 _satResolver->setUpdatesystem (false);
316 _satResolver->setNoupdateprovide (false);
317 _satResolver->setDosplitprovides (true);
318 _satResolver->setSolveSrcPackages ( solveSrcPackages() );
319 _satResolver->setCleandepsOnRemove ( cleandepsOnRemove() );
321 _satResolver->setDistupgrade (_upgradeMode);
323 // may overwrite some settings
324 _satResolver->setDistupgrade_removeunsupported (false);
327 // Resetting additional solver information
328 _isInstalledBy.clear();
330 _satifiedByInstalled.clear();
331 _installedSatisfied.clear();
334 bool Resolver::resolvePool()
337 return _satResolver->resolvePool(_extra_requires, _extra_conflicts, _addWeak, _upgradeRepos );
340 bool Resolver::resolveQueue( solver::detail::SolverQueueItemList & queue )
344 // add/remove additional SolverQueueItems
345 for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
346 iter != _removed_queue_items.end(); iter++) {
347 for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
348 if ( (*iterQueue)->cmp(*iter) == 0) {
349 MIL << "remove from queue" << *iter;
350 queue.remove(*iterQueue);
356 for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
357 iter != _added_queue_items.end(); iter++) {
359 for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
360 if ( (*iterQueue)->cmp(*iter) == 0) {
366 MIL << "add to queue" << *iter;
367 queue.push_back(*iter);
371 // The application has to take care to write these solutions back to e.g. selectables in order
372 // give the user a chance for changing these decisions again.
373 _removed_queue_items.clear();
374 _added_queue_items.clear();
376 return _satResolver->resolveQueue(queue, _addWeak);
379 sat::Transaction Resolver::getTransaction()
381 // FIXME: That's an ugly way of pushing autoInstalled into the transaction.
382 sat::Transaction ret( sat::Transaction::loadFromPool );
383 ret.autoInstalled( _satResolver->autoInstalled() );
388 //----------------------------------------------------------------------------
389 // Getting more information about the solve results
391 ResolverProblemList Resolver::problems() const
393 MIL << "Resolver::problems()" << endl;
394 return _satResolver->problems();
397 void Resolver::applySolutions( const ProblemSolutionList & solutions )
399 for ( ProblemSolution_Ptr solution : solutions )
401 if ( ! applySolution( *solution ) )
406 bool Resolver::applySolution( const ProblemSolution & solution )
409 DBG << "apply solution " << solution << endl;
410 for ( SolutionAction_Ptr action : solution.actions() )
412 if ( ! action->execute( *this ) )
414 WAR << "apply solution action failed: " << action << endl;
422 //----------------------------------------------------------------------------
424 void Resolver::collectResolverInfo()
427 && _isInstalledBy.empty()
428 && _installs.empty()) {
431 PoolItemList itemsToInstall = _satResolver->resultItemsToInstall();
433 for (PoolItemList::const_iterator instIter = itemsToInstall.begin();
434 instIter != itemsToInstall.end(); instIter++) {
436 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::REQUIRES).begin(); capIt != (*instIter)->dep (Dep::REQUIRES).end(); ++capIt)
438 sat::WhatProvides possibleProviders(*capIt);
439 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
440 PoolItem provider = ResPool::instance().find( *iter );
442 // searching if this provider will already be installed
444 bool alreadySetForInstallation = false;
445 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
446 while (pos != _isInstalledBy.end()
447 && pos->first == provider
449 alreadySetForInstallation = true;
450 ItemCapKind capKind = pos->second;
451 if (capKind.item() == *instIter) found = true;
456 && provider.status().isToBeInstalled()) {
457 if (provider.status().isBySolver()) {
458 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
459 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
461 // no initial installation cause it has been set be e.g. user
462 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, false );
463 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
465 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
466 _installs.insert (make_pair( *instIter, capKindisInstalledBy));
469 if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
470 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, false );
471 _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
473 ItemCapKind installedSatisfied( *instIter, *capIt, Dep::REQUIRES, false );
474 _installedSatisfied.insert (make_pair( provider, installedSatisfied));
479 if (!(_satResolver->onlyRequires())) {
481 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::RECOMMENDS).begin(); capIt != (*instIter)->dep (Dep::RECOMMENDS).end(); ++capIt)
483 sat::WhatProvides possibleProviders(*capIt);
484 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
485 PoolItem provider = ResPool::instance().find( *iter );
487 // searching if this provider will already be installed
489 bool alreadySetForInstallation = false;
490 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
491 while (pos != _isInstalledBy.end()
492 && pos->first == provider
494 alreadySetForInstallation = true;
495 ItemCapKind capKind = pos->second;
496 if (capKind.item() == *instIter) found = true;
501 && provider.status().isToBeInstalled()) {
502 if (provider.status().isBySolver()) {
503 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
504 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
506 // no initial installation cause it has been set be e.g. user
507 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, false );
508 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
510 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
511 _installs.insert (make_pair( *instIter, capKindisInstalledBy));
514 if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
515 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, false );
516 _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
518 ItemCapKind installedSatisfied( *instIter, *capIt, Dep::RECOMMENDS, false );
519 _installedSatisfied.insert (make_pair( provider, installedSatisfied));
525 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::SUPPLEMENTS).begin(); capIt != (*instIter)->dep (Dep::SUPPLEMENTS).end(); ++capIt)
527 sat::WhatProvides possibleProviders(*capIt);
528 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
529 PoolItem provider = ResPool::instance().find( *iter );
530 // searching if this item will already be installed
532 bool alreadySetForInstallation = false;
533 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(*instIter);
534 while (pos != _isInstalledBy.end()
535 && pos->first == *instIter
537 alreadySetForInstallation = true;
538 ItemCapKind capKind = pos->second;
539 if (capKind.item() == provider) found = true;
544 && instIter->status().isToBeInstalled()) {
545 if (instIter->status().isBySolver()) {
546 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
547 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
549 // no initial installation cause it has been set be e.g. user
550 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, false );
551 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
553 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
554 _installs.insert (make_pair( provider, capKindisInstalledBy));
557 if (instIter->status().staysInstalled()) { // Is already satisfied by an item which is installed
558 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
559 _satifiedByInstalled.insert (make_pair( provider, capKindisInstalledBy));
561 ItemCapKind installedSatisfied( provider, *capIt, Dep::SUPPLEMENTS, false );
562 _installedSatisfied.insert (make_pair( *instIter, installedSatisfied));
572 ItemCapKindList Resolver::isInstalledBy( const PoolItem & item )
575 collectResolverInfo();
577 for (ItemCapKindMap::const_iterator iter = _isInstalledBy.find(item); iter != _isInstalledBy.end();) {
578 ItemCapKind info = iter->second;
579 PoolItem iterItem = iter->first;
580 if (iterItem == item) {
585 iter = _isInstalledBy.end();
591 ItemCapKindList Resolver::installs( const PoolItem & item )
594 collectResolverInfo();
596 for (ItemCapKindMap::const_iterator iter = _installs.find(item); iter != _installs.end();) {
597 ItemCapKind info = iter->second;
598 PoolItem iterItem = iter->first;
599 if (iterItem == item) {
604 iter = _installs.end();
610 ItemCapKindList Resolver::satifiedByInstalled( const PoolItem & item )
613 collectResolverInfo();
615 for (ItemCapKindMap::const_iterator iter = _satifiedByInstalled.find(item); iter != _satifiedByInstalled.end();) {
616 ItemCapKind info = iter->second;
617 PoolItem iterItem = iter->first;
618 if (iterItem == item) {
623 iter = _satifiedByInstalled.end();
629 ItemCapKindList Resolver::installedSatisfied( const PoolItem & item )
632 collectResolverInfo();
634 for (ItemCapKindMap::const_iterator iter = _installedSatisfied.find(item); iter != _installedSatisfied.end();) {
635 ItemCapKind info = iter->second;
636 PoolItem iterItem = iter->first;
637 if (iterItem == item) {
642 iter = _installedSatisfied.end();
649 ///////////////////////////////////////////////////////////////////
650 };// namespace detail
651 /////////////////////////////////////////////////////////////////////
652 /////////////////////////////////////////////////////////////////////
653 };// namespace solver
654 ///////////////////////////////////////////////////////////////////////
655 ///////////////////////////////////////////////////////////////////////
657 /////////////////////////////////////////////////////////////////////////