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