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