1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * Copyright (C) 2005 SUSE Linux Products GmbH
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.
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.
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
21 // stolen from yast2-packagemanager
24 Purpose: Determine order for installing packages
25 Author: Ludwig Nussel <lnussel@suse.de>
26 Maintainer: Ludwig Nussel <lnussel@suse.de>
30 #include "zypp/solver/detail/InstallOrder.h"
31 #include "zypp/base/LogTools.h"
32 #include "zypp/base/Iterator.h"
33 #include "zypp/base/Algorithm.h"
35 #include "zypp/solver/detail/SATResolver.h"
37 #include "zypp/ResFilters.h"
38 #include "zypp/ResStatus.h"
39 #include "zypp/NameKindProxy.h"
40 #include "zypp/sat/Pool.h"
42 /////////////////////////////////////////////////////////////////////////
44 { ///////////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////////
47 { /////////////////////////////////////////////////////////////////////
48 /////////////////////////////////////////////////////////////////////
50 { ///////////////////////////////////////////////////////////////////
55 #define ITEMNAME(item) (item)->name()
56 //-----------------------------------------------------------------------------
58 InstallOrder::InstallOrder( const ResPool & pool, const PoolItemSet & toinstall, const PoolItemSet & installed )
60 , _toinstall( toinstall )
61 , _installed( installed )
65 _DEBUG("InstallOrder::InstallOrder(_toinstall " << _toinstall.size() << " items, _installed " << _installed.size() << " items)");
69 //-----------------------------------------------------------------------------
72 InstallOrder::printAdj (std::ostream& os, bool reversed) const
74 const Graph& g = (reversed ? _rgraph : _graph);
75 os << "digraph pkgdeps {" << endl;
76 for (Graph::const_iterator gcit = g.begin(); gcit != g.end(); ++gcit)
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 << "\"";
83 for (PoolItemList::const_iterator scit = gcit->second.begin(); scit != gcit->second.end(); ++scit)
85 os << "\"" << name << "\" -> \"" << (*scit)->name() << "\"" << endl;
92 //-----------------------------------------------------------------------------
94 // yea, that stuff is suboptimal. there should be a heap sorted by order
96 InstallOrder::computeNextSet()
100 if (_dirty) startrdfs();
102 for (Nodes::iterator it = _nodes.begin(); it != _nodes.end(); ++it)
104 if (it->second.order == 0
105 && it->second.item) // the default Nodes constructor leaves this empty
107 XXX << "InstallOrder::computeNextSet found " << ITEMNAME(it->second.item) << endl;
109 newlist.push_back(it->second.item);
117 // decrease order of every adjacent node
119 InstallOrder::setInstalled(PoolItem item )
123 PoolItemList adj = _rgraph[item];
125 XXX << "InstallOrder::setInstalled " << ITEMNAME(item) << endl;
128 _nodes[item].order--;
129 _installed.insert( item );
130 _toinstall.erase( item );
132 for (PoolItemList::iterator it = adj.begin(); it != adj.end(); ++it)
134 NodeInfo& info = _nodes[*it];
138 WAR << "order of node " << (*it) << " is < 0" << endl;
145 InstallOrder::setInstalled( const PoolItemList & rl )
147 for (PoolItemList::const_iterator it = rl.begin(); it != rl.end(); ++it)
153 //-----------------------------------------------------------------------------
156 InstallOrder::doesProvide( const Capability requirement, PoolItem item ) const
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 ) {
169 InstallOrder::findProviderInSet( const Capability requirement, const PoolItemSet & candidates ) const
171 for( PoolItemSet::const_iterator citer = candidates.begin(); citer != candidates.end(); citer++) {
172 if( doesProvide( requirement, *citer ) ) {
180 //-----------------------------------------------------------------------------
184 InstallOrder::rdfsvisit (const PoolItem item)
186 typedef list<Capability> CapList;
189 XXX << "InstallOrder::rdfsvisit, visiting " << ITEMNAME(item) << endl;
191 NodeInfo& nodeinfo = _nodes[item];
193 nodeinfo.visited = true;
194 nodeinfo.begintime = _rdfstime;
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)
200 NameKindProxy nkp( _pool, item->name(), item->kind() );
201 if ( ! nkp.installedEmpty() )
203 prq.insert( (*nkp.installedBegin())->dep(Dep::PREREQUIRES).begin(),
204 (*nkp.installedBegin())->dep(Dep::PREREQUIRES).end() );
206 // put prerequires first and requires last on list to ensure
207 // that prerequires are processed first
208 for (CapabilitySet::const_iterator it = prq.begin(); it != prq.end(); ++it)
210 requires.push_back(*it);
213 // Product requirements are ignored to assert Product gets installed
214 // as early as possible. Some stuff depends on it (e.g. registration).
215 if ( ! isKind<Product>( item.resolvable() ) )
217 for (Capabilities::const_iterator it = item->dep (Dep::REQUIRES).begin(); it != item->dep (Dep::REQUIRES).end(); ++it)
219 requires.push_back(*it);
223 for (CapList::const_iterator iter = requires.begin(); iter != requires.end(); ++iter)
225 const Capability requirement = *iter;
226 PoolItemList providers;
228 XXX << "check requirement " << requirement << " of " << ITEMNAME(item) << endl;
229 SATResolver satResolver(_pool, sat::Pool::instance().get());
230 PoolItemList tovisit;
231 sat::WhatProvides possibleProviders(requirement);
233 // first, look in _installed
234 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
235 PoolItem provider = ResPool::instance().find( *iter );
236 if (provider != item // resolvable could provide its own requirement
237 && (_installed.find( provider ) != _installed.end())) // and is not installed
239 XXX << "tovisit " << ITEMNAME(provider) << endl;
240 providers.push_back (provider);
244 // if not found in _installed, look in _toinstall
246 if (providers.empty()) {
247 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
248 PoolItem provider = ResPool::instance().find( *iter );
249 if ((provider.resolvable() != item.resolvable()) // resolvable could provide its own requirement
250 && (_toinstall.find( provider ) != _toinstall.end())) // and is not to be installed
252 XXX << "tovisit " << ITEMNAME(provider) << endl;
253 tovisit.push_back (provider);
258 for (PoolItemList::iterator it = tovisit.begin(); it != tovisit.end(); ++it)
260 const PoolItem must_visit = *it;
261 if (_nodes[must_visit].visited == false)
264 _rgraph[must_visit].push_back( item );
265 _graph[item].push_back( must_visit );
266 rdfsvisit( must_visit );
268 else if (_nodes[must_visit].endtime == 0)
270 if (must_visit != item)
272 // log only the 1st occurrence.
273 std::string lstr( ITEMNAME(item) );
275 lstr += ITEMNAME(must_visit);
276 if ( _logset.insert( lstr ).second )
278 WAR << "** dependency loop: " << lstr << endl;
284 // filter multiple depends on same item (cosmetic)
285 PoolItemList & lrg = _rgraph[must_visit];
286 if( find( lrg.begin(), lrg.end(), item) == lrg.end() )
289 lrg.push_back( item );
291 PoolItemList & lg = _graph[item];
292 if( find( lg.begin(), lg.end(), must_visit ) == lg.end() )
293 lg.push_back( must_visit );
298 _topsorted.push_back(item);
299 _nodes[item].endtime = _rdfstime;
302 XXX << ITEMNAME(item) << " done" << endl;
307 InstallOrder::startrdfs()
318 XXX << "run #" << _numrun << endl;
320 // initialize all nodes
321 for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
324 _nodes[item] = NodeInfo (item);
325 _rgraph[item] = PoolItemList();
326 _graph[item] = PoolItemList();
330 for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
332 const PoolItem item = *it;
333 if (_nodes[item].visited == false)
335 XXX << "start recursion on " << ITEMNAME(item) << endl;
344 //-----------------------------------------------------------------------------
347 InstallOrder::getTopSorted() const
353 ///////////////////////////////////////////////////////////////////
354 };// namespace detail
355 /////////////////////////////////////////////////////////////////////
356 /////////////////////////////////////////////////////////////////////
357 };// namespace solver
358 ///////////////////////////////////////////////////////////////////////
359 ///////////////////////////////////////////////////////////////////////
361 /////////////////////////////////////////////////////////////////////////