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