rename packages works for update now
[platform/upstream/libzypp.git] / zypp / solver / detail / ResolverUpgrade.cc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*---------------------------------------------------------------------\
3 |                          ____ _   __ __ ___                          |
4 |                         |__  / \ / / . \ . \                         |
5 |                           / / \ V /|  _/  _/                         |
6 |                          / /__ | | | | | |                           |
7 |                         /_____||_| |_| |_|                           |
8 |                                                                      |
9 \---------------------------------------------------------------------*/
10 /* ResolverUpgrade.cc
11  *
12  * Implements the distribution upgrade algorithm.
13  *
14  * Copyright (C) 2005 SUSE Linux Products GmbH
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License,
18  * version 2, as published by the Free Software Foundation.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28  * 02111-1307, USA.
29  */
30
31 /*
32   stolen from PMPackageManager_update.cc
33   original author Michael Andres <ma@suse.de>
34   zypp port by Klaus Kaempf <kkaempf@suse.de>
35
36 /-*/
37
38 #include "zypp/Capabilities.h"
39 #include "zypp/base/Easy.h"
40 #include "zypp/base/LogTools.h"
41 #include "zypp/base/String.h"
42 #include "zypp/base/Gettext.h"
43 #include "zypp/base/Exception.h"
44 #include "zypp/VendorAttr.h"
45 #include "zypp/base/Algorithm.h"
46 #include "zypp/ResPool.h"
47 #include "zypp/ResStatus.h"
48 #include "zypp/ResFilters.h"
49 #include "zypp/CapFilters.h"
50 #include "zypp/Capability.h"
51 #include "zypp/VendorAttr.h"
52 #include "zypp/Package.h"
53 #include "zypp/ZYppFactory.h"
54 #include "zypp/solver/detail/Types.h"
55 #include "zypp/solver/detail/Helper.h"
56 #include "zypp/solver/detail/Resolver.h"
57 #include "zypp/solver/detail/Testcase.h"
58 #include "zypp/Target.h"
59 #include "zypp/sat/SATResolver.h"
60
61 /////////////////////////////////////////////////////////////////////////
62 namespace zypp
63 { ///////////////////////////////////////////////////////////////////////
64   ///////////////////////////////////////////////////////////////////////
65   namespace solver
66   { /////////////////////////////////////////////////////////////////////
67     /////////////////////////////////////////////////////////////////////
68     namespace detail
69     { ///////////////////////////////////////////////////////////////////
70
71 using namespace std;
72 using namespace zypp;
73
74 /** Order on AvialableItemSet.
75  * \li best Arch
76  * \li best Edition
77  * \li ResObject::constPtr as fallback.
78 */
79 struct AVOrder : public std::binary_function<PoolItem,PoolItem,bool>
80 {
81     // NOTE: operator() provides LESS semantics to order the set.
82     // So LESS means 'prior in set'. We want 'better' archs and
83     // 'better' editions at the beginning of the set. So we return
84     // TRUE if (lhs > rhs)!
85     //
86     bool operator()( const PoolItem lhs, const PoolItem rhs ) const
87         {
88             int res = lhs->arch().compare( rhs->arch() );
89             if ( res )
90                 return res > 0;
91             res = lhs->edition().compare( rhs->edition() );
92             if ( res )
93                 return res > 0;
94
95             // no more criteria, still equal:
96             // use the ResObject::constPtr (the poiner value)
97             // (here it's arbitrary whether < or > )
98             return lhs.resolvable() < rhs.resolvable();
99         }
100 };
101
102 typedef std::set<PoolItem, AVOrder> PoolItemOrderSet;
103
104
105
106 // check if downgrade is allowed
107 // (Invariant on entry: installed.edition >= candidate.edition)
108 //
109 // candidate must have allowed vendor (e.g. 'SuSE', 'Novell', ...) and candidates buildtime must be
110 // newer.
111
112 static bool
113 downgrade_allowed( PoolItem installed, PoolItem candidate, bool silent_downgrades )
114 {
115     if (installed.status().isLocked()) {
116         MIL << "Installed " << installed << " is locked, not upgrading" << endl;
117         return false;
118     }
119
120     Resolvable::constPtr ires = installed.resolvable();
121     Package::constPtr ipkg = asKind<Package>(ires);
122     Resolvable::constPtr cres = candidate.resolvable();
123     Package::constPtr cpkg = asKind<Package>(cres);
124
125     if (ipkg)
126       DBG << "Installed vendor '" << ipkg->vendor() << "'" << endl;
127     if (cpkg)
128       DBG << "Candidate vendor '" << cpkg->vendor() << "'" << endl;
129
130     if (cpkg
131         && VendorAttr::instance().equivalent( ipkg->vendor(), cpkg->vendor() ) )
132     {
133         if ( silent_downgrades )
134             return true;
135         if ( ipkg->buildtime() < cpkg->buildtime() ) {                  // installed has older buildtime
136             MIL << "allowed downgrade " << installed << " to " << candidate << endl;
137             return true;                                                // see bug #152760
138         }
139     }
140     return false;
141 }
142
143
144 bool
145 Resolver::doesObsoleteItem (PoolItem candidate, PoolItem installed)
146 {
147     return _satResolver->doesObsoleteItem (candidate, installed);
148 }
149
150 //-----------------------------------------------------------------------------
151
152
153 //-----------------------------------------------------------------------------
154
155 // Selecting item for installation
156
157 class LookForSelected : public resfilter::PoolItemFilterFunctor
158 {
159   public:
160     bool found;
161     PoolItem candidate;
162
163     LookForSelected (PoolItem can)
164         : found (false),
165         candidate (can)
166     { }
167
168     bool operator()( PoolItem item )
169     {
170         if (item.status().isToBeInstalled()
171             && item->edition() == candidate->edition()
172             && item->arch() == candidate->arch()) {
173             MIL << item << " is already selected for installation --> ignoring" << endl;
174             found = true;
175             return false; // stop here
176         }
177         return true;
178     }
179 };
180
181 bool setForInstallation (const ResPool &pool, PoolItem item) {
182     LookForSelected info(item);
183
184     invokeOnEach( pool.byIdentBegin (item->kind(),item->name()),
185                   pool.byIdentEnd (item->kind(),item->name()),
186                   resfilter::ByUninstalled (),                  // ByUninstalled
187                   functor::functorRef<bool,PoolItem> (info) );
188     if (info.found) {
189         MIL << "   ---> " << item << " will be ignoring" << endl;
190         return true;
191     } else {
192         return item.status().setToBeInstalled( ResStatus::APPL_HIGH );
193     }
194 }
195
196 //-----------------------------------------------------------------------------
197
198 ///////////////////////////////////////////////////////////////////
199 //
200 //
201 //      METHOD NAME : Resolver::doUpgrade
202 //      METHOD TYPE : int
203 //
204 //      DESCRIPTION : go through all installed (but not yet touched by user)
205 //              packages and look for update candidates
206 //
207 void
208 Resolver::doUpgrade( UpgradeStatistics & opt_stats_r )
209 {
210   typedef map<PoolItem,PoolItem> CandidateMap;
211   typedef map<PoolItem,PoolItemOrderSet> TodoMap;
212
213   CandidateMap candidatemap;
214
215   TodoMap     addProvided;
216   TodoMap     addMultiProvided;
217
218   sat::Pool::instance().prepare();  
219
220   Target_Ptr target;
221   try {
222         target = getZYpp()->target();
223   }
224   catch( const Exception & excpt_r) {
225         ERR << "Huh, no target ?";
226         ZYPP_CAUGHT(excpt_r);
227         if (!_testing) return;          // can't continue without target
228         MIL << "Running in test mode, continuing without target" << endl;
229   }
230   MIL << "target at " << target << endl;
231
232   MIL << "doUpgrade start... "
233     << "(delete_unmaintained:" << (opt_stats_r.delete_unmaintained?"yes":"no") << ")"
234     << "(silent_downgrades:" << (opt_stats_r.silent_downgrades?"yes":"no") << ")"
235     << "(keep_installed_patches:" << (opt_stats_r.keep_installed_patches?"yes":"no") << ")"
236     << endl;
237
238   // create a testcase for the updating system
239   Testcase testcase("/var/log/updateTestcase");
240   testcase.createTestcase (*this, true, false); // create pool, do not solve
241
242   _update_items.clear();
243   {
244     UpgradeOptions opts( opt_stats_r );
245     opt_stats_r = UpgradeStatistics();
246     (UpgradeOptions&)opt_stats_r = opts;
247   }
248
249   /* Find upgrade candidates for each package.  */
250
251   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
252     PoolItem item = *it;
253     PoolItem candidate;
254     PoolItem installed;
255
256     if ( item.status().isToBeUninstalled() ) {
257       MIL << "doUpgrade available: SKIP to delete " << item << endl;
258       ++opt_stats_r.pre_todel;
259       continue;
260     }
261     if ( item.status().isLocked() ) {
262       MIL << "doUpgrade available: SKIP locked " << item << endl;
263       if ( item.status().staysInstalled() ) {
264         ++opt_stats_r.pre_nocand;
265       }
266       continue;
267     }
268
269     if ( item.status().staysInstalled() ) {     // installed item
270       installed = item;
271       CandidateMap::const_iterator cand_it = candidatemap.find( installed );
272       if (cand_it != candidatemap.end()) {
273         candidate = cand_it->second;                            // found candidate already
274       }
275       else {
276         candidate = Helper::findUpdateItem( _pool, installed ); // find 'best' upgrade candidate
277       }
278       if (!candidate) {
279         MIL << "doUpgrade available: SKIP no candidate for " << installed << endl;
280         ++opt_stats_r.pre_nocand;
281         continue;
282       }
283       if (candidate.status().isSeen()) {                        // seen already
284         candidate.status().setSeen(true);
285         continue;
286       }
287       candidate.status().setSeen(true);                         // mark as seen
288       candidatemap[installed] = candidate;
289     }
290     else {                                      // assume Uninstalled
291       if (item.status().isSeen()) {                             // seen already
292         item.status().setSeen(true);
293         continue;
294       }
295       candidate = item;
296       candidate.status().setSeen(true);                         // mark as seen
297       installed = Helper::findInstalledItem( _pool, candidate );
298       if (installed) {                                          // check if we already have an installed
299         if ( installed.status().isLocked() ) {
300           MIL << "doUpgrade available: SKIP candidate " << candidate << ", locked " << installed << endl;
301           continue;
302         }
303
304         if ( !VendorAttr::instance().equivalent(installed->vendor(), candidate->vendor()) )
305         {
306             MIL << "Discarding '" << candidate << "' from vendor '"
307                 << candidate->vendor() << "' different to installed '"
308                 << installed->vendor() << "' vendor." << endl;
309             continue;
310         }
311
312         CandidateMap::const_iterator cand_it = candidatemap.find( installed );
313         if (cand_it == candidatemap.end()                                               // not in map yet
314             || (cand_it->second->arch().compare( candidate->arch() ) < 0)               // or the new has better architecture
315             || ((cand_it->second->arch().compare( candidate->arch() ) == 0)             // or the new has the same architecture
316                 && (cand_it->second->edition().compare( candidate->edition() ) < 0))    //   and a better edition (-> 157501)
317             )
318         {
319             candidatemap[installed] = candidate;                                // put it in !
320         }
321       }
322     }
323
324     ++opt_stats_r.pre_avcand;
325   } // iterate over the complete pool
326
327   // reset all seen (for next run)
328   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
329         it->status().setSeen( false );
330   }
331
332   MIL << "doUpgrade: " << opt_stats_r.pre_todel  << " packages tagged to delete" << endl;
333   MIL << "doUpgrade: " << opt_stats_r.pre_nocand << " packages without candidate (foreign, replaced or dropped)" << endl;
334   MIL << "doUpgrade: " << opt_stats_r.pre_avcand << " packages available for update" << endl;
335
336   ///////////////////////////////////////////////////////////////////
337   // Now iterate installed packages, not selected to delete, and
338   // figure out what might be an appropriate replacement. Current
339   // packages state is changed immediately. Additional packages are
340   // reported but set to install later.
341   ///////////////////////////////////////////////////////////////////
342   MIL << "doUpgrade pass 1..." << endl;
343
344   for ( ResPool::const_iterator it = _pool.begin(); it != _pool.end(); ++it ) {
345
346     PoolItem installed(*it);
347     ResStatus status (installed.status());
348
349     if ( ! status.staysInstalled() ) {
350       continue;
351     }
352     ++opt_stats_r.chk_installed_total;
353
354     if ( status.transacts() ) {                                 // we know its installed, if it transacts also
355       MIL << "SKIP to delete: " << installed.resolvable() << endl;      // it'll be deleted
356       ++opt_stats_r.chk_already_todel;
357       continue;
358     }
359
360     if ( installed.status().isLocked() ) {                      // skip locked
361       MIL << "SKIP taboo: " << installed << endl;
362       ++opt_stats_r.chk_is_taboo;
363       _update_items.push_back( installed );                     // remember in problem list
364       continue;
365     }
366
367     if ( isKind<Patch>(installed.resolvable())
368          || isKind<Atom>(installed.resolvable())
369          || isKind<Script>(installed.resolvable())
370          || isKind<Message>(installed.resolvable()) )
371       {
372         if ( ! opt_stats_r.keep_installed_patches )
373           {
374             if ( isKind<Patch>(installed.resolvable()) )
375               MIL << "OUTDATED Patch: " << installed << endl;
376             installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
377           }
378         else
379           {
380             if ( isKind<Patch>(installed.resolvable()) )
381               MIL << "SKIP Patch: " << installed << endl;
382           }
383         continue;
384       }
385
386     CandidateMap::iterator cand_it = candidatemap.find( installed );
387
388     bool probably_dropped = false;
389
390     MIL << "REPLACEMENT FOR " << installed << endl;
391     ///////////////////////////////////////////////////////////////////
392     // figure out replacement
393     ///////////////////////////////////////////////////////////////////
394     if ( cand_it != candidatemap.end() ) {
395
396       PoolItem candidate (cand_it->second);
397
398       if ( ! candidate.status().isToBeInstalled() ) {
399         int cmp = installed->edition().compare( candidate->edition() );
400         if ( cmp < 0 ) {   // new edition
401           setForInstallation (_pool,candidate);
402           MIL << " ==> INSTALL (new version): " << candidate << endl;
403           ++opt_stats_r.chk_to_update;
404         } else {                                                        // older or equal edition
405           // check whether to downgrade:
406
407           if (cmp == 0                                                  // equal
408               || !downgrade_allowed( installed, candidate,
409                                      opt_stats_r.silent_downgrades) )   //  or downgrade not allowed
410           {
411             MIL << " ==> (keep installed)" << candidate << endl;        // keep installed
412             ++opt_stats_r.chk_to_keep_installed;
413           } else {// older and downgrade allowed
414             setForInstallation (_pool, candidate);
415             MIL << " ==> INSTALL (SuSE version downgrade): " << candidate << endl;
416             ++opt_stats_r.chk_to_downgrade;
417           }
418         }
419       } else {
420         MIL << " ==> INSTALL (preselected): " << candidate << endl;
421         ++opt_stats_r.chk_already_toins;
422       }
423
424     }
425     else {              // no candidate
426
427       // replaced or dropped (anyway there's no candidate for this!)
428       // If unique provides exists check if obsoleted (replaced).
429       // Remember new package for 2nd pass.
430
431       Capability installedCap( installed->name(), Rel::EQ, installed->edition(), installed->kind());
432       // find ALL providers
433       PoolItemList possibleProviders = _satResolver->whoProvides (installedCap);
434
435       // find best available providers for installed name
436       typedef map<string, PoolItem> FindMap;
437       FindMap providersMap;             // the best providers which matched
438       bool otherVendorFound = false;
439       for (PoolItemList::const_iterator iter = possibleProviders.begin(); iter != possibleProviders.end(); iter++) {
440           PoolItem provider = *iter;
441           if ( !VendorAttr::instance().equivalent(provider->vendor(), installed->vendor()) )
442           {
443               MIL << "Discarding '" << provider << "' from vendor '"
444                   << provider->vendor() << "' different to uninstalled '"
445                   << installed->vendor() << "' vendor." << endl;
446               otherVendorFound = true;
447           } else if ( provider.status().isToBeUninstalled() ) {
448               MIL << "  IGNORE relation match (package is tagged to delete): " << provider << endl;
449           }
450           else {
451               FindMap::iterator it = providersMap.find( provider->name() );
452
453               if (it != providersMap.end()) {                           // provider with same name found
454                   if (provider.status().isToBeInstalled()
455                       || it->second.status().isToBeInstalled()) {
456
457                       if (provider.status().isToBeInstalled()
458                           && it->second.status().isToBeInstalled()) {
459                           ERR << "only one should be set for installation: " << it->second << "; " << provider << endl;
460                       } else {
461                           if (provider.status().isToBeInstalled()) {
462                               it->second = provider; // take thatone which is already set for installation
463                           }
464                       }
465                   } else {
466                       // not the same --> find better provider
467                       int cmp = it->second->arch().compare( provider->arch() );
468                       if (cmp < 0) {                                            // new provider has better arch
469                           it->second = provider;
470                       }
471                       else if (cmp == 0) {                                      // new provider has equal arch
472                           if (it->second->edition().compare( provider->edition() ) < 0) {
473                               it->second = provider;                            // new provider has better edition
474                           }
475                       }
476                   }
477               }
478               else {
479                   providersMap[provider->name()] = provider;
480               }
481           }
482       }
483
484       _DEBUG("lookup " << providersMap.size() << " provides for installed " << installedCap);
485
486       // copy from map to set
487       PoolItemOrderSet providers;
488       for (FindMap::const_iterator mapit = providersMap.begin(); mapit != providersMap.end(); ++mapit) {
489         providers.insert( mapit->second );
490       }
491
492       switch ( providersMap.size() ) {
493       case 0:
494           if (otherVendorFound) {
495               MIL << " only resolvable with other vendor found ==> do nothing" << endl;
496           } else {
497               MIL << " ==> (dropped)" << endl;
498               probably_dropped = true;
499           }
500         break;
501       case 1:
502         addProvided[installed] = providers;
503         MIL << " ==> REPLACED by: " << (*providers.begin()) << endl;
504         // count stats later
505         // check obsoletes later
506         break;
507       default:
508         addMultiProvided[installed] = providers;
509         MIL << " ==> pass 2 (" << providers.size() << " times provided)" << endl;
510         // count stats later
511         // check obsoletes later
512         break;
513       }
514
515     }   // no candidate
516
517
518     ///////////////////////////////////////////////////////////////////
519     // now handle dropped package
520     ///////////////////////////////////////////////////////////////////
521
522     if ( probably_dropped ) {
523       if ( opt_stats_r.delete_unmaintained
524            && VendorAttr::instance().equivalent( installed->vendor(), "suse" ) ) {
525         installed.status().setToBeUninstalled( ResStatus::APPL_HIGH );
526       }
527       ++opt_stats_r.chk_dropped;
528       _update_items.push_back( installed );
529     }
530
531   } // pass 1 end
532
533   ///////////////////////////////////////////////////////////////////
534   // Now check the remembered packages and check non unique provided.
535   // Maybe one of them was somehow selected. Otherwise we have to guess
536   // one.
537   ///////////////////////////////////////////////////////////////////
538   MIL << "doUpgrade pass 2..." << endl;
539
540   // look at the ones with a single provide first
541
542   for ( TodoMap::iterator it = addProvided.begin(); it != addProvided.end(); ++it ) {
543
544     PoolItemOrderSet & tset( it->second );              // these are the providers (well, just one)
545
546     for ( PoolItemOrderSet::iterator sit = tset.begin(); sit != tset.end(); ++sit ) {
547       PoolItem provider (*sit);
548
549       if (setForInstallation (_pool, provider)) {
550         ++opt_stats_r.chk_replaced;
551       }
552
553       // needs installed
554
555       if ( doesObsoleteItem (provider, it->first ) ) {
556         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
557       }
558     }
559
560   }
561
562   // look at the ones with multiple providers
563
564   for ( TodoMap::iterator it = addMultiProvided.begin(); it != addMultiProvided.end(); ++it ) {
565     MIL << "GET ONE OUT OF " << it->second.size() << " for " << it->first << endl;
566
567     PoolItem guess;
568     PoolItemOrderSet & gset( it->second );
569
570     for ( PoolItemOrderSet::iterator git = gset.begin(); git != gset.end(); ++git ) {
571         PoolItem item (*git);
572
573         if (git == gset.begin())                // default to first of set; the set is ordered, first is the best
574             guess = item;
575
576         if ( item.status().isToBeInstalled()) {
577             MIL << " ==> (pass 2: meanwhile set to install): " << item << endl;
578             if ( ! doesObsoleteItem (item, it->first ) ) {
579                 it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
580             }
581             guess = PoolItem();
582             break;
583         } else {
584             // Be prepared to guess.
585             // Most common situation for guessing is something like:
586             //   qt-devel
587             //   qt-devel-experimental
588             //   qt-devel-japanese
589             // That's why currently the shortest package name wins.
590             if ( !guess || guess->name().size() > item->name().size() ) {
591                 guess = item;
592             }
593         }
594     }
595
596     if ( guess ) {
597         // Checking if the selected provider depends on language, if yes try to find out the
598         // correct language package
599         bool requested_locale_match = false;
600         Capabilities freshens( guess->dep( Dep::FRESHENS ) );
601
602         // is this a language package ?
603         for (Capabilities::const_iterator cit = freshens.begin(); cit != freshens.end(); ++cit) {
604             string citName = cit->asString();
605             if (citName.length() > 7 &&  citName.compare(0, 7, "locale(") == 0) { // is a language dependency
606                 requested_locale_match = true;
607                 break;
608             }
609         }
610
611         if (requested_locale_match) {
612             // searching the best language
613             PoolItemOrderSet & gset( it->second );
614             requested_locale_match = false;
615
616             for ( PoolItemOrderSet::iterator git = gset.begin(); git != gset.end(); ++git ) {
617                 PoolItem item (*git);
618
619                 if ( item.status().isToBeInstalled()) {
620                     MIL << " ==> (pass 2: meanwhile set to install): " << item << endl;
621                     if ( ! doesObsoleteItem (item, it->first ) ) {
622                         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
623                     }
624                     guess = PoolItem();
625                     break;
626                 } else {
627                     freshens = item->dep( Dep::FRESHENS );
628                     ZYpp::Ptr z = zypp::getZYpp();
629                     ZYpp::LocaleSet requested_locales = z->getRequestedLocales();
630
631                     // try to find a match of the locale freshens with one of the requested locales
632
633                     for (Capabilities::const_iterator cit = freshens.begin(); cit != freshens.end(); ++cit) {
634                         string citName = cit->asString();
635                         if (citName.length() > 7 &&  citName.compare(0, 7, "locale(") == 0) { // is a language dependency
636                             string loc = cit->index();
637                             MIL << "Look for language fallback " << loc << ":" << item << endl;
638                             if (requested_locales.find( Locale( loc ) ) != requested_locales.end()) {
639                                 MIL << "Locale '" << loc << "' is requested" << endl;
640                                 requested_locale_match = true;
641                                 guess = item;
642                                 break;
643                             }
644                         }
645                     }
646                 }
647                 if (requested_locale_match) break;
648             }
649         }
650     }
651
652     if ( guess ) {
653       setForInstallation (_pool, guess);
654       MIL << " ==> REPLACED by: (pass 2: guessed): " << guess << endl;
655       if ( ! doesObsoleteItem (guess, it->first ) ) {
656         it->first.status().setToBeUninstalled( ResStatus::APPL_HIGH );
657       }
658       ++opt_stats_r.chk_replaced_guessed;
659     }
660   }
661
662   ///////////////////////////////////////////////////////////////////
663   // done
664   ///////////////////////////////////////////////////////////////////
665   MIL << opt_stats_r << endl;
666
667   // Setting Resolver to upgrade mode
668   _upgradeMode = true;
669 }
670
671 ///////////////////////////////////////////////////////////////////
672     };// namespace detail
673     /////////////////////////////////////////////////////////////////////
674     /////////////////////////////////////////////////////////////////////
675   };// namespace solver
676   ///////////////////////////////////////////////////////////////////////
677   ///////////////////////////////////////////////////////////////////////
678 };// namespace zypp
679 /////////////////////////////////////////////////////////////////////////
680
681