new call resolveQueue added
[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 #include "zypp/solver/detail/SATResolver.h"
27
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
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(indeterminate)
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 void
260 Resolver::solverInit()
261 {
262     // Solving with the satsolver
263         static bool poolDumped = false;
264         MIL << "-------------- Calling SAT Solver -------------------" << endl;
265         if ( getenv("ZYPP_FULLLOG") ) {
266             Testcase testcase("/var/log/YaST2/autoTestcase");
267             if (!poolDumped) {
268                 testcase.createTestcase (*this, true, false); // dump pool
269                 poolDumped = true;
270             } else {
271                 testcase.createTestcase (*this, false, false); // write control file only
272             }
273         }
274
275         _satResolver->setFixsystem(false);
276         _satResolver->setAllowdowngrade(false);
277         _satResolver->setAllowarchchange(false);
278         _satResolver->setAllowvendorchange(false);
279         _satResolver->setAllowuninstall(false);
280         _satResolver->setUpdatesystem(false);
281         _satResolver->setAllowvirtualconflicts(false);
282         _satResolver->setNoupdateprovide(true);
283         _satResolver->setDosplitprovides(false);
284         
285         if (_upgradeMode) {
286             _satResolver->setAllowdowngrade(true);
287             _satResolver->setAllowarchchange(true);
288             _satResolver->setUpdatesystem(true);
289             _satResolver->setDosplitprovides(true);   
290         }
291
292         if (_forceResolve)
293             _satResolver->setAllowuninstall(true);
294         
295         if (_onlyRequires == indeterminate)
296             _satResolver->setOnlyRequires(ZConfig::instance().solver_onlyRequires());
297         else if (_onlyRequires)
298             _satResolver->setOnlyRequires(true);
299         else
300             _satResolver->setOnlyRequires(false);
301
302         if (_verifying)
303             _satResolver->setFixsystem(true);
304 }
305
306 bool
307 Resolver::resolvePool()
308 {
309     solverInit();
310     return _satResolver->resolvePool(_extra_requires, _extra_conflicts);
311 }
312
313 bool
314 Resolver::resolveQueue(solver::detail::SolverQueueItemList & queue)
315 {
316     solverInit();
317     return _satResolver->resolveQueue(queue);
318 }
319
320
321
322 ///////////////////////////////////////////////////////////////////
323 //
324 //
325 //      METHOD NAME : Resolver::checkUnmaintainedItems
326 //      METHOD TYPE : 
327 //
328 //      DESCRIPTION : Unmaintained packages which does not fit to 
329 //                    the updated system (broken dependencies) will be
330 //                    deleted.
331 //
332 void Resolver::checkUnmaintainedItems () {
333     int solverRuns = 1;
334     MIL << "Checking unmaintained items....." << endl;
335
336     while (!resolvePool() && solverRuns++ < MAXSOLVERRUNS) {
337         ResolverProblemList problemList = problems();
338         ProblemSolutionList solutionList;
339         PoolItemList problemItemList;   
340
341         for (ResolverProblemList::iterator iter = problemList.begin(); iter != problemList.end(); ++iter) {
342             ResolverProblem problem = **iter;
343             DBG << "Problem:" << endl;
344             DBG << problem.description() << endl;
345             DBG << problem.details() << endl;
346
347             ProblemSolutionList solutions = problem.solutions();
348             for (ProblemSolutionList::const_iterator iterSolution = solutions.begin();
349                  iterSolution != solutions.end(); ++iterSolution) {
350                 ProblemSolution_Ptr solution = *iterSolution;
351                 DBG << "   Solution:" << endl;
352                 DBG << "      " << solution->description() << endl;
353                 DBG << "      " << solution->details() << endl;         
354                 solver::detail::CSolutionActionList actionList = solution->actions();
355                 bool fitUnmaintained = false;
356                 PoolItemList deletedItems;
357                 for (CSolutionActionList::const_iterator iterActions = actionList.begin();
358                      iterActions != actionList.end(); ++iterActions) {
359                     TransactionSolutionAction_constPtr transactionAction = dynamic_pointer_cast<const TransactionSolutionAction>(*iterActions);
360                     if (transactionAction &&
361                         transactionAction->action() == REMOVE
362                         && _unmaintained_items.find(transactionAction->item()) != _unmaintained_items.end()) {
363                         // The solution contains unmaintained items ONLY which will be deleted. So take this solution
364                         fitUnmaintained = true;
365                         deletedItems.push_back (transactionAction->item());
366                     } else {
367                         fitUnmaintained = false;
368                     }
369                 }
370                 if (fitUnmaintained) {
371                     MIL << "Problem:" << endl;
372                     MIL << problem.description() << endl;
373                     MIL << problem.details() << endl;
374                     MIL << "Will be solved by removing unmaintained package(s)............" << endl;
375                     MIL << "   Solution:" << endl;
376                     MIL << "      " << solution->description() << endl;
377                     MIL << "      " << solution->details() << endl;                                 
378                     solutionList.push_back (solution);
379                     problemItemList.insert (problemItemList.end(), deletedItems.begin(), deletedItems.end() );
380                     break; // not regarding the other solutions
381                 }
382             }
383         }
384
385         if (!solutionList.empty()) {
386             applySolutions (solutionList);
387             // list of problematic items after doUpgrade() which is show to the user
388             _problem_items.insert (_problem_items.end(), problemItemList.begin(), problemItemList.end());
389             _problem_items.unique();
390         } else {
391             // break cause there is no other solution available by the next run
392             solverRuns = MAXSOLVERRUNS;
393         }
394     }
395 }
396
397
398 ///////////////////////////////////////////////////////////////////
399     };// namespace detail
400     /////////////////////////////////////////////////////////////////////
401     /////////////////////////////////////////////////////////////////////
402   };// namespace solver
403   ///////////////////////////////////////////////////////////////////////
404   ///////////////////////////////////////////////////////////////////////
405 };// namespace zypp
406 /////////////////////////////////////////////////////////////////////////
407