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 WAR << "** dependency loop: " << ITEMNAME(item) << " -> " << ITEMNAME(must_visit) << endl;
00300 }
00301 }
00302 else
00303 {
00304
00305 PoolItemList & lrg = _rgraph[must_visit];
00306 if( find( lrg.begin(), lrg.end(), item) == lrg.end() )
00307 {
00308 nodeinfo.order++;
00309 lrg.push_back( item );
00310
00311 PoolItemList & lg = _graph[item];
00312 if( find( lg.begin(), lg.end(), must_visit ) == lg.end() )
00313 lg.push_back( must_visit );
00314 }
00315 }
00316 }
00317 }
00318 _topsorted.push_back(item);
00319 _nodes[item].endtime = _rdfstime;
00320 _rdfstime++;
00321
00322 XXX << ITEMNAME(item) << " done" << endl;
00323 }
00324
00325
00326 void
00327 InstallOrder::startrdfs()
00328 {
00329 _nodes.clear();
00330 _rgraph.clear();
00331 _graph.clear();
00332
00333 _rdfstime = 1;
00334
00335 _topsorted.clear();
00336
00337 _numrun++;
00338 XXX << "run #" << _numrun << endl;
00339
00340
00341 for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
00342 {
00343 PoolItem_Ref item = *it;
00344 _nodes[item] = NodeInfo (item);
00345 _rgraph[item] = PoolItemList();
00346 _graph[item] = PoolItemList();
00347 }
00348
00349
00350 for (PoolItemSet::iterator it = _toinstall.begin(); it != _toinstall.end(); ++it)
00351 {
00352 const PoolItem_Ref item = *it;
00353 if (_nodes[item].visited == false)
00354 {
00355 XXX << "start recursion on " << ITEMNAME(item) << endl;
00356 rdfsvisit (item);
00357 }
00358 }
00359
00360 _dirty = false;
00361 }
00362
00363
00364
00365
00366 const PoolItemList
00367 InstallOrder::getTopSorted() const
00368 {
00369 return _topsorted;
00370 }
00371
00372
00374 };
00377 };
00380 };