libzypp  11.13.5
InstallOrder.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* InstallOrder.cc
3  *
4  * Copyright (C) 2005 SUSE Linux Products GmbH
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 
21 // stolen from yast2-packagemanager
22 /*
23  File: InstallOrder.h
24  Purpose: Determine order for installing packages
25  Author: Ludwig Nussel <lnussel@suse.de>
26  Maintainer: Ludwig Nussel <lnussel@suse.de>
27 
28 /-*/
29 
31 #include "zypp/base/LogTools.h"
32 #include "zypp/base/Iterator.h"
33 #include "zypp/base/Algorithm.h"
34 
36 
37 #include "zypp/ResFilters.h"
38 #include "zypp/ResStatus.h"
39 #include "zypp/sat/Pool.h"
40 #include "zypp/sat/WhatObsoletes.h"
41 
43 namespace zypp
44 {
45 
46  namespace solver
47  {
48 
49  namespace detail
50  {
51 
52 using namespace std;
53 using namespace zypp;
54 
55 #define ITEMNAME(item) (item)->name()
56 //-----------------------------------------------------------------------------
57 
58 InstallOrder::InstallOrder( const ResPool & pool, const PoolItemSet & toinstall, const PoolItemSet & installed )
59  : _pool( pool )
60  , _toinstall( toinstall )
61  , _installed( installed )
62  , _dirty (true)
63  , _numrun (0)
64 {
65  _DEBUG("InstallOrder::InstallOrder(_toinstall " << _toinstall.size() << " items, _installed " << _installed.size() << " items)");
66 }
67 
68 
69 //-----------------------------------------------------------------------------
70 
71 void
72 InstallOrder::printAdj (std::ostream& os, bool reversed) const
73 {
74  const Graph& g = (reversed ? _rgraph : _graph);
75  os << "digraph pkgdeps {" << endl;
76  for (Graph::const_iterator gcit = g.begin(); gcit != g.end(); ++gcit)
77  {
78  Nodes::const_iterator niit = _nodes.find(gcit->first);
79  int order = niit->second.order;
80  string name = gcit->first->name();
81  os << "\"" << name << "\"" << "[label=\"" << name << "\\n" << order << "\"";
82  os << "] " << endl;
83  for (PoolItemList::const_iterator scit = gcit->second.begin(); scit != gcit->second.end(); ++scit)
84  {
85  os << "\"" << name << "\" -> \"" << (*scit)->name() << "\"" << endl;
86  }
87  }
88  os << "}" << endl;
89 }
90 
91 
92 //-----------------------------------------------------------------------------
93 
94 // yea, that stuff is suboptimal. there should be a heap sorted by order
97 {
98  PoolItemList newlist;
99 
100  if (_dirty) startrdfs();
101 
102  for (Nodes::iterator it = _nodes.begin(); it != _nodes.end(); ++it)
103  {
104  if (it->second.order == 0
105  && it->second.item) // the default Nodes constructor leaves this empty
106  {
107  XXX << "InstallOrder::computeNextSet found " << ITEMNAME(it->second.item) << endl;
108 
109  newlist.push_back(it->second.item);
110  }
111  }
112 
113  return newlist;
114 }
115 
116 
117 // decrease order of every adjacent node
118 void
120 {
121  _dirty = true;
122 
123  PoolItemList adj = _rgraph[item];
124 
125  XXX << "InstallOrder::setInstalled " << ITEMNAME(item) << endl;
126 
127  // order will be < 0
128  _nodes[item].order--;
129  _installed.insert( item );
130  _toinstall.erase( item );
131 
132  for (PoolItemList::iterator it = adj.begin(); it != adj.end(); ++it)
133  {
134  NodeInfo& info = _nodes[*it];
135  info.order--;
136  if (info.order < 0)
137  {
138  WAR << "order of node " << (*it) << " is < 0" << endl;
139  }
140  }
141 }
142 
143 
144 void
146 {
147  for (PoolItemList::const_iterator it = rl.begin(); it != rl.end(); ++it)
148  {
149  setInstalled(*it);
150  }
151 }
152 
153 //-----------------------------------------------------------------------------
154 
155 bool
156 InstallOrder::doesProvide( const Capability requirement, PoolItem item ) const
157 {
158  Capabilities::const_iterator pend = item->dep( Dep::PROVIDES ).end();
159  for( Capabilities::const_iterator pit = item->dep( Dep::PROVIDES ).begin(); pit != pend; ++pit) {
160  if( pit->matches( requirement ) == CapMatch::yes ) {
161  return item;
162  }
163  }
164  return PoolItem();
165 }
166 
167 
168 PoolItem
169 InstallOrder::findProviderInSet( const Capability requirement, const PoolItemSet & candidates ) const
170 {
171  for( PoolItemSet::const_iterator citer = candidates.begin(); citer != candidates.end(); citer++) {
172  if( doesProvide( requirement, *citer ) ) {
173  return *citer;
174  }
175  }
176 
177  return PoolItem();
178 }
179 
180 //-----------------------------------------------------------------------------
181 
182 
183 void
185 {
186  typedef list<Capability> CapList;
187  CapList requires;
188 
189  XXX << "InstallOrder::rdfsvisit, visiting " << ITEMNAME(item) << endl;
190 
191  NodeInfo& nodeinfo = _nodes[item];
192 
193  nodeinfo.visited = true;
194  nodeinfo.begintime = _rdfstime;
195  _rdfstime++;
196 
197  // items prereq
198  CapabilitySet prq( item->dep(Dep::PREREQUIRES).begin(), item->dep(Dep::PREREQUIRES).end() );
199  // an installed items prereq (in case they are reqired for uninstall scripts)
201  for_( it, sel->installedBegin(), sel->installedEnd() )
202  {
203  Capabilities p( it->satSolvable().prerequires() );
204  prq.insert( p.begin(), p.end() );
205  }
206  // any obsoleted items prereq (in case they are reqired for uninstall scripts)
207  sat::WhatObsoletes obs( item );
208  for_( it, obs.begin(), obs.end() )
209  {
210  Capabilities p( it->prerequires() );
211  prq.insert( p.begin(), p.end() );
212  }
213  // put prerequires first and requires last on list to ensure
214  // that prerequires are processed first
215  for (CapabilitySet::const_iterator it = prq.begin(); it != prq.end(); ++it)
216  {
217  requires.push_back(*it);
218  }
219 
220  // Product requirements are ignored to assert Product gets installed
221  // as early as possible. Some stuff depends on it (e.g. registration).
222  if ( ! isKind<Product>( item.resolvable() ) )
223  {
224  for (Capabilities::const_iterator it = item->dep (Dep::REQUIRES).begin(); it != item->dep (Dep::REQUIRES).end(); ++it)
225  {
226  requires.push_back(*it);
227  }
228  }
229 
230  for (CapList::const_iterator iter = requires.begin(); iter != requires.end(); ++iter)
231  {
232  bool goBack = false;
233  const Capability requirement = *iter;
234  PoolItemList providers;
235 
236  XXX << "check requirement " << requirement << " of " << ITEMNAME(item) << endl;
237  SATResolver satResolver(_pool, sat::Pool::instance().get());
238  PoolItemList tovisit;
239  sat::WhatProvides possibleProviders(requirement);
240 
241  // first, look in _installed
242  for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
243  PoolItem provider = ResPool::instance().find( *iter );
244  if ( provider == item )
245  {
246  goBack = true;
247  break;
248  }
249  if (_installed.find( provider ) != _installed.end()) // and is not installed
250  {
251  XXX << "tovisit " << ITEMNAME(provider) << endl;
252  providers.push_back (provider);
253  }
254  }
255 
256  if ( goBack )
257  continue;
258 
259  // if not found in _installed, look in _toinstall
260 
261  if (providers.empty()) {
262  for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
263  PoolItem provider = ResPool::instance().find( *iter );
264  if ((provider.resolvable() != item.resolvable()) // resolvable could provide its own requirement
265  && (_toinstall.find( provider ) != _toinstall.end())) // and is not to be installed
266  {
267  XXX << "tovisit " << ITEMNAME(provider) << endl;
268  tovisit.push_back (provider);
269  }
270  }
271  }
272 
273  for (PoolItemList::iterator it = tovisit.begin(); it != tovisit.end(); ++it)
274  {
275  const PoolItem must_visit = *it;
276  if (_nodes[must_visit].visited == false)
277  {
278  nodeinfo.order++;
279  _rgraph[must_visit].push_back( item );
280  _graph[item].push_back( must_visit );
281  rdfsvisit( must_visit );
282  }
283  else if (_nodes[must_visit].endtime == 0)
284  {
285  if (must_visit != item)
286  {
287  // log only the 1st occurrence.
288  std::string lstr( ITEMNAME(item) );
289  lstr += " -> ";
290  lstr += ITEMNAME(must_visit);
291  if ( _logset.insert( lstr ).second )
292  {
293  WAR << "** dependency loop: " << lstr << endl;
294  }
295  }
296  }
297  else
298  {
299  // filter multiple depends on same item (cosmetic)
300  PoolItemList & lrg = _rgraph[must_visit];
301  if( find( lrg.begin(), lrg.end(), item) == lrg.end() )
302  {
303  nodeinfo.order++;
304  lrg.push_back( item );
305 
306  PoolItemList & lg = _graph[item];
307  if( find( lg.begin(), lg.end(), must_visit ) == lg.end() )
308  lg.push_back( must_visit );
309  }
310  }
311  }
312  }
313  _topsorted.push_back(item);
314  _nodes[item].endtime = _rdfstime;
315  _rdfstime++;
316 
317  XXX << ITEMNAME(item) << " done" << endl;
318 }
319 
320 
321 void
323 {
324  _nodes.clear();
325  _rgraph.clear();
326  _graph.clear();
327 
328  _rdfstime = 1;
329 
330  _topsorted.clear();
331 
332  _numrun++;
333  XXX << "run #" << _numrun << endl;
334 
335  // initialize all nodes
336  for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
337  {
338  PoolItem item = *it;
339  _nodes[item] = NodeInfo (item);
340  _rgraph[item] = PoolItemList();
341  _graph[item] = PoolItemList();
342  }
343 
344  // visit all nodes
345  for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
346  {
347  const PoolItem item = *it;
348  if (_nodes[item].visited == false)
349  {
350  XXX << "start recursion on " << ITEMNAME(item) << endl;
351  rdfsvisit (item);
352  }
353  }
354 
355  _dirty = false;
356 }
357 
358 
359 //-----------------------------------------------------------------------------
360 
361 const PoolItemList
363 {
364  return _topsorted;
365 }
366 
367 
369  };// namespace detail
372  };// namespace solver
375 };// namespace zypp