789f35b48aaa8c955bc14aaccc74d1a0abacb3a8
[platform/upstream/libzypp.git] / zypp / solver / detail / Resolver.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* Resolver.cc
3  *
4  * Copyright (C) 2000-2002 Ximian, Inc.
5  * Copyright (C) 2005 SUSE Linux Products GmbH
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19  * 02111-1307, USA.
20  */
21 #include <boost/static_assert.hpp>
22
23 #define ZYPP_USE_RESOLVER_INTERNALS
24
25 #include "zypp/solver/detail/Resolver.h"
26 #include "zypp/solver/detail/Testcase.h"
27 #include "zypp/solver/detail/SATResolver.h"
28 #include "zypp/solver/detail/ItemCapKind.h"
29 #include "zypp/solver/detail/SolutionAction.h"
30 #include "zypp/solver/detail/SolverQueueItem.h"
31
32 #include "zypp/Capabilities.h"
33 #include "zypp/ZConfig.h"
34 #include "zypp/base/Logger.h"
35 #include "zypp/base/String.h"
36 #include "zypp/base/Gettext.h"
37 #include "zypp/base/Algorithm.h"
38 #include "zypp/ResPool.h"
39 #include "zypp/ResFilters.h"
40 #include "zypp/sat/Pool.h"
41 #include "zypp/sat/Solvable.h"
42 #include "zypp/sat/Transaction.h"
43 #include "zypp/ResolverProblem.h"
44
45 #define MAXSOLVERRUNS 5
46
47 using std::endl;
48 using std::make_pair;
49
50 /////////////////////////////////////////////////////////////////////////
51 namespace zypp
52 { ///////////////////////////////////////////////////////////////////////
53   ///////////////////////////////////////////////////////////////////////
54   namespace solver
55   { /////////////////////////////////////////////////////////////////////
56     /////////////////////////////////////////////////////////////////////
57     namespace detail
58     { ///////////////////////////////////////////////////////////////////
59
60       //using namespace std;
61
62 //---------------------------------------------------------------------------
63
64
65 std::ostream & Resolver::dumpOn( std::ostream & os ) const
66 {
67   os << "<resolver>" << endl;
68   #define OUTS(t) os << "  " << #t << ":\t" << t << endl;
69   OUTS( _upgradeMode );
70   OUTS( _updateMode );
71   OUTS( _verifying );
72   OUTS( _onlyRequires );
73   OUTS( _solveSrcPackages );
74   OUTS( _cleandepsOnRemove );
75   OUTS( _ignoreAlreadyRecommended );
76   #undef OUT
77   return os << "<resolver/>";
78 }
79
80
81 //---------------------------------------------------------------------------
82
83 Resolver::Resolver (const ResPool & pool)
84     : _pool(pool)
85     , _satResolver(NULL)
86     , _poolchanged(_pool.serial() )
87     , _upgradeMode              (false)
88     , _updateMode               (false)
89     , _verifying                (false)
90     , _onlyRequires             ( ZConfig::instance().solver_onlyRequires() )
91     , _solveSrcPackages         ( false )
92     , _cleandepsOnRemove        ( ZConfig::instance().solver_cleandepsOnRemove() )
93     , _ignoreAlreadyRecommended ( true )
94
95 {
96     sat::Pool satPool( sat::Pool::instance() );
97     _satResolver = new SATResolver(_pool, satPool.get());
98 }
99
100
101 Resolver::~Resolver()
102 {
103   delete _satResolver;
104 }
105
106 //---------------------------------------------------------------------------
107 // forward flags too SATResolver
108 #define ZOLV_FLAG_TRIBOOL( ZSETTER, ZGETTER, ZVARNAME, ZVARDEFAULT )                    \
109     void Resolver::ZSETTER( TriBool state_r )                                           \
110     { _satResolver->ZVARNAME = indeterminate(state_r) ? ZVARDEFAULT : bool(state_r); }  \
111     bool Resolver::ZGETTER() const                                                      \
112     { return _satResolver->ZVARNAME; }                                                  \
113
114 // NOTE: ZVARDEFAULT must be in sync with SATResolver ctor
115 ZOLV_FLAG_TRIBOOL( setForceResolve,             forceResolve,           _allowuninstall,        false )
116
117 ZOLV_FLAG_TRIBOOL( setAllowDowngrade,           allowDowngrade,         _allowdowngrade,        false )
118 ZOLV_FLAG_TRIBOOL( setAllowNameChange,          allowNameChange,        _allownamechange,       true )  // bsc#1071466
119 ZOLV_FLAG_TRIBOOL( setAllowArchChange,          allowArchChange,        _allowarchchange,       false )
120 ZOLV_FLAG_TRIBOOL( setAllowVendorChange,        allowVendorChange,      _allowvendorchange,     ZConfig::instance().solver_allowVendorChange() )
121
122 ZOLV_FLAG_TRIBOOL( dupSetAllowDowngrade,        dupAllowDowngrade,      _dup_allowdowngrade,    ZConfig::instance().solver_dupAllowDowngrade() )
123 ZOLV_FLAG_TRIBOOL( dupSetAllowNameChange,       dupAllowNameChange,     _dup_allownamechange,   ZConfig::instance().solver_dupAllowNameChange() )
124 ZOLV_FLAG_TRIBOOL( dupSetAllowArchChange,       dupAllowArchChange,     _dup_allowarchchange,   ZConfig::instance().solver_dupAllowArchChange() )
125 ZOLV_FLAG_TRIBOOL( dupSetAllowVendorChange,     dupAllowVendorChange,   _dup_allowvendorchange, ZConfig::instance().solver_dupAllowVendorChange() )
126
127 #undef ZOLV_FLAG_TRIBOOL
128 //---------------------------------------------------------------------------
129
130 void Resolver::setOnlyRequires( TriBool state_r )
131 {
132   _onlyRequires = indeterminate(state_r) ? ZConfig::instance().solver_onlyRequires() : bool(state_r);
133 }
134
135 void Resolver::setCleandepsOnRemove( TriBool state_r )
136 {
137   _cleandepsOnRemove = indeterminate(state_r) ? ZConfig::instance().solver_cleandepsOnRemove() : bool(state_r);
138 }
139
140 //---------------------------------------------------------------------------
141
142 ResPool Resolver::pool() const
143 { return _pool; }
144
145 void Resolver::reset( bool keepExtras )
146 {
147     _verifying = false;
148
149     if (!keepExtras) {
150       _extra_requires.clear();
151       _extra_conflicts.clear();
152     }
153
154     _isInstalledBy.clear();
155     _installs.clear();
156     _satifiedByInstalled.clear();
157     _installedSatisfied.clear();
158 }
159
160 bool Resolver::doUpgrade()
161 {
162   // Setting Resolver to upgrade mode. SAT solver will do the update
163   _upgradeMode = true;
164   return resolvePool();
165 }
166
167 void Resolver::doUpdate()
168 {
169     _updateMode = true;
170     return _satResolver->doUpdate();
171 }
172
173 PoolItemList Resolver::problematicUpdateItems() const
174 { return _satResolver->problematicUpdateItems(); }
175
176 void Resolver::addExtraRequire( const Capability & capability )
177 { _extra_requires.insert (capability); }
178
179 void Resolver::removeExtraRequire( const Capability & capability )
180 { _extra_requires.erase (capability); }
181
182 void Resolver::addExtraConflict( const Capability & capability )
183 { _extra_conflicts.insert (capability); }
184
185 void Resolver::removeExtraConflict( const Capability & capability )
186 { _extra_conflicts.erase (capability); }
187
188 void Resolver::removeQueueItem( SolverQueueItem_Ptr item )
189 {
190     bool found = false;
191     for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
192          iter != _added_queue_items.end(); iter++) {
193         if (*iter == item) {
194             _added_queue_items.remove(*iter);
195             found = true;
196             break;
197         }
198     }
199     if (!found) {
200         _removed_queue_items.push_back (item);
201         _removed_queue_items.unique ();
202     }
203 }
204
205 void Resolver::addQueueItem( SolverQueueItem_Ptr item )
206 {
207     bool found = false;
208     for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
209          iter != _removed_queue_items.end(); iter++) {
210         if (*iter == item) {
211             _removed_queue_items.remove(*iter);
212             found = true;
213             break;
214         }
215     }
216     if (!found) {
217         _added_queue_items.push_back (item);
218         _added_queue_items.unique ();
219     }
220 }
221
222 void Resolver::addWeak( const PoolItem & item )
223 { _addWeak.push_back( item ); }
224
225 //---------------------------------------------------------------------------
226
227 struct UndoTransact : public resfilter::PoolItemFilterFunctor
228 {
229     ResStatus::TransactByValue resStatus;
230     UndoTransact ( const ResStatus::TransactByValue &status)
231         :resStatus(status)
232     { }
233
234     bool operator()( PoolItem item )            // only transacts() items go here
235     {
236         item.status().resetTransact( resStatus );// clear any solver/establish transactions
237         return true;
238     }
239 };
240
241
242 struct DoTransact : public resfilter::PoolItemFilterFunctor
243 {
244     ResStatus::TransactByValue resStatus;
245     DoTransact ( const ResStatus::TransactByValue &status)
246         :resStatus(status)
247     { }
248
249     bool operator()( PoolItem item )            // only transacts() items go here
250     {
251         item.status().setTransact( true, resStatus );
252         return true;
253     }
254 };
255
256
257 bool Resolver::verifySystem()
258 {
259     UndoTransact resetting (ResStatus::APPL_HIGH);
260
261     DBG << "Resolver::verifySystem()" << endl;
262
263     _verifying = true;
264
265     invokeOnEach ( _pool.begin(), _pool.end(),
266                    resfilter::ByTransact( ),                    // Resetting all transcations
267                    functor::functorRef<bool,PoolItem>(resetting) );
268
269     return resolvePool();
270 }
271
272
273 //----------------------------------------------------------------------------
274 // undo
275 void Resolver::undo()
276 {
277     UndoTransact info(ResStatus::APPL_LOW);
278     MIL << "*** undo ***" << endl;
279     invokeOnEach ( _pool.begin(), _pool.end(),
280                    resfilter::ByTransact( ),                    // collect transacts from Pool to resolver queue
281                    functor::functorRef<bool,PoolItem>(info) );
282     //  Regard dependencies of the item weak onl
283     _addWeak.clear();
284
285     // Additional QueueItems which has to be regarded by the solver
286     _removed_queue_items.clear();
287     _added_queue_items.clear();
288
289     return;
290 }
291
292 void Resolver::solverInit()
293 {
294     // Solving with libsolv
295     static bool poolDumped = false;
296     MIL << "-------------- Calling SAT Solver -------------------" << endl;
297     if ( getenv("ZYPP_FULLLOG") ) {
298         Testcase testcase("/var/log/YaST2/autoTestcase");
299         if (!poolDumped) {
300             testcase.createTestcase (*this, true, false); // dump pool
301             poolDumped = true;
302         } else {
303             testcase.createTestcase (*this, false, false); // write control file only
304         }
305     }
306
307     _satResolver->setFixsystem                  ( isVerifyingMode() );
308     _satResolver->setIgnorealreadyrecommended   ( ignoreAlreadyRecommended() );
309     _satResolver->setOnlyRequires               ( onlyRequires() );
310     _satResolver->setUpdatesystem               (_updateMode);
311     _satResolver->setSolveSrcPackages           ( solveSrcPackages() );
312     _satResolver->setCleandepsOnRemove          ( cleandepsOnRemove() );
313
314     _satResolver->setDistupgrade                (_upgradeMode);
315     if (_upgradeMode) {
316       // may overwrite some settings
317       _satResolver->setDistupgrade_removeunsupported    (false);
318     }
319
320     // Resetting additional solver information
321     _isInstalledBy.clear();
322     _installs.clear();
323     _satifiedByInstalled.clear();
324     _installedSatisfied.clear();
325 }
326
327 bool Resolver::resolvePool()
328 {
329     solverInit();
330     return _satResolver->resolvePool(_extra_requires, _extra_conflicts, _addWeak, _upgradeRepos );
331 }
332
333 bool Resolver::resolveQueue( solver::detail::SolverQueueItemList & queue )
334 {
335     solverInit();
336
337     // add/remove additional SolverQueueItems
338     for (SolverQueueItemList::const_iterator iter = _removed_queue_items.begin();
339          iter != _removed_queue_items.end(); iter++) {
340         for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
341             if ( (*iterQueue)->cmp(*iter) == 0) {
342                 MIL << "remove from queue" << *iter;
343                 queue.remove(*iterQueue);
344                 break;
345             }
346         }
347     }
348
349     for (SolverQueueItemList::const_iterator iter = _added_queue_items.begin();
350          iter != _added_queue_items.end(); iter++) {
351         bool found = false;
352         for (SolverQueueItemList::const_iterator iterQueue = queue.begin(); iterQueue != queue.end(); iterQueue++) {
353             if ( (*iterQueue)->cmp(*iter) == 0) {
354                 found = true;
355                 break;
356             }
357         }
358         if (!found) {
359             MIL << "add to queue" << *iter;
360             queue.push_back(*iter);
361         }
362     }
363
364     // The application has to take care to write these solutions back to e.g. selectables in order
365     // give the user a chance for changing these decisions again.
366     _removed_queue_items.clear();
367     _added_queue_items.clear();
368
369     return _satResolver->resolveQueue(queue, _addWeak);
370 }
371
372 sat::Transaction Resolver::getTransaction()
373 {
374   // FIXME: That's an ugly way of pushing autoInstalled into the transaction.
375   sat::Transaction ret( sat::Transaction::loadFromPool );
376   ret.autoInstalled( _satResolver->autoInstalled() );
377   return ret;
378 }
379
380
381 //----------------------------------------------------------------------------
382 // Getting more information about the solve results
383
384 ResolverProblemList Resolver::problems() const
385 {
386   MIL << "Resolver::problems()" << endl;
387   return _satResolver->problems();
388 }
389
390 void Resolver::applySolutions( const ProblemSolutionList & solutions )
391 {
392   for ( ProblemSolution_Ptr solution : solutions )
393   {
394     if ( ! applySolution( *solution ) )
395       break;
396   }
397 }
398
399 bool Resolver::applySolution( const ProblemSolution & solution )
400 {
401   bool ret = true;
402   DBG << "apply solution " << solution << endl;
403   for ( SolutionAction_Ptr action : solution.actions() )
404   {
405     if ( ! action->execute( *this ) )
406     {
407       WAR << "apply solution action failed: " << action << endl;
408       ret = false;
409       break;
410     }
411   }
412   return ret;
413 }
414
415 //----------------------------------------------------------------------------
416
417 void Resolver::collectResolverInfo()
418 {
419     if ( _satResolver
420          && _isInstalledBy.empty()
421          && _installs.empty()) {
422
423         // generating new
424         PoolItemList itemsToInstall = _satResolver->resultItemsToInstall();
425
426         for (PoolItemList::const_iterator instIter = itemsToInstall.begin();
427              instIter != itemsToInstall.end(); instIter++) {
428             // Requires
429             for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::REQUIRES).begin(); capIt != (*instIter)->dep (Dep::REQUIRES).end(); ++capIt)
430             {
431                 sat::WhatProvides possibleProviders(*capIt);
432                 for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
433                     PoolItem provider = ResPool::instance().find( *iter );
434
435                     // searching if this provider will already be installed
436                     bool found = false;
437                     bool alreadySetForInstallation = false;
438                     ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
439                     while (pos != _isInstalledBy.end()
440                            && pos->first == provider
441                            && !found) {
442                         alreadySetForInstallation = true;
443                         ItemCapKind capKind = pos->second;
444                         if (capKind.item() == *instIter)  found = true;
445                         pos++;
446                     }
447
448                     if (!found
449                         && provider.status().isToBeInstalled()) {
450                         if (provider.status().isBySolver()) {
451                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
452                             _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
453                         } else {
454                             // no initial installation cause it has been set be e.g. user
455                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::REQUIRES, false );
456                             _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
457                         }
458                         ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, !alreadySetForInstallation );
459                         _installs.insert (make_pair( *instIter, capKindisInstalledBy));
460                     }
461
462                     if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
463                         ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::REQUIRES, false );
464                         _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
465
466                         ItemCapKind installedSatisfied( *instIter, *capIt, Dep::REQUIRES, false );
467                         _installedSatisfied.insert (make_pair( provider, installedSatisfied));
468                     }
469                 }
470             }
471
472             if (!(_satResolver->onlyRequires())) {
473                 //Recommends
474                 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::RECOMMENDS).begin(); capIt != (*instIter)->dep (Dep::RECOMMENDS).end(); ++capIt)
475                 {
476                     sat::WhatProvides possibleProviders(*capIt);
477                     for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
478                         PoolItem provider = ResPool::instance().find( *iter );
479
480                         // searching if this provider will already be installed
481                         bool found = false;
482                         bool alreadySetForInstallation = false;
483                         ItemCapKindMap::const_iterator pos = _isInstalledBy.find(provider);
484                         while (pos != _isInstalledBy.end()
485                                && pos->first == provider
486                                && !found) {
487                             alreadySetForInstallation = true;
488                             ItemCapKind capKind = pos->second;
489                             if (capKind.item() == *instIter)  found = true;
490                             pos++;
491                         }
492
493                         if (!found
494                             && provider.status().isToBeInstalled()) {
495                             if (provider.status().isBySolver()) {
496                                 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
497                                 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
498                             } else {
499                                 // no initial installation cause it has been set be e.g. user
500                                 ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::RECOMMENDS, false );
501                                 _isInstalledBy.insert (make_pair( provider, capKindisInstalledBy));
502                             }
503                             ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, !alreadySetForInstallation );
504                             _installs.insert (make_pair( *instIter, capKindisInstalledBy));
505                         }
506
507                         if (provider.status().staysInstalled()) { // Is already satisfied by an item which is installed
508                             ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::RECOMMENDS, false );
509                             _satifiedByInstalled.insert (make_pair( *instIter, capKindisInstalledBy));
510
511                             ItemCapKind installedSatisfied( *instIter, *capIt, Dep::RECOMMENDS, false );
512                             _installedSatisfied.insert (make_pair( provider, installedSatisfied));
513                         }
514                     }
515                 }
516
517                 //Supplements
518                 for (Capabilities::const_iterator capIt = (*instIter)->dep (Dep::SUPPLEMENTS).begin(); capIt != (*instIter)->dep (Dep::SUPPLEMENTS).end(); ++capIt)
519                 {
520                     sat::WhatProvides possibleProviders(*capIt);
521                     for_( iter, possibleProviders.begin(), possibleProviders.end() ) {
522                         PoolItem provider = ResPool::instance().find( *iter );
523                         // searching if this item will already be installed
524                         bool found = false;
525                         bool alreadySetForInstallation = false;
526                         ItemCapKindMap::const_iterator pos = _isInstalledBy.find(*instIter);
527                         while (pos != _isInstalledBy.end()
528                                && pos->first == *instIter
529                                && !found) {
530                             alreadySetForInstallation = true;
531                             ItemCapKind capKind = pos->second;
532                             if (capKind.item() == provider)  found = true;
533                             pos++;
534                         }
535
536                         if (!found
537                             && instIter->status().isToBeInstalled()) {
538                             if (instIter->status().isBySolver()) {
539                                 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
540                                 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
541                             } else {
542                                 // no initial installation cause it has been set be e.g. user
543                                 ItemCapKind capKindisInstalledBy( provider, *capIt, Dep::SUPPLEMENTS, false );
544                                 _isInstalledBy.insert (make_pair( *instIter, capKindisInstalledBy));
545                             }
546                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
547                             _installs.insert (make_pair( provider, capKindisInstalledBy));
548                         }
549
550                         if (instIter->status().staysInstalled()) { // Is already satisfied by an item which is installed
551                             ItemCapKind capKindisInstalledBy( *instIter, *capIt, Dep::SUPPLEMENTS, !alreadySetForInstallation );
552                             _satifiedByInstalled.insert (make_pair( provider, capKindisInstalledBy));
553
554                             ItemCapKind installedSatisfied( provider, *capIt, Dep::SUPPLEMENTS, false );
555                             _installedSatisfied.insert (make_pair( *instIter, installedSatisfied));
556                         }
557                     }
558                 }
559             }
560         }
561     }
562 }
563
564
565 ItemCapKindList Resolver::isInstalledBy( const PoolItem & item )
566 {
567     ItemCapKindList ret;
568     collectResolverInfo();
569
570     for (ItemCapKindMap::const_iterator iter = _isInstalledBy.find(item); iter != _isInstalledBy.end();) {
571         ItemCapKind info = iter->second;
572         PoolItem iterItem = iter->first;
573         if (iterItem == item) {
574             ret.push_back(info);
575             iter++;
576         } else {
577             // exit
578             iter = _isInstalledBy.end();
579         }
580     }
581     return ret;
582 }
583
584 ItemCapKindList Resolver::installs( const PoolItem & item )
585 {
586     ItemCapKindList ret;
587     collectResolverInfo();
588
589     for (ItemCapKindMap::const_iterator iter = _installs.find(item); iter != _installs.end();) {
590         ItemCapKind info = iter->second;
591         PoolItem iterItem = iter->first;
592         if (iterItem == item) {
593             ret.push_back(info);
594             iter++;
595         } else {
596             // exit
597             iter = _installs.end();
598         }
599     }
600     return ret;
601 }
602
603 ItemCapKindList Resolver::satifiedByInstalled( const PoolItem & item )
604 {
605     ItemCapKindList ret;
606     collectResolverInfo();
607
608     for (ItemCapKindMap::const_iterator iter = _satifiedByInstalled.find(item); iter != _satifiedByInstalled.end();) {
609         ItemCapKind info = iter->second;
610         PoolItem iterItem = iter->first;
611         if (iterItem == item) {
612             ret.push_back(info);
613             iter++;
614         } else {
615             // exit
616             iter = _satifiedByInstalled.end();
617         }
618     }
619     return ret;
620 }
621
622 ItemCapKindList Resolver::installedSatisfied( const PoolItem & item )
623 {
624     ItemCapKindList ret;
625     collectResolverInfo();
626
627     for (ItemCapKindMap::const_iterator iter = _installedSatisfied.find(item); iter != _installedSatisfied.end();) {
628         ItemCapKind info = iter->second;
629         PoolItem iterItem = iter->first;
630         if (iterItem == item) {
631             ret.push_back(info);
632             iter++;
633         } else {
634             // exit
635             iter = _installedSatisfied.end();
636         }
637     }
638     return ret;
639 }
640
641
642 ///////////////////////////////////////////////////////////////////
643     };// namespace detail
644     /////////////////////////////////////////////////////////////////////
645     /////////////////////////////////////////////////////////////////////
646   };// namespace solver
647   ///////////////////////////////////////////////////////////////////////
648   ///////////////////////////////////////////////////////////////////////
649 };// namespace zypp
650 /////////////////////////////////////////////////////////////////////////
651