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"
38 #include "zypp/sat/Transaction.h"
40 #define MAXSOLVERRUNS 5
42 /////////////////////////////////////////////////////////////////////////
44 { ///////////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////////
47 { /////////////////////////////////////////////////////////////////////
48 /////////////////////////////////////////////////////////////////////
50 { ///////////////////////////////////////////////////////////////////
54 IMPL_PTR_TYPE(Resolver);
57 //---------------------------------------------------------------------------
60 std::ostream & Resolver::dumpOn( std::ostream & os ) const
62 os << "<resolver>" << endl;
63 #define OUTS(t) os << " " << #t << ":\t" << t << endl;
64 OUTS( _forceResolve );
68 OUTS( _onlyRequires );
69 OUTS( _allowVendorChange );
70 OUTS( _solveSrcPackages );
71 OUTS( _cleandepsOnRemove );
72 OUTS( _ignoreAlreadyRecommended );
74 return os << "<resolver/>";
78 //---------------------------------------------------------------------------
80 Resolver::Resolver (const ResPool & pool)
83 , _poolchanged(_pool.serial() )
84 , _forceResolve (false)
85 , _upgradeMode (false)
88 , _onlyRequires ( ZConfig::instance().solver_onlyRequires() )
89 , _allowVendorChange ( ZConfig::instance().solver_allowVendorChange() )
90 , _solveSrcPackages ( false )
91 , _cleandepsOnRemove ( ZConfig::instance().solver_cleandepsOnRemove() )
92 , _ignoreAlreadyRecommended ( false )
95 sat::Pool satPool( sat::Pool::instance() );
96 _satResolver = new SATResolver(_pool, satPool.get());
100 Resolver::~Resolver()
105 //---------------------------------------------------------------------------
107 void Resolver::setAllowVendorChange( TriBool state_r )
109 _allowVendorChange = indeterminate(state_r) ? ZConfig::instance().solver_allowVendorChange() : bool(state_r);
112 void Resolver::setOnlyRequires( TriBool state_r )
114 _onlyRequires = indeterminate(state_r) ? ZConfig::instance().solver_onlyRequires() : bool(state_r);
117 void Resolver::setCleandepsOnRemove( TriBool state_r )
119 _cleandepsOnRemove = indeterminate(state_r) ? ZConfig::instance().solver_cleandepsOnRemove() : bool(state_r);
122 //---------------------------------------------------------------------------
124 ResPool Resolver::pool() const
127 void Resolver::reset( bool keepExtras )
132 _extra_requires.clear();
133 _extra_conflicts.clear();
136 _isInstalledBy.clear();
138 _satifiedByInstalled.clear();
139 _installedSatisfied.clear();
142 void Resolver::doUpdate()
145 return _satResolver->doUpdate();
148 PoolItemList Resolver::problematicUpdateItems() const
149 { return _satResolver->problematicUpdateItems(); }
151 void Resolver::addExtraRequire( const Capability & capability )
152 { _extra_requires.insert (capability); }
154 void Resolver::removeExtraRequire( const Capability & capability )
155 { _extra_requires.erase (capability); }
157 void Resolver::addExtraConflict( const Capability & capability )
158 { _extra_conflicts.insert (capability); }
160 void Resolver::removeExtraConflict( const Capability & capability )
161 { _extra_conflicts.erase (capability); }
163 void Resolver::removeQueueItem( SolverQueueItem_Ptr item )
166 for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
167 iter != _added_queue_items.end(); iter++) {
169 _added_queue_items.remove(*iter);
175 _removed_queue_items.push_back (item);
176 _removed_queue_items.unique ();
180 void Resolver::addQueueItem( SolverQueueItem_Ptr item )
183 for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
184 iter != _removed_queue_items.end(); iter++) {
186 _removed_queue_items.remove(*iter);
192 _added_queue_items.push_back (item);
193 _added_queue_items.unique ();
197 void Resolver::addWeak( const PoolItem & item )
198 { _addWeak.push_back( item ); }
200 //---------------------------------------------------------------------------
202 struct UndoTransact : public resfilter::PoolItemFilterFunctor
204 ResStatus::TransactByValue resStatus;
205 UndoTransact ( const ResStatus::TransactByValue &status)
209 bool operator()( PoolItem item ) // only transacts() items go here
211 item.status().resetTransact( resStatus );// clear any solver/establish transactions
217 struct DoTransact : public resfilter::PoolItemFilterFunctor
219 ResStatus::TransactByValue resStatus;
220 DoTransact ( const ResStatus::TransactByValue &status)
224 bool operator()( PoolItem item ) // only transacts() items go here
226 item.status().setTransact( true, resStatus );
232 bool Resolver::verifySystem()
234 UndoTransact resetting (ResStatus::APPL_HIGH);
236 _DEBUG ("Resolver::verifySystem() ");
240 invokeOnEach ( _pool.begin(), _pool.end(),
241 resfilter::ByTransact( ), // Resetting all transcations
242 functor::functorRef<bool,PoolItem>(resetting) );
244 return resolvePool();
248 //----------------------------------------------------------------------------
251 void Resolver::undo()
253 UndoTransact info(ResStatus::APPL_LOW);
254 MIL << "*** undo ***" << endl;
255 invokeOnEach ( _pool.begin(), _pool.end(),
256 resfilter::ByTransact( ), // collect transacts from Pool to resolver queue
257 functor::functorRef<bool,PoolItem>(info) );
258 // Regard dependencies of the item weak onl
261 // Additional QueueItems which has to be regarded by the solver
262 _removed_queue_items.clear();
263 _added_queue_items.clear();
268 void Resolver::solverInit()
270 // Solving with the satsolver
271 static bool poolDumped = false;
272 MIL << "-------------- Calling SAT Solver -------------------" << endl;
273 if ( getenv("ZYPP_FULLLOG") ) {
274 Testcase testcase("/var/log/YaST2/autoTestcase");
276 testcase.createTestcase (*this, true, false); // dump pool
279 testcase.createTestcase (*this, false, false); // write control file only
283 _satResolver->setFixsystem ( isVerifyingMode() );
284 _satResolver->setIgnorealreadyrecommended ( ignoreAlreadyRecommended() );
285 _satResolver->setOnlyRequires ( onlyRequires() );
286 _satResolver->setAllowdowngrade (false);
287 _satResolver->setAllowarchchange (false);
288 _satResolver->setAllowvendorchange ( allowVendorChange() );
289 _satResolver->setAllowuninstall ( forceResolve() );
290 _satResolver->setUpdatesystem (false);
291 _satResolver->setNoupdateprovide (false);
292 _satResolver->setDosplitprovides (false);
293 _satResolver->setSolveSrcPackages ( solveSrcPackages() );
294 _satResolver->setCleandepsOnRemove ( cleandepsOnRemove() );
297 // may overwrite some settings
298 _satResolver->setDistupgrade (true);
299 _satResolver->setDistupgrade_removeunsupported (false);
300 _satResolver->setUpdatesystem (true);
301 _satResolver->setAllowdowngrade (true);
302 _satResolver->setAllowarchchange (true);
303 _satResolver->setAllowvendorchange (true);
304 _satResolver->setDosplitprovides (true);
307 // Resetting additional solver information
308 _isInstalledBy.clear();
310 _satifiedByInstalled.clear();
311 _installedSatisfied.clear();
314 bool Resolver::resolvePool()
317 return _satResolver->resolvePool(_extra_requires, _extra_conflicts, _addWeak, _upgradeRepos );
320 bool Resolver::resolveQueue( solver::detail::SolverQueueItemList & queue )
324 // add/remove additional SolverQueueItems
325 for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
326 iter != _removed_queue_items.end(); iter++) {
327 for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
328 if ( (*iterQueue)->cmp(*iter) == 0) {
329 MIL << "remove from queue" << *iter;
330 queue.remove(*iterQueue);
336 for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
337 iter != _added_queue_items.end(); iter++) {
339 for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
340 if ( (*iterQueue)->cmp(*iter) == 0) {
346 MIL << "add to queue" << *iter;
347 queue.push_back(*iter);
351 // The application has to take care to write these solutions back to e.g. selectables in order
352 // give the user a chance for changing these decisions again.
353 _removed_queue_items.clear();
354 _added_queue_items.clear();
356 return _satResolver->resolveQueue(queue, _addWeak);
359 sat::Transaction Resolver::getTransaction()
360 { return _satResolver->getTransaction(); }
362 //----------------------------------------------------------------------------
363 // Getting more information about the solve results
366 void Resolver::collectResolverInfo()
369 && _isInstalledBy.empty()
370 && _installs.empty()) {
373 PoolItemList itemsToInstall = _satResolver->resultItemsToInstall();
375 for (PoolItemList::const_iterator instIter = itemsToInstall.begin();
376 instIter != itemsToInstall.end(); instIter++) {
378 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::REQUIRES).begin(); capIt != (*instIter)->dep (Dep::REQUIRES).end(); ++capIt)
380 sat::WhatProvides possibleProviders(*capIt);
381 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
382 PoolItem provider = ResPool::instance().find( *iter );
384 // searching if this provider will already be installed
386 bool alreadySetForInstallation = false;
387 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
388 while (pos != _isInstalledBy.end()
389 && pos->first == provider
391 alreadySetForInstallation = true;
392 ItemCapKind capKind = pos->second;
393 if (capKind.item == *instIter) found = true;
398 && provider.status().isToBeInstalled()) {
399 if (provider.status().isBySolver()) {
400 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
401 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
403 // no initial installation cause it has been set be e.g. user
404 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, false );
405 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
407 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
408 _installs.insert (make_pair( *instIter, capKindisInstalledBy));
411 if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
412 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, false );
413 _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
415 ItemCapKind installedSatisfied( *instIter, *capIt, Dep::REQUIRES, false );
416 _installedSatisfied.insert (make_pair( provider, installedSatisfied));
421 if (!(_satResolver->onlyRequires())) {
423 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::RECOMMENDS).begin(); capIt != (*instIter)->dep (Dep::RECOMMENDS).end(); ++capIt)
425 sat::WhatProvides possibleProviders(*capIt);
426 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
427 PoolItem provider = ResPool::instance().find( *iter );
429 // searching if this provider will already be installed
431 bool alreadySetForInstallation = false;
432 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
433 while (pos != _isInstalledBy.end()
434 && pos->first == provider
436 alreadySetForInstallation = true;
437 ItemCapKind capKind = pos->second;
438 if (capKind.item == *instIter) found = true;
443 && provider.status().isToBeInstalled()) {
444 if (provider.status().isBySolver()) {
445 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
446 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
448 // no initial installation cause it has been set be e.g. user
449 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, false );
450 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
452 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
453 _installs.insert (make_pair( *instIter, capKindisInstalledBy));
456 if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
457 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, false );
458 _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
460 ItemCapKind installedSatisfied( *instIter, *capIt, Dep::RECOMMENDS, false );
461 _installedSatisfied.insert (make_pair( provider, installedSatisfied));
467 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::SUPPLEMENTS).begin(); capIt != (*instIter)->dep (Dep::SUPPLEMENTS).end(); ++capIt)
469 sat::WhatProvides possibleProviders(*capIt);
470 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
471 PoolItem provider = ResPool::instance().find( *iter );
472 // searching if this item will already be installed
474 bool alreadySetForInstallation = false;
475 ItemCapKindMap::const_iterator pos = _isInstalledBy.find(*instIter);
476 while (pos != _isInstalledBy.end()
477 && pos->first == *instIter
479 alreadySetForInstallation = true;
480 ItemCapKind capKind = pos->second;
481 if (capKind.item == provider) found = true;
486 && instIter->status().isToBeInstalled()) {
487 if (instIter->status().isBySolver()) {
488 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
489 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
491 // no initial installation cause it has been set be e.g. user
492 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, false );
493 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
495 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
496 _installs.insert (make_pair( provider, capKindisInstalledBy));
499 if (instIter->status().staysInstalled()) { // Is already satisfied by an item which is installed
500 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
501 _satifiedByInstalled.insert (make_pair( provider, capKindisInstalledBy));
503 ItemCapKind installedSatisfied( provider, *capIt, Dep::SUPPLEMENTS, false );
504 _installedSatisfied.insert (make_pair( *instIter, installedSatisfied));
514 ItemCapKindList Resolver::isInstalledBy( const PoolItem & item )
517 collectResolverInfo();
519 for (ItemCapKindMap::const_iterator iter = _isInstalledBy.find(item); iter != _isInstalledBy.end();) {
520 ItemCapKind info = iter->second;
521 PoolItem iterItem = iter->first;
522 if (iterItem == item) {
527 iter = _isInstalledBy.end();
533 ItemCapKindList Resolver::installs( const PoolItem & item )
536 collectResolverInfo();
538 for (ItemCapKindMap::const_iterator iter = _installs.find(item); iter != _installs.end();) {
539 ItemCapKind info = iter->second;
540 PoolItem iterItem = iter->first;
541 if (iterItem == item) {
546 iter = _installs.end();
552 ItemCapKindList Resolver::satifiedByInstalled( const PoolItem & item )
555 collectResolverInfo();
557 for (ItemCapKindMap::const_iterator iter = _satifiedByInstalled.find(item); iter != _satifiedByInstalled.end();) {
558 ItemCapKind info = iter->second;
559 PoolItem iterItem = iter->first;
560 if (iterItem == item) {
565 iter = _satifiedByInstalled.end();
571 ItemCapKindList Resolver::installedSatisfied( const PoolItem & item )
574 collectResolverInfo();
576 for (ItemCapKindMap::const_iterator iter = _installedSatisfied.find(item); iter != _installedSatisfied.end();) {
577 ItemCapKind info = iter->second;
578 PoolItem iterItem = iter->first;
579 if (iterItem == item) {
584 iter = _installedSatisfied.end();
591 ///////////////////////////////////////////////////////////////////
592 };// namespace detail
593 /////////////////////////////////////////////////////////////////////
594 /////////////////////////////////////////////////////////////////////
595 };// namespace solver
596 ///////////////////////////////////////////////////////////////////////
597 ///////////////////////////////////////////////////////////////////////
599 /////////////////////////////////////////////////////////////////////////