47ae82ffb79edd51c84e4263b34a919bfc69ccec
[platform/upstream/libzypp.git] / zypp / solver / detail / Resolver.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* Resolver.cc
3  *
4  * Copyright (C) 2000-2002 Ximian, Inc.
5  * Copyright (C) 2005 SUSE Linux Products GmbH
6  *
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.
10  *
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.
15  *
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
19  * 02111-1307, USA.
20  */
21 #include <boost/static_assert.hpp>
22
23 #include "zypp/solver/detail/Resolver.h"
24 #include "zypp/solver/detail/Helper.h"
25 #include "zypp/solver/detail/Testcase.h"
26
27 #include "zypp/Capabilities.h"
28 #include "zypp/ZConfig.h"
29 #include "zypp/base/Logger.h"
30 #include "zypp/base/String.h"
31 #include "zypp/base/Gettext.h"
32 #include "zypp/base/Algorithm.h"
33 #include "zypp/ResPool.h"
34 #include "zypp/ResFilters.h"
35 #include "zypp/sat/Pool.h"
36 #include "zypp/sat/Solvable.h"
37 #include "zypp/sat/SATResolver.h"
38
39 #define MAXSOLVERRUNS 5
40
41 /////////////////////////////////////////////////////////////////////////
42 namespace zypp
43 { ///////////////////////////////////////////////////////////////////////
44   ///////////////////////////////////////////////////////////////////////
45   namespace solver
46   { /////////////////////////////////////////////////////////////////////
47     /////////////////////////////////////////////////////////////////////
48     namespace detail
49     { ///////////////////////////////////////////////////////////////////
50
51 using namespace std;
52
53 IMPL_PTR_TYPE(Resolver);
54
55
56 //---------------------------------------------------------------------------
57
58
59 std::ostream &
60 Resolver::dumpOn( std::ostream & os ) const
61 {
62     return os << "<resolver/>";
63 }
64
65
66 //---------------------------------------------------------------------------
67
68 Resolver::Resolver (const ResPool & pool)
69     : _pool(pool)
70     , _satResolver(NULL)
71     , _poolchanged(_pool.serial() )
72     , _forceResolve(false)
73     , _upgradeMode(false)
74     , _verifying(false)
75     , _onlyRequires(DEFAULT)
76
77 {
78     sat::Pool satPool( sat::Pool::instance() );
79     _satResolver = new SATResolver(_pool, satPool.get());
80 }
81
82
83 Resolver::~Resolver()
84 {
85 }
86
87 //---------------------------------------------------------------------------
88
89 ResPool
90 Resolver::pool (void) const
91 {
92     return _pool;
93 }
94
95 void
96 Resolver::reset (bool keepExtras )
97 {
98     _verifying = false;    
99
100     if (!keepExtras) {
101       _extra_requires.clear();
102       _extra_conflicts.clear();
103     }
104 }
105
106 bool
107 Resolver::doUpdate()
108 {
109     if (_satResolver) {
110         return _satResolver->doUpdate();
111     } else {
112         ERR << "SAT solver has not been initialized." << endl;
113         return false;
114     }
115 }
116
117 void
118 Resolver::addExtraRequire (const Capability & capability)
119 {
120     _extra_requires.insert (capability);
121 }
122
123 void
124 Resolver::removeExtraRequire (const Capability & capability)
125 {
126     _extra_requires.erase (capability);
127 }
128
129 void
130 Resolver::addExtraConflict (const Capability & capability)
131 {
132     _extra_conflicts.insert (capability);
133 }
134
135 void
136 Resolver::removeExtraConflict (const Capability & capability)
137 {
138     _extra_conflicts.erase (capability);
139 }
140
141 void
142 Resolver::addIgnoreConflict (const PoolItem item,
143                    const Capability & capability)
144 {
145     _ignoreConflicts.insert(make_pair(item, capability));
146 }
147
148 void
149 Resolver::addIgnoreRequires (const PoolItem item,
150                              const Capability & capability)
151 {
152     _ignoreRequires.insert(make_pair(item, capability));
153 }
154
155 void
156 Resolver::addIgnoreObsoletes (const PoolItem item,
157                               const Capability & capability)
158 {
159     _ignoreObsoletes.insert(make_pair(item, capability));
160 }
161
162 void
163 Resolver::addIgnoreInstalledItem (const PoolItem item)
164 {
165     _ignoreInstalledItem.push_back (item);
166 }
167
168 void
169 Resolver::addIgnoreArchitectureItem (const PoolItem item)
170 {
171     _ignoreArchitectureItem.push_back (item);
172 }
173
174 void
175 Resolver::addIgnoreVendorItem (const PoolItem item)
176 {
177     _ignoreVendorItem.push_back (item);
178 }
179
180 //---------------------------------------------------------------------------
181
182 struct UndoTransact : public resfilter::PoolItemFilterFunctor
183 {
184     ResStatus::TransactByValue resStatus;
185     UndoTransact ( const ResStatus::TransactByValue &status)
186         :resStatus(status)
187     { }
188
189     bool operator()( PoolItem item )            // only transacts() items go here
190     {
191         item.status().resetTransact( resStatus );// clear any solver/establish transactions
192         return true;
193     }
194 };
195
196
197 struct DoTransact : public resfilter::PoolItemFilterFunctor
198 {
199     ResStatus::TransactByValue resStatus;
200     DoTransact ( const ResStatus::TransactByValue &status)
201         :resStatus(status)
202     { }
203
204     bool operator()( PoolItem item )            // only transacts() items go here
205     {
206         item.status().setTransact( true, resStatus );
207         return true;
208     }
209 };
210
211
212 bool
213 Resolver::verifySystem ()
214 {
215     UndoTransact resetting (ResStatus::APPL_HIGH);
216
217     _DEBUG ("Resolver::verifySystem() ");
218     
219     _verifying = true;    
220
221     invokeOnEach ( _pool.begin(), _pool.end(),
222                    resfilter::ByTransact( ),                    // Resetting all transcations
223                    functor::functorRef<bool,PoolItem>(resetting) );
224
225     return resolvePool();
226 }
227
228
229 //----------------------------------------------------------------------------
230 // undo
231
232 void
233 Resolver::undo(void)
234 {
235     UndoTransact info(ResStatus::APPL_LOW);
236     MIL << "*** undo ***" << endl;
237     invokeOnEach ( _pool.begin(), _pool.end(),
238                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
239                    functor::functorRef<bool,PoolItem>(info) );
240     // These conflict should be ignored of the concering item
241     _ignoreConflicts.clear();
242     // These requires should be ignored of the concering item
243     _ignoreRequires.clear();
244     // These obsoletes should be ignored of the concering item
245     _ignoreObsoletes.clear();
246     // Ignore architecture of the item
247     _ignoreArchitecture.clear();
248     // Ignore the status "installed" of the item
249     _ignoreInstalledItem.clear();
250     // Ignore the architecture of the item
251     _ignoreArchitectureItem.clear();
252     // Ignore the vendor of the item
253     _ignoreVendorItem.clear();
254
255
256     return;
257 }
258
259
260 bool
261 Resolver::resolvePool()
262 {
263
264     // Solving with the satsolver
265         static bool poolDumped = false;
266         MIL << "-------------- Calling SAT Solver -------------------" << endl;
267         if ( getenv("ZYPP_FULLLOG") ) {
268             Testcase testcase("/var/log/YaST2/autoTestcase");
269             if (!poolDumped) {
270                 testcase.createTestcase (*this, true, false); // dump pool
271                 poolDumped = true;
272             } else {
273                 testcase.createTestcase (*this, false, false); // write control file only
274             }
275         }
276 #if 0
277         MIL << "------SAT-Pool------" << endl;
278         for (sat::Pool::SolvableIterator i = satPool.solvablesBegin();
279              i != satPool.solvablesEnd(); i++ ) {
280             MIL << *i << " ID: " << i->id() << endl;
281         }
282         MIL << "------SAT-Pool end------" << endl;
283 #endif
284         _satResolver->setFixsystem(false);
285         _satResolver->setAllowdowngrade(false);
286         _satResolver->setAllowarchchange(false);
287         _satResolver->setAllowvendorchange(false);
288         _satResolver->setAllowuninstall(false);
289         _satResolver->setUpdatesystem(false);
290         _satResolver->setAllowvirtualconflicts(false);
291         _satResolver->setNoupdateprovide(true);
292         _satResolver->setDosplitprovides(false);
293         
294         if (_upgradeMode) {
295             _satResolver->setAllowdowngrade(true);
296             _satResolver->setAllowarchchange(true);
297             _satResolver->setUpdatesystem(true);
298             _satResolver->setDosplitprovides(true);   
299         }
300
301         if (_forceResolve)
302             _satResolver->setAllowuninstall(true);
303         
304         switch (_onlyRequires) {
305             case DEFAULT:
306                 _satResolver->setOnlyRequires(ZConfig::instance().solver_onlyRequires());
307             case TRUE:
308                 _satResolver->setOnlyRequires(true);
309             case FALSE:
310                 _satResolver->setOnlyRequires(false);
311         }
312
313         if (_verifying)
314             _satResolver->setFixsystem(true);
315         
316         return _satResolver->resolvePool(_extra_requires, _extra_conflicts);
317 }
318
319
320 ///////////////////////////////////////////////////////////////////
321 //
322 //
323 //      METHOD NAME : Resolver::checkUnmaintainedItems
324 //      METHOD TYPE : 
325 //
326 //      DESCRIPTION : Unmaintained packages which does not fit to 
327 //                    the updated system (broken dependencies) will be
328 //                    deleted.
329 //
330 void Resolver::checkUnmaintainedItems () {
331     int solverRuns = 1;
332     MIL << "Checking unmaintained items....." << endl;
333
334     while (!resolvePool() && solverRuns++ < MAXSOLVERRUNS) {
335         ResolverProblemList problemList = problems();
336         ProblemSolutionList solutionList;
337         PoolItemList problemItemList;   
338
339         for (ResolverProblemList::iterator iter = problemList.begin(); iter != problemList.end(); ++iter) {
340             ResolverProblem problem = **iter;
341             DBG << "Problem:" << endl;
342             DBG << problem.description() << endl;
343             DBG << problem.details() << endl;
344
345             ProblemSolutionList solutions = problem.solutions();
346             for (ProblemSolutionList::const_iterator iterSolution = solutions.begin();
347                  iterSolution != solutions.end(); ++iterSolution) {
348                 ProblemSolution_Ptr solution = *iterSolution;
349                 DBG << "   Solution:" << endl;
350                 DBG << "      " << solution->description() << endl;
351                 DBG << "      " << solution->details() << endl;         
352                 solver::detail::CSolutionActionList actionList = solution->actions();
353                 bool fitUnmaintained = false;
354                 PoolItemList deletedItems;
355                 for (CSolutionActionList::const_iterator iterActions = actionList.begin();
356                      iterActions != actionList.end(); ++iterActions) {
357                     TransactionSolutionAction_constPtr transactionAction = dynamic_pointer_cast<const TransactionSolutionAction>(*iterActions);
358                     if (transactionAction &&
359                         transactionAction->action() == REMOVE
360                         && _unmaintained_items.find(transactionAction->item()) != _unmaintained_items.end()) {
361                         // The solution contains unmaintained items ONLY which will be deleted. So take this solution
362                         fitUnmaintained = true;
363                         deletedItems.push_back (transactionAction->item());
364                     } else {
365                         fitUnmaintained = false;
366                     }
367                 }
368                 if (fitUnmaintained) {
369                     MIL << "Problem:" << endl;
370                     MIL << problem.description() << endl;
371                     MIL << problem.details() << endl;
372                     MIL << "Will be solved by removing unmaintained package(s)............" << endl;
373                     MIL << "   Solution:" << endl;
374                     MIL << "      " << solution->description() << endl;
375                     MIL << "      " << solution->details() << endl;                                 
376                     solutionList.push_back (solution);
377                     problemItemList.insert (problemItemList.end(), deletedItems.begin(), deletedItems.end() );
378                     break; // not regarding the other solutions
379                 }
380             }
381         }
382
383         if (!solutionList.empty()) {
384             applySolutions (solutionList);
385             // list of problematic items after doUpgrade() which is show to the user
386             _problem_items.insert (_problem_items.end(), problemItemList.begin(), problemItemList.end());
387             _problem_items.unique();
388         } else {
389             // break cause there is no other solution available by the next run
390             solverRuns = MAXSOLVERRUNS;
391         }
392     }
393 }
394
395
396 ///////////////////////////////////////////////////////////////////
397     };// namespace detail
398     /////////////////////////////////////////////////////////////////////
399     /////////////////////////////////////////////////////////////////////
400   };// namespace solver
401   ///////////////////////////////////////////////////////////////////////
402   ///////////////////////////////////////////////////////////////////////
403 };// namespace zypp
404 /////////////////////////////////////////////////////////////////////////
405