00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "zypp/solver/detail/InstallOrder.h"
00031 #include "zypp/base/LogTools.h"
00032 #include "zypp/base/Iterator.h"
00033 #include "zypp/base/Algorithm.h"
00034
00035 #include "zypp/ResFilters.h"
00036 #include "zypp/ResStatus.h"
00037 #include "zypp/CapAndItem.h"
00038 #include "zypp/NameKindProxy.h"
00039
00041 namespace zypp
00042 {
00043
00044 namespace solver
00045 {
00046
00047 namespace detail
00048 {
00049
00050 using namespace std;
00051 using namespace zypp;
00052
00053 #define ITEMNAME(item) (item)->name()
00054
00055
00056 InstallOrder::InstallOrder( const ResPool & pool, const PoolItemSet & toinstall, const PoolItemSet & installed )
00057 : _pool( pool )
00058 , _toinstall( toinstall )
00059 , _installed( installed )
00060 , _dirty (true)
00061 , _numrun (0)
00062 {
00063 _DEBUG("InstallOrder::InstallOrder(_toinstall " << _toinstall.size() << " items, _installed " << _installed.size() << " items)");
00064 }
00065
00066
00067
00068
00069 const void
00070 InstallOrder::printAdj (std::ostream& os, bool reversed) const
00071 {
00072 const Graph& g = (reversed ? _rgraph : _graph);
00073 os << "digraph pkgdeps {" << endl;
00074 for (Graph::const_iterator gcit = g.begin(); gcit != g.end(); ++gcit)
00075 {
00076 Nodes::const_iterator niit = _nodes.find(gcit->first);
00077 int order = niit->second.order;
00078 string name = gcit->first->name();
00079 os << "\"" << name << "\"" << "[label=\"" << name << "\\n" << order << "\"";
00080 os << "] " << endl;
00081 for (PoolItemList::const_iterator scit = gcit->second.begin(); scit != gcit->second.end(); ++scit)
00082 {
00083 os << "\"" << name << "\" -> \"" << (*scit)->name() << "\"" << endl;
00084 }
00085 }
00086 os << "}" << endl;
00087 }
00088
00089
00090
00091
00092
00093 PoolItemList
00094 InstallOrder::computeNextSet()
00095 {
00096 PoolItemList newlist;
00097
00098 if (_dirty) startrdfs();
00099
00100 for (Nodes::iterator it = _nodes.begin(); it != _nodes.end(); ++it)
00101 {
00102 if (it->second.order == 0
00103 && it->second.item)
00104 {
00105 if (isKind<SystemResObject>( it->second.item.resolvable() ))
00106 continue;
00107
00108 XXX << "InstallOrder::computeNextSet found " << ITEMNAME(it->second.item) << endl;
00109
00110 newlist.push_back(it->second.item);
00111 }
00112 }
00113
00114 return newlist;
00115 }
00116
00117
00118
00119 void
00120 InstallOrder::setInstalled(PoolItem_Ref item )
00121 {
00122 _dirty = true;
00123
00124 PoolItemList adj = _rgraph[item];
00125
00126 XXX << "InstallOrder::setInstalled " << ITEMNAME(item) << endl;
00127
00128
00129 _nodes[item].order--;
00130 _installed.insert( item );
00131 _toinstall.erase( item );
00132
00133 for (PoolItemList::iterator it = adj.begin(); it != adj.end(); ++it)
00134 {
00135 NodeInfo& info = _nodes[*it];
00136 info.order--;
00137 if (info.order < 0)
00138 {
00139 WAR << "order of node " << (*it) << " is < 0" << endl;
00140 }
00141 }
00142 }
00143
00144
00145 void
00146 InstallOrder::setInstalled( const PoolItemList & rl )
00147 {
00148 for (PoolItemList::const_iterator it = rl.begin(); it != rl.end(); ++it)
00149 {
00150 setInstalled(*it);
00151 }
00152 }
00153
00154
00155
00156 bool
00157 InstallOrder::doesProvide( const Capability requirement, PoolItem_Ref item ) const
00158 {
00159 CapSet::const_iterator pend = item->dep( Dep::PROVIDES ).end();
00160 for( CapSet::const_iterator pit = item->dep( Dep::PROVIDES ).begin(); pit != pend; ++pit) {
00161 if( pit->matches( requirement ) == CapMatch::yes ) {
00162 return item;
00163 }
00164 }
00165 return PoolItem_Ref();
00166 }
00167
00168
00169 PoolItem_Ref
00170 InstallOrder::findProviderInSet( const Capability requirement, const PoolItemSet & candidates ) const
00171 {
00172 for( PoolItemSet::const_iterator citer = candidates.begin(); citer != candidates.end(); citer++) {
00173 if( doesProvide( requirement, *citer ) ) {
00174 return *citer;
00175 }
00176 }
00177
00178 return PoolItem_Ref();
00179 }
00180
00181 struct CollectProviders
00182 {
00183 const PoolItem_Ref requestor;
00184 PoolItemList result;
00185 const PoolItemSet & limitto;
00186
00187 CollectProviders (const PoolItem_Ref pi, const PoolItemSet & limit)
00188 : requestor (pi)
00189 , limitto (limit)
00190 { }
00191
00192
00193 bool operator()( const CapAndItem & c_and_i )
00194 {
00195
00196
00197
00198
00199 XXX << "info(" << c_and_i.item <<")"<< endl;
00200 if ((c_and_i.item.resolvable() != requestor.resolvable())
00201 && (limitto.find( c_and_i.item ) != limitto.end()))
00202 {
00203 XXX << "tovisit " << ITEMNAME(c_and_i.item) << endl;
00204 result.push_back (c_and_i.item);
00205 }
00206
00207 return true;
00208 }
00209
00210 };
00211
00212
00213
00214
00215 void
00216 InstallOrder::rdfsvisit (const PoolItem_Ref item)
00217 {
00218 typedef list<Capability> CapList;
00219 CapList requires;
00220
00221 XXX << "InstallOrder::rdfsvisit, visiting " << ITEMNAME(item) << endl;
00222
00223 NodeInfo& nodeinfo = _nodes[item];
00224
00225 nodeinfo.visited = true;
00226 nodeinfo.begintime = _rdfstime;
00227 _rdfstime++;
00228
00229
00230 CapSet prq( item->dep(Dep::PREREQUIRES) );
00231
00232 NameKindProxy nkp( _pool, item->name(), item->kind() );
00233 if ( ! nkp.installedEmpty() )
00234 {
00235 prq.insert( (*nkp.installedBegin())->dep(Dep::PREREQUIRES).begin(),
00236 (*nkp.installedBegin())->dep(Dep::PREREQUIRES).end() );
00237 }
00238
00239
00240 for (CapSet::const_iterator it = prq.begin(); it != prq.end(); ++it)
00241 {
00242 requires.push_back(*it);
00243 }
00244
00245
00246
00247 if ( ! isKind<Product>( item.resolvable() ) )
00248 {
00249 for (CapSet::const_iterator it = item->dep (Dep::REQUIRES).begin(); it != item->dep (Dep::REQUIRES).end(); ++it)
00250 {
00251 requires.push_back(*it);
00252 }
00253 }
00254
00255 for (CapList::const_iterator iter = requires.begin(); iter != requires.end(); ++iter)
00256 {
00257 const Capability requirement = *iter;
00258 XXX << "check requirement " << requirement << " of " << ITEMNAME(item) << endl;
00259 PoolItemList tovisit;
00260
00261
00262 Dep dep (Dep::PROVIDES);
00263
00264
00265 CollectProviders info ( item, _installed );
00266
00267 invokeOnEach( _pool.byCapabilityIndexBegin( requirement.index(), dep ),
00268 _pool.byCapabilityIndexEnd( requirement.index(), dep ),
00269 resfilter::ByCapMatch( requirement ),
00270 functor::functorRef<bool,CapAndItem>(info) );
00271
00272
00273
00274 if (info.result.empty()) {
00275 CollectProviders info1 ( item, _toinstall );
00276
00277 invokeOnEach( _pool.byCapabilityIndexBegin( requirement.index(), dep ),
00278 _pool.byCapabilityIndexEnd( requirement.index(), dep ),
00279 resfilter::ByCapMatch( requirement ),
00280 functor::functorRef<bool,CapAndItem>(info1) );
00281
00282 tovisit = info1.result;
00283 }
00284
00285 for (PoolItemList::iterator it = tovisit.begin(); it != tovisit.end(); ++it)
00286 {
00287 const PoolItem_Ref must_visit = *it;
00288 if (_nodes[must_visit].visited == false)
00289 {
00290 nodeinfo.order++;
00291 _rgraph[must_visit].push_back( item );
00292 _graph[item].push_back( must_visit );
00293 rdfsvisit( must_visit );
00294 }
00295 else if (_nodes[must_visit].endtime == 0)
00296 {
00297 if (must_visit != item)
00298 {
00299
00300 std::string lstr( ITEMNAME(item) );
00301 lstr += " -> ";
00302 lstr += ITEMNAME(must_visit);
00303 if ( _logset.insert( lstr ).second )
00304 {
00305 WAR << "** dependency loop: " << lstr << endl;
00306 }
00307 }
00308 }
00309 else
00310 {
00311
00312 PoolItemList & lrg = _rgraph[must_visit];
00313 if( find( lrg.begin(), lrg.end(), item) == lrg.end() )
00314 {
00315 nodeinfo.order++;
00316 lrg.push_back( item );
00317
00318 PoolItemList & lg = _graph[item];
00319 if( find( lg.begin(), lg.end(), must_visit ) == lg.end() )
00320 lg.push_back( must_visit );
00321 }
00322 }
00323 }
00324 }
00325 _topsorted.push_back(item);
00326 _nodes[item].endtime = _rdfstime;
00327 _rdfstime++;
00328
00329 XXX << ITEMNAME(item) << " done" << endl;
00330 }
00331
00332
00333 void
00334 InstallOrder::startrdfs()
00335 {
00336 _nodes.clear();
00337 _rgraph.clear();
00338 _graph.clear();
00339
00340 _rdfstime = 1;
00341
00342 _topsorted.clear();
00343
00344 _numrun++;
00345 XXX << "run #" << _numrun << endl;
00346
00347
00348 for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
00349 {
00350 PoolItem_Ref item = *it;
00351 _nodes[item] = NodeInfo (item);
00352 _rgraph[item] = PoolItemList();
00353 _graph[item] = PoolItemList();
00354 }
00355
00356
00357 for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
00358 {
00359 const PoolItem_Ref item = *it;
00360 if (_nodes[item].visited == false)
00361 {
00362 XXX << "start recursion on " << ITEMNAME(item) << endl;
00363 rdfsvisit (item);
00364 }
00365 }
00366
00367 _dirty = false;
00368 }
00369
00370
00371
00372
00373 const PoolItemList
00374 InstallOrder::getTopSorted() const
00375 {
00376 return _topsorted;
00377 }
00378
00379
00381 };
00384 };
00387 };