cleanup in return values of doUpgrade and doUpdate
[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 void
107 Resolver::doUpdate()
108 {
109     return _satResolver->doUpdate();
110 }
111
112 void
113 Resolver::addExtraRequire (const Capability & capability)
114 {
115     _extra_requires.insert (capability);
116 }
117
118 void
119 Resolver::removeExtraRequire (const Capability & capability)
120 {
121     _extra_requires.erase (capability);
122 }
123
124 void
125 Resolver::addExtraConflict (const Capability & capability)
126 {
127     _extra_conflicts.insert (capability);
128 }
129
130 void
131 Resolver::removeExtraConflict (const Capability & capability)
132 {
133     _extra_conflicts.erase (capability);
134 }
135
136 void
137 Resolver::addWeak (const PoolItem item)
138 {
139     _addWeak.push_back (item);
140 }
141
142 //---------------------------------------------------------------------------
143
144 struct UndoTransact : public resfilter::PoolItemFilterFunctor
145 {
146     ResStatus::TransactByValue resStatus;
147     UndoTransact ( const ResStatus::TransactByValue &status)
148         :resStatus(status)
149     { }
150
151     bool operator()( PoolItem item )            // only transacts() items go here
152     {
153         item.status().resetTransact( resStatus );// clear any solver/establish transactions
154         return true;
155     }
156 };
157
158
159 struct DoTransact : public resfilter::PoolItemFilterFunctor
160 {
161     ResStatus::TransactByValue resStatus;
162     DoTransact ( const ResStatus::TransactByValue &status)
163         :resStatus(status)
164     { }
165
166     bool operator()( PoolItem item )            // only transacts() items go here
167     {
168         item.status().setTransact( true, resStatus );
169         return true;
170     }
171 };
172
173
174 bool
175 Resolver::verifySystem ()
176 {
177     UndoTransact resetting (ResStatus::APPL_HIGH);
178
179     _DEBUG ("Resolver::verifySystem() ");
180     
181     _verifying = true;    
182
183     invokeOnEach ( _pool.begin(), _pool.end(),
184                    resfilter::ByTransact( ),                    // Resetting all transcations
185                    functor::functorRef<bool,PoolItem>(resetting) );
186
187     return resolvePool();
188 }
189
190
191 //----------------------------------------------------------------------------
192 // undo
193
194 void
195 Resolver::undo(void)
196 {
197     UndoTransact info(ResStatus::APPL_LOW);
198     MIL << "*** undo ***" << endl;
199     invokeOnEach ( _pool.begin(), _pool.end(),
200                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
201                    functor::functorRef<bool,PoolItem>(info) );
202     //  Regard dependencies of the item weak onl
203     _addWeak.clear();
204
205     return;
206 }
207
208 void
209 Resolver::solverInit()
210 {
211     // Solving with the satsolver
212         static bool poolDumped = false;
213         MIL << "-------------- Calling SAT Solver -------------------" << endl;
214         if ( getenv("ZYPP_FULLLOG") ) {
215             Testcase testcase("/var/log/YaST2/autoTestcase");
216             if (!poolDumped) {
217                 testcase.createTestcase (*this, true, false); // dump pool
218                 poolDumped = true;
219             } else {
220                 testcase.createTestcase (*this, false, false); // write control file only
221             }
222         }
223
224         _satResolver->setFixsystem(false);
225         _satResolver->setAllowdowngrade(false);
226         _satResolver->setAllowarchchange(false);
227         _satResolver->setAllowvendorchange(false);
228         _satResolver->setAllowuninstall(false);
229         _satResolver->setUpdatesystem(false);
230         _satResolver->setAllowvirtualconflicts(false);
231         _satResolver->setNoupdateprovide(true);
232         _satResolver->setDosplitprovides(false);
233         
234         if (_upgradeMode) {
235             _satResolver->setAllowdowngrade(true);
236             _satResolver->setUpdatesystem(true);
237             _satResolver->setDosplitprovides(true);   
238         }
239
240         if (_forceResolve)
241             _satResolver->setAllowuninstall(true);
242         
243         if (_onlyRequires == indeterminate)
244             _satResolver->setOnlyRequires(ZConfig::instance().solver_onlyRequires());
245         else if (_onlyRequires)
246             _satResolver->setOnlyRequires(true);
247         else
248             _satResolver->setOnlyRequires(false);
249
250         if (_verifying)
251             _satResolver->setFixsystem(true);
252 }
253
254 bool
255 Resolver::resolvePool()
256 {
257     solverInit();
258     return _satResolver->resolvePool(_extra_requires, _extra_conflicts, _addWeak);
259 }
260
261 bool
262 Resolver::resolveQueue(solver::detail::SolverQueueItemList & queue)
263 {
264     solverInit();
265     return _satResolver->resolveQueue(queue, _addWeak);
266 }
267
268
269
270 ///////////////////////////////////////////////////////////////////
271 //
272 //
273 //      METHOD NAME : Resolver::checkUnmaintainedItems
274 //      METHOD TYPE : 
275 //
276 //      DESCRIPTION : Unmaintained packages which does not fit to 
277 //                    the updated system (broken dependencies) will be
278 //                    deleted.
279 //                    returns true if solving was successful
280 //
281 bool Resolver::checkUnmaintainedItems () {
282     int solverRuns = 1;
283     bool solverRet = resolvePool();
284     MIL << "Checking unmaintained items....." << endl;
285
286     while (!solverRet && solverRuns++ < MAXSOLVERRUNS) {
287         ResolverProblemList problemList = problems();
288         ProblemSolutionList solutionList;
289         PoolItemList problemItemList;   
290
291         for (ResolverProblemList::iterator iter = problemList.begin(); iter != problemList.end(); ++iter) {
292             ResolverProblem problem = **iter;
293             DBG << "Problem:" << endl;
294             DBG << problem.description() << endl;
295             DBG << problem.details() << endl;
296
297             ProblemSolutionList solutions = problem.solutions();
298             for (ProblemSolutionList::const_iterator iterSolution = solutions.begin();
299                  iterSolution != solutions.end(); ++iterSolution) {
300                 ProblemSolution_Ptr solution = *iterSolution;
301                 DBG << "   Solution:" << endl;
302                 DBG << "      " << solution->description() << endl;
303                 DBG << "      " << solution->details() << endl;         
304                 solver::detail::CSolutionActionList actionList = solution->actions();
305                 bool fitUnmaintained = false;
306                 PoolItemList deletedItems;
307                 for (CSolutionActionList::const_iterator iterActions = actionList.begin();
308                      iterActions != actionList.end(); ++iterActions) {
309                     TransactionSolutionAction_constPtr transactionAction = dynamic_pointer_cast<const TransactionSolutionAction>(*iterActions);
310                     if (transactionAction &&
311                         transactionAction->action() == REMOVE
312                         && _unmaintained_items.find(transactionAction->item()) != _unmaintained_items.end()) {
313                         // The solution contains unmaintained items ONLY which will be deleted. So take this solution
314                         fitUnmaintained = true;
315                         deletedItems.push_back (transactionAction->item());
316                     } else {
317                         fitUnmaintained = false;
318                     }
319                 }
320                 if (fitUnmaintained) {
321                     MIL << "Problem:" << endl;
322                     MIL << problem.description() << endl;
323                     MIL << problem.details() << endl;
324                     MIL << "Will be solved by removing unmaintained package(s)............" << endl;
325                     MIL << "   Solution:" << endl;
326                     MIL << "      " << solution->description() << endl;
327                     MIL << "      " << solution->details() << endl;                                 
328                     solutionList.push_back (solution);
329                     problemItemList.insert (problemItemList.end(), deletedItems.begin(), deletedItems.end() );
330                     break; // not regarding the other solutions
331                 }
332             }
333         }
334
335         if (!solutionList.empty()) {
336             applySolutions (solutionList);
337             // list of problematic items after doUpgrade() which is show to the user
338             _problem_items.insert (_problem_items.end(), problemItemList.begin(), problemItemList.end());
339             _problem_items.unique();
340         } else {
341             // break cause there is no other solution available by the next run
342             solverRuns = MAXSOLVERRUNS;
343         }
344         // next try
345         solverRet = resolvePool();      
346     }
347 }
348
349
350 ///////////////////////////////////////////////////////////////////
351     };// namespace detail
352     /////////////////////////////////////////////////////////////////////
353     /////////////////////////////////////////////////////////////////////
354   };// namespace solver
355   ///////////////////////////////////////////////////////////////////////
356   ///////////////////////////////////////////////////////////////////////
357 };// namespace zypp
358 /////////////////////////////////////////////////////////////////////////
359