00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <map>
00023
00024 #include "zypp/base/String.h"
00025 #include "zypp/solver/detail/ResolverQueue.h"
00026 #include "zypp/solver/detail/QueueItemBranch.h"
00027 #include "zypp/solver/detail/QueueItemConflict.h"
00028 #include "zypp/solver/detail/QueueItemEstablish.h"
00029 #include "zypp/solver/detail/QueueItemGroup.h"
00030 #include "zypp/solver/detail/QueueItemInstall.h"
00031 #include "zypp/solver/detail/QueueItemRequire.h"
00032 #include "zypp/solver/detail/QueueItemUninstall.h"
00033 #include "zypp/solver/detail/ResolverContext.h"
00034 #include "zypp/CapSet.h"
00035 #include "zypp/base/Logger.h"
00036
00038 namespace zypp
00039 {
00040
00041 namespace solver
00042 {
00043
00044 namespace detail
00045 {
00046
00047 using namespace std;
00048
00049 IMPL_PTR_TYPE(ResolverQueue);
00050
00051
00052
00053
00054
00055
00056 ostream&
00057 operator<<( ostream& os, const ResolverQueue & resolverqueue)
00058 {
00059 os << str::form ("Context [%p]", (const void *)resolverqueue._context.get());
00060 os << ", " << resolverqueue._qitems.size() << " Items:" << endl << "\t";
00061 os << resolverqueue._qitems;
00062 return os;
00063 }
00064
00065
00066
00067 ResolverQueue::ResolverQueue (const ResPool & pool, const Arch & arch, ResolverContext_Ptr context)
00068 : _context (context)
00069 {
00070 _XDEBUG("ResolverQueue::ResolverQueue(pool,... )");
00071 if (context == NULL)
00072 _context = new ResolverContext(pool, arch);
00073 }
00074
00075
00076 ResolverQueue::~ResolverQueue()
00077 {
00078 }
00079
00080
00081
00082 void
00083 ResolverQueue::addPoolItemToInstall (PoolItem_Ref poolItem)
00084 {
00085 QueueItemInstall_Ptr qitem;
00086
00087 if (_context->isPresent (poolItem)
00088 && poolItem.status().staysInstalled()) {
00089 WAR << poolItem << " is already installed" << endl;
00090 return;
00091 }
00092
00093 qitem = new QueueItemInstall (_context->pool(), poolItem, poolItem.status().isSoftInstall());
00094 poolItem.status().setSoftInstall(false);
00095 qitem->setExplicitlyRequested ();
00096
00097 addItem (qitem);
00098 }
00099
00100
00101 void
00102 ResolverQueue::addPoolItemToEstablish (PoolItem_Ref poolItem)
00103 {
00104 QueueItemEstablish_Ptr qitem;
00105
00106 qitem = new QueueItemEstablish (_context->pool(), poolItem);
00107 qitem->setExplicitlyRequested ();
00108
00109 addItem (qitem);
00110 }
00111
00112
00113 void
00114 ResolverQueue::addPoolItemToRemove (PoolItem_Ref poolItem, bool remove_only_mode)
00115 {
00116 QueueItemUninstall_Ptr qitem;
00117
00118 if (_context->isAbsent (poolItem))
00119 return;
00120
00121 qitem = new QueueItemUninstall (_context->pool(), poolItem, QueueItemUninstall::EXPLICIT, poolItem.status().isSoftUninstall());
00122 poolItem.status().setSoftUninstall(false);
00123 if (remove_only_mode)
00124 qitem->setRemoveOnly ();
00125
00126 qitem->setExplicitlyRequested ();
00127
00128 addItem (qitem);
00129 }
00130
00131
00132 void
00133 ResolverQueue::addPoolItemToVerify (PoolItem_Ref poolItem)
00134 {
00135 if (poolItem.status().staysInstalled()
00136 || poolItem.status().isToBeInstalled()) {
00137
00138 CapSet requires = poolItem->dep (Dep::REQUIRES);
00139 for (CapSet::const_iterator iter = requires.begin(); iter != requires.end(); ++iter) {
00140 QueueItemRequire_Ptr qitem = new QueueItemRequire (_context->pool(), *iter);
00141 qitem->addPoolItem (poolItem);
00142 addItem (qitem);
00143 }
00144
00145 CapSet conflicts = poolItem->dep (Dep::CONFLICTS);
00146 for (CapSet::const_iterator iter = conflicts.begin(); iter != conflicts.end(); ++iter) {
00147 QueueItemConflict_Ptr qitem = new QueueItemConflict (_context->pool(), *iter, poolItem);
00148 addItem (qitem);
00149 }
00150 }
00151 }
00152
00153
00154 void
00155 ResolverQueue::addExtraCapability (const Capability & dep)
00156 {
00157 QueueItemRequire_Ptr qitem = new QueueItemRequire (_context->pool(), dep);
00158 addItem (qitem);
00159 }
00160
00161
00162 void
00163 ResolverQueue::addExtraConflict (const Capability & dep)
00164 {
00165 QueueItemConflict_Ptr qitem = new QueueItemConflict (_context->pool(), dep, PoolItem_Ref());
00166 qitem->setExplicitlyRequested();
00167 addItem (qitem);
00168 }
00169
00170
00171 void
00172 ResolverQueue::addItem (QueueItem_Ptr qitem)
00173 {
00174 _qitems.push_back(qitem);
00175 }
00176
00177
00178 bool
00179 ResolverQueue::isInvalid ()
00180 {
00181 return _context->isInvalid() || _context->askUser();
00182 }
00183
00184
00185 bool
00186 ResolverQueue::containsOnlyBranches ()
00187 {
00188 for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end(); ++iter) {
00189 if (!(*iter)->isBranch())
00190 return false;
00191 }
00192
00193 return true;
00194 }
00195
00196
00197
00198 static int
00199 qitemlist_max_priority (const QueueItemList & qil)
00200 {
00201 int max_priority = -1;
00202 for (QueueItemList::const_iterator iter = qil.begin(); iter != qil.end(); ++iter) {
00203 if ((*iter)->priority() > max_priority) {
00204 max_priority = (*iter)->priority();
00205 }
00206 }
00207
00208 return max_priority;
00209 }
00210
00211
00212
00213 bool
00214 ResolverQueue::processOnce ()
00215 {
00216 QueueItemList new_qitems;
00217 int max_priority;
00218 bool did_something = false;
00219
00220 _XDEBUG("ResolverQueue::processOnce()" << (int) _qitems.size() << " items");
00221 while ( (max_priority = qitemlist_max_priority (_qitems)) >= 0
00222 && _context->isValid () ) {
00223
00224 bool did_something_recently = false;
00225
00226 for (QueueItemList::iterator iter = _qitems.begin(); iter != _qitems.end() && _context->isValid();) {
00227 QueueItem_Ptr qitem = *iter;
00228 _XDEBUG( "=====> 1st pass: [" << *qitem << "]");
00229 QueueItemList::iterator next = iter; ++next;
00230 if (qitem && qitem->priority() == max_priority) {
00231 if (qitem->process (_qitems, _context, new_qitems)) {
00232 did_something_recently = true;
00233 }
00234 _qitems.erase (iter);
00235 }
00236 iter = next;
00237 }
00238
00239 if (did_something_recently) {
00240 did_something = true;
00241 }
00242 }
00243
00244 _qitems = new_qitems;
00245 _XDEBUG(_qitems.size() << " qitems after first pass");
00246
00247
00248
00249
00250
00251
00252
00253 for (QueueItemList::iterator iter = _qitems.begin(); iter != _qitems.end();) {
00254 QueueItemList::iterator next = iter; ++next;
00255 QueueItem_Ptr qitem = *iter;
00256
00257 _XDEBUG( "=====> 2nd pass: [" << *qitem << "]");
00258 if (qitem->isBranch()) {
00259 _XDEBUG("ResolverQueue::processOnce() is branch");
00260 QueueItemBranch_Ptr branch = dynamic_pointer_cast<QueueItemBranch>(qitem);
00261 for (QueueItemList::const_iterator iter2 = _qitems.begin(); iter2 != _qitems.end(); ++iter2) {
00262 _XDEBUG("Compare branch with [" << *(*iter2) << "]");
00263 if (iter != iter2
00264 && branch->contains (*iter2)) {
00265 _XDEBUG("Contained within, removing");
00266 _qitems.erase (iter);
00267 break;
00268 }
00269 }
00270 }
00271 iter = next;
00272 }
00273 if (did_something) {
00274 _XDEBUG( "did something: " << _qitems.size() << " qitems");
00275 }
00276 else {
00277 _XDEBUG( "did nothing: " << _qitems.size() << " qitems");
00278 }
00279
00280 return did_something;
00281 }
00282
00283
00284 void
00285 ResolverQueue::process ()
00286 {
00287 _XDEBUG("----- Processing -----");
00288 spew ();
00289
00290 while (_context->isValid ()
00291 && ! isEmpty ()
00292 && processOnce ()) {
00293
00294 spew ();
00295 }
00296 }
00297
00298
00299
00300
00301 ResolverQueue_Ptr
00302 ResolverQueue::copy_queue_except_for_branch (QueueItem_Ptr branch_qitem, QueueItem_Ptr subqitem) const
00303 {
00304 ResolverContext_Ptr new_context;
00305 ResolverQueue_Ptr new_queue;
00306 _XDEBUG("copy_queue_except_for_branch");
00307 new_context = new ResolverContext (_context->pool(), _context->architecture(), _context);
00308
00309 new_queue = new ResolverQueue (new_context->pool(), new_context->architecture(), new_context);
00310
00311 QueueItemList qil = _qitems;
00312 for (QueueItemList::const_iterator iter = qil.begin(); iter != qil.end(); ++iter) {
00313 QueueItem_Ptr qitem = *iter;
00314 QueueItem_Ptr new_qitem;
00315
00316 if (qitem == branch_qitem) {
00317 new_qitem = subqitem->copy ();
00318
00319 if (new_qitem->isInstall()) {
00320 QueueItemInstall_Ptr install_qitem = dynamic_pointer_cast<QueueItemInstall>(new_qitem);
00321
00322
00323 #warning FIX priorities
00324 int penalty = 0;
00325 Repository repo = install_qitem->item()->repository();
00326
00327 install_qitem->setOtherPenalty (penalty);
00328 }
00329
00330 } else {
00331
00332 new_qitem = qitem->copy ();
00333
00334 }
00335
00336 new_queue->addItem (new_qitem);
00337 }
00338
00339 return new_queue;
00340 }
00341
00342
00343 void
00344 ResolverQueue::splitFirstBranch (ResolverQueueList & new_queues, ResolverQueueList & deferred_queues)
00345 {
00346 QueueItemBranch_Ptr first_branch = NULL;
00347 typedef std::map <QueueItem_Ptr, QueueItem_Ptr> DeferTable;
00348 DeferTable to_defer;
00349
00350 for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end() && first_branch == NULL; ++iter) {
00351 QueueItem_Ptr qitem = *iter;
00352 if (qitem->isBranch()) {
00353 first_branch = dynamic_pointer_cast<QueueItemBranch>(qitem);
00354 }
00355 }
00356
00357 if (first_branch == NULL)
00358 return;
00359
00360 QueueItemList possible_qitems = first_branch->possibleQItems();
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 for (QueueItemList::const_iterator iter = possible_qitems.begin(); iter != possible_qitems.end(); ++iter) {
00371 QueueItemList::const_iterator iter2 = iter;
00372 for (iter2++; iter2 != possible_qitems.end(); iter2++) {
00373 QueueItem_Ptr qitem = *iter;
00374 QueueItem_Ptr qitem2 = *iter2;
00375
00376 if (qitem->isInstall() && qitem2->isInstall()) {
00377 PoolItem_Ref r = (dynamic_pointer_cast<QueueItemInstall>(qitem))->item();
00378 PoolItem_Ref r2 = (dynamic_pointer_cast<QueueItemInstall>(qitem2))->item();
00379 Repository repo1 = r->repository();
00380 Repository repo2 = r2->repository();
00381 int priority, priority2;
00382
00383 priority = _context->getRepoPriority( repo1 );
00384 priority2 = _context->getRepoPriority( repo2 );
00385
00386 if (priority != priority2 && r->name() == r2->name()) {
00387 if (r->edition().compare(r2->edition()) == 0
00388 || (priority < priority2 && r->edition().compare(r2->edition()) < 0)
00389 || (priority > priority2 && r->edition().compare(r2->edition()) > 0))
00390 {
00391 if (priority < priority2)
00392 to_defer[qitem] = qitem;
00393 else
00394 to_defer[qitem2] = qitem2;
00395 }
00396 }
00397 }
00398 }
00399 }
00400
00401 for (QueueItemList::const_iterator iter = possible_qitems.begin(); iter != possible_qitems.end(); ++iter) {
00402 ResolverQueue_Ptr new_queue;
00403 QueueItem_Ptr new_qitem = *iter;
00404
00405 new_queue = copy_queue_except_for_branch ((QueueItem_Ptr) first_branch, new_qitem);
00406
00407 DeferTable::const_iterator pos = to_defer.find (new_qitem);
00408 if (pos != to_defer.end()) {
00409 deferred_queues.push_back(new_queue);
00410 } else {
00411 new_queues.push_back(new_queue);
00412 }
00413 }
00414
00415 }
00416
00417
00418 void
00419 ResolverQueue::spew ()
00420 {
00421 _XDEBUG( "Resolver Queue: " << (_context->isInvalid() ? "INVALID" : "") );
00422
00423 if (_qitems.empty()) {
00424
00425 _XDEBUG( " (empty)" );
00426
00427 } else {
00428 for (QueueItemList::const_iterator iter = _qitems.begin(); iter != _qitems.end(); ++iter) {
00429 _XDEBUG( " " << *(*iter) );
00430 }
00431
00432 }
00433 }
00434
00436 };
00439 };
00442 };
00444