7e17ad08889144c39b8f5364e4ecafb52b18a15f
[platform/upstream/libzypp.git] / zypp / ZConfig.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/ZConfig.cc
10  *
11 */
12 extern "C"
13 {
14 #include <sys/utsname.h>
15 #include <unistd.h>
16 }
17 #include <iostream>
18 #include <fstream>
19 #include "zypp/base/Logger.h"
20 #include "zypp/base/IOStream.h"
21 #include "zypp/base/InputStream.h"
22 #include "zypp/base/String.h"
23
24 #include "zypp/ZConfig.h"
25 #include "zypp/ZYppFactory.h"
26 #include "zypp/PathInfo.h"
27 #include "zypp/parser/IniDict.h"
28
29 using namespace std;
30 using namespace zypp::filesystem;
31 using namespace zypp::parser;
32
33 #undef ZYPP_BASE_LOGGER_LOGGROUP
34 #define ZYPP_BASE_LOGGER_LOGGROUP "zconfig"
35
36 ///////////////////////////////////////////////////////////////////
37 namespace zypp
38 { /////////////////////////////////////////////////////////////////
39
40   ///////////////////////////////////////////////////////////////////
41   namespace
42   { /////////////////////////////////////////////////////////////////
43
44     /** Determine system architecture evaluating \c uname and \c /proc/cpuinfo.
45     */
46     Arch _autodetectSystemArchitecture()
47     {
48       struct ::utsname buf;
49       if ( ::uname( &buf ) < 0 )
50       {
51         ERR << "Can't determine system architecture" << endl;
52         return Arch_noarch;
53       }
54
55       Arch architecture( buf.machine );
56       MIL << "Uname architecture is '" << buf.machine << "'" << endl;
57
58       // some CPUs report i686 but dont implement cx8 and cmov
59       // check for both flags in /proc/cpuinfo and downgrade
60       // to i586 if either is missing (cf bug #18885)
61       if ( architecture == Arch_i686 )
62       {
63         std::ifstream cpuinfo( "/proc/cpuinfo" );
64         if ( cpuinfo )
65         {
66           for( iostr::EachLine in( cpuinfo ); in; in.next() )
67           {
68             if ( str::hasPrefix( *in, "flags" ) )
69             {
70               if (    in->find( "cx8" ) == std::string::npos
71                    || in->find( "cmov" ) == std::string::npos )
72               {
73                 architecture = Arch_i586;
74                 WAR << "CPU lacks 'cx8' or 'cmov': architecture downgraded to '" << architecture << "'" << endl;
75               }
76               break;
77             }
78           }
79         }
80         else
81         {
82           ERR << "Cant open " << PathInfo("/proc/cpuinfo") << endl;
83         }
84       }
85       return architecture;
86     }
87
88      /** The locale to be used for texts and messages.
89      *
90      * For the encoding to be used the preference is
91      *
92      *    LC_ALL, LC_CTYPE, LANG
93      *
94      * For the language of the messages to be used, the preference is
95      *
96      *    LANGUAGE, LC_ALL, LC_MESSAGES, LANG
97      *
98      * Note that LANGUAGE can contain more than one locale name, it can be
99      * a list of locale names like for example
100      *
101      *    LANGUAGE=ja_JP.UTF-8:de_DE.UTF-8:fr_FR.UTF-8
102
103      * \todo Support dynamic fallbacklists defined by LANGUAGE
104      */
105     Locale _autodetectTextLocale()
106     {
107       Locale ret( "en" );
108       const char * envlist[] = { "LC_ALL", "LC_MESSAGES", "LANG", NULL };
109       for ( const char ** envvar = envlist; *envvar; ++envvar )
110       {
111         const char * envlang = getenv( *envvar );
112         if ( envlang )
113         {
114           std::string envstr( envlang );
115           if ( envstr != "POSIX" && envstr != "C" )
116           {
117             Locale lang( envstr );
118             if ( ! lang.code().empty() )
119             {
120               MIL << "Found " << *envvar << "=" << envstr << endl;
121               ret = lang;
122               break;
123             }
124           }
125         }
126       }
127       MIL << "Default text locale is '" << ret << "'" << endl;
128 #warning HACK AROUND BOOST_TEST_CATCH_SYSTEM_ERRORS
129       setenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS", "no", 1 );
130       return ret;
131     }
132
133    /////////////////////////////////////////////////////////////////
134   } // namespace zypp
135   ///////////////////////////////////////////////////////////////////
136
137   /** Mutable option with initial value. */
138   template<class _Tp, _Tp _Initial>
139       struct Option
140       {
141         typedef _Tp value_type;
142
143         /** Default ctor sets _Initial. */
144         Option()
145           : _val( _Initial )
146         {}
147
148         /** Get the value.  */
149         value_type get() const
150         { return _val; }
151
152         /** Set a new value.  */
153         void set( const value_type & newval_r )
154         { _val = newval_r; }
155
156         private:
157           value_type _val;
158       };
159
160   /** Mutable option with initial value also remembering a config value. */
161   template<class _Tp, _Tp _Initial>
162       struct DefaultOption : public Option<_Tp,_Initial>
163       {
164         typedef _Tp                  value_type;
165         typedef Option<_Tp,_Initial> option_type;
166
167         /** Reset value to the current default. */
168         void restoreToDefault()
169         { this->set( _default.get() ); }
170
171         /** Reset value to a new default. */
172         void restoreToDefault( const value_type & newval_r )
173         { setDefault( newval_r ); restoreToDefault(); }
174
175         /** Get the current default value. */
176         value_type getDefault() const
177         { return _default.get(); }
178
179         /** Set a new default value. */
180         void setDefault( const value_type & newval_r )
181         { _default.set( newval_r ); }
182
183         private:
184           option_type _default;
185       };
186
187   ///////////////////////////////////////////////////////////////////
188   //
189   //    CLASS NAME : ZConfig::Impl
190   //
191   /** ZConfig implementation.
192    * \todo Enrich section and entry definition by some comment
193    * (including the default setting and provide some method to
194    * write this into a sample zypp.conf.
195   */
196   class ZConfig::Impl
197   {
198     public:
199       Impl( const Pathname & override_r = Pathname() )
200         : _parsedZyppConf               ( override_r )
201         , cfg_arch                      ( defaultSystemArchitecture() )
202         , cfg_textLocale                ( defaultTextLocale() )
203         , repo_add_probe                ( false )
204         , repo_refresh_delay            ( 10 )
205         , download_use_deltarpm         ( true )
206         , download_use_deltarpm_always  ( false )
207         , download_max_concurrent_connections(2)
208         , download_min_download_speed(0)
209         , download_max_download_speed(0)
210         , download_max_silent_tries(5)
211         , apply_locks_file              ( true )
212
213       {
214         MIL << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
215         // override_r has higest prio
216         // ZYPP_CONF might override /etc/zypp/zypp.conf
217         if ( _parsedZyppConf.empty() )
218         {
219           const char *env_confpath = getenv( "ZYPP_CONF" );
220           _parsedZyppConf = env_confpath ? env_confpath : "/etc/zypp/zypp.conf";
221         }
222         else
223         {
224           // Inject this into ZConfig. Be shure this is
225           // allocated via new. See: reconfigureZConfig
226           INT << "Reconfigure to " << _parsedZyppConf << endl;
227           ZConfig::instance()._pimpl.reset( this );
228         }
229         if ( PathInfo(_parsedZyppConf).isExist() )
230         {
231           parser::IniDict dict( _parsedZyppConf );
232           for ( IniDict::section_const_iterator sit = dict.sectionsBegin();
233                 sit != dict.sectionsEnd();
234                 ++sit )
235           {
236             string section(*sit);
237             //MIL << section << endl;
238             for ( IniDict::entry_const_iterator it = dict.entriesBegin(*sit);
239                   it != dict.entriesEnd(*sit);
240                   ++it )
241             {
242               string entry(it->first);
243               string value(it->second);
244               //DBG << (*it).first << "=" << (*it).second << endl;
245               if ( section == "main" )
246               {
247                 if ( entry == "arch" )
248                 {
249                   Arch carch( value );
250                   if ( carch != cfg_arch )
251                   {
252                     WAR << "Overriding system architecture (" << cfg_arch << "): " << carch << endl;
253                     cfg_arch = carch;
254                   }
255                 }
256                 else if ( entry == "cachedir" )
257                 {
258                   cfg_cache_path = Pathname(value);
259                 }
260                 else if ( entry == "metadatadir" )
261                 {
262                   cfg_metadata_path = Pathname(value);
263                 }
264                 else if ( entry == "solvfilesdir" )
265                 {
266                   cfg_solvfiles_path = Pathname(value);
267                 }
268                 else if ( entry == "packagesdir" )
269                 {
270                   cfg_packages_path = Pathname(value);
271                 }
272                 else if ( entry == "configdir" )
273                 {
274                   cfg_config_path = Pathname(value);
275                 }
276                 else if ( entry == "reposdir" )
277                 {
278                   cfg_known_repos_path = Pathname(value);
279                 }
280                 else if ( entry == "servicesdir" )
281                 {
282                   cfg_known_services_path = Pathname(value);
283                 }
284                 else if ( entry == "repo.add.probe" )
285                 {
286                   repo_add_probe = str::strToBool( value, repo_add_probe );
287                 }
288                 else if ( entry == "repo.refresh.delay" )
289                 {
290                   str::strtonum(value, repo_refresh_delay);
291                 }
292                 else if ( entry == "download.use_deltarpm" )
293                 {
294                   download_use_deltarpm = str::strToBool( value, download_use_deltarpm );
295                 }
296                 else if ( entry == "download.use_deltarpm.always" )
297                 {
298                   download_use_deltarpm_always = str::strToBool( value, download_use_deltarpm_always );
299                 }
300                 else if ( entry == "download.media_preference" )
301                 {
302                   download_media_prefer_download.restoreToDefault( str::compareCI( value, "volatile" ) != 0 );
303                 }
304                 else if ( entry == "download.max_concurrent_connections" )
305                 {
306                   str::strtonum(value, download_max_concurrent_connections);
307                 }
308                 else if ( entry == "download.min_download_speed" )
309                 {
310                   str::strtonum(value, download_min_download_speed);
311                 }
312                 else if ( entry == "download.max_download_speed" )
313                 {
314                   str::strtonum(value, download_max_download_speed);
315                 }
316                 else if ( entry == "download.max_silent_tries" )
317                 {
318                   str::strtonum(value, download_max_silent_tries);
319                 }
320                 else if ( entry == "vendordir" )
321                 {
322                   cfg_vendor_path = Pathname(value);
323                 }
324                 else if ( entry == "productsdir" )
325                 {
326                   WAR << "Deprecated entry 'productsdir=': This locations is no longer used or supported." << endl;
327                   cfg_products_path = Pathname(value);
328                 }
329                 else if ( entry == "solver.onlyRequires" )
330                 {
331                   solver_onlyRequires.set( str::strToBool( value, solver_onlyRequires.get() ) );
332                 }
333                 else if ( entry == "solver.allowVendorChange" )
334                 {
335                   solver_allowVendorChange.set( str::strToBool( value, solver_allowVendorChange.get() ) );
336                 }
337                 else if ( entry == "solver.checkSystemFile" )
338                 {
339                   solver_checkSystemFile = Pathname(value);
340                 }
341                 else if ( entry == "multiversion" )
342                 {
343                   std::list<std::string> multi;
344                   str::split( value, back_inserter(multi), ", \t" );
345                   for ( std::list<string>::const_iterator it = multi.begin();
346                         it != multi.end(); it++) {
347                       multiversion.insert (IdString(*it));
348                   }
349                 }
350                 else if ( entry == "locksfile.path" )
351                 {
352                   locks_file = Pathname(value);
353                 }
354                 else if ( entry == "locksfile.apply" )
355                 {
356                   apply_locks_file = str::strToBool( value, apply_locks_file );
357                 }
358                 else if ( entry == "update.datadir" )
359                 {
360                   update_data_path = Pathname(value);
361                 }
362                 else if ( entry == "update.scriptsdir" )
363                 {
364                   update_scripts_path = Pathname(value);
365                 }
366                 else if ( entry == "update.messagessdir" )
367                 {
368                   update_messages_path = Pathname(value);
369                 }
370                 else if ( entry == "rpm.install.excludedocs" )
371                 {
372                   rpmInstallFlags.setFlag( target::rpm::RPMINST_EXCLUDEDOCS );
373                 }
374                 else if ( entry == "history.logfile" )
375                 {
376                   history_log_path = Pathname(value);
377                 }
378                 else if ( entry == "credentials.global.dir" )
379                 {
380                   credentials_global_dir_path = Pathname(value);
381                 }
382                 else if ( entry == "credentials.global.file" )
383                 {
384                   credentials_global_file_path = Pathname(value);
385                 }
386               }
387             }
388           }
389         }
390         else
391         {
392           MIL << _parsedZyppConf << " not found, using defaults instead." << endl;
393           _parsedZyppConf.extend( " (NOT FOUND)" );
394         }
395
396         // legacy:
397         if ( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) )
398         {
399           Arch carch( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) );
400           if ( carch != cfg_arch )
401           {
402             WAR << "ZYPP_TESTSUITE_FAKE_ARCH: Overriding system architecture (" << cfg_arch << "): " << carch << endl;
403             cfg_arch = carch;
404           }
405         }
406         MIL << "ZConfig singleton created." << endl;
407       }
408
409       ~Impl()
410       {}
411
412     public:
413     /** Remember any parsed zypp.conf. */
414     Pathname _parsedZyppConf;
415
416     Arch     cfg_arch;
417     Locale   cfg_textLocale;
418
419     Pathname cfg_cache_path;
420     Pathname cfg_metadata_path;
421     Pathname cfg_solvfiles_path;
422     Pathname cfg_packages_path;
423
424     Pathname cfg_config_path;
425     Pathname cfg_known_repos_path;
426     Pathname cfg_known_services_path;
427     Pathname cfg_vendor_path;
428     Pathname cfg_products_path;
429     Pathname locks_file;
430
431     Pathname update_data_path;
432     Pathname update_scripts_path;
433     Pathname update_messages_path;
434
435     bool repo_add_probe;
436     unsigned repo_refresh_delay;
437
438     bool download_use_deltarpm;
439     bool download_use_deltarpm_always;
440     DefaultOption<bool,true> download_media_prefer_download;
441
442     int download_max_concurrent_connections;
443     int download_min_download_speed;
444     int download_max_download_speed;
445     int download_max_silent_tries;
446
447     Option<bool,false> solver_onlyRequires;
448     Option<bool,false> solver_allowVendorChange;
449     Pathname solver_checkSystemFile;
450
451     std::set<IdString> multiversion;
452
453     bool apply_locks_file;
454
455     target::rpm::RpmInstFlags rpmInstallFlags;
456
457     Pathname history_log_path;
458     Pathname credentials_global_dir_path;
459     Pathname credentials_global_file_path;
460   };
461   ///////////////////////////////////////////////////////////////////
462
463   // Backdoor to redirect ZConfig from within the running
464   // TEST-application. HANDLE WITH CARE!
465   void reconfigureZConfig( const Pathname & override_r )
466   {
467     // ctor puts itself unter smart pointer control.
468     new ZConfig::Impl( override_r );
469   }
470
471   ///////////////////////////////////////////////////////////////////
472   //
473   //    METHOD NAME : ZConfig::instance
474   //    METHOD TYPE : ZConfig &
475   //
476   ZConfig & ZConfig::instance()
477   {
478     static ZConfig _instance; // The singleton
479     return _instance;
480   }
481
482   ///////////////////////////////////////////////////////////////////
483   //
484   //    METHOD NAME : ZConfig::ZConfig
485   //    METHOD TYPE : Ctor
486   //
487   ZConfig::ZConfig()
488   : _pimpl( new Impl )
489   {
490     about( MIL);
491   }
492
493   ///////////////////////////////////////////////////////////////////
494   //
495   //    METHOD NAME : ZConfig::~ZConfig
496   //    METHOD TYPE : Dtor
497   //
498   ZConfig::~ZConfig( )
499   {}
500
501   ///////////////////////////////////////////////////////////////////
502   //
503   // system architecture
504   //
505   ///////////////////////////////////////////////////////////////////
506
507   Arch ZConfig::defaultSystemArchitecture()
508   {
509     static Arch _val( _autodetectSystemArchitecture() );
510     return _val;
511   }
512
513   Arch ZConfig::systemArchitecture() const
514   { return _pimpl->cfg_arch; }
515
516   void ZConfig::setSystemArchitecture( const Arch & arch_r )
517   {
518     if ( arch_r != _pimpl->cfg_arch )
519     {
520       WAR << "Overriding system architecture (" << _pimpl->cfg_arch << "): " << arch_r << endl;
521       _pimpl->cfg_arch = arch_r;
522     }
523   }
524
525   ///////////////////////////////////////////////////////////////////
526   //
527   // text locale
528   //
529   ///////////////////////////////////////////////////////////////////
530
531   Locale ZConfig::defaultTextLocale()
532   {
533     static Locale _val( _autodetectTextLocale() );
534     return _val;
535   }
536
537   Locale ZConfig::textLocale() const
538   { return _pimpl->cfg_textLocale; }
539
540   void ZConfig::setTextLocale( const Locale & locale_r )
541   {
542     if ( locale_r != _pimpl->cfg_textLocale )
543     {
544       WAR << "Overriding text locale (" << _pimpl->cfg_textLocale << "): " << locale_r << endl;
545       _pimpl->cfg_textLocale = locale_r;
546     }
547   }
548
549   ///////////////////////////////////////////////////////////////////
550
551   Pathname ZConfig::repoCachePath() const
552   {
553     return ( _pimpl->cfg_cache_path.empty()
554         ? Pathname("/var/cache/zypp") : _pimpl->cfg_cache_path );
555   }
556
557   Pathname ZConfig::repoMetadataPath() const
558   {
559     return ( _pimpl->cfg_metadata_path.empty()
560         ? (repoCachePath()/"raw") : _pimpl->cfg_metadata_path );
561   }
562
563   Pathname ZConfig::repoSolvfilesPath() const
564   {
565     return ( _pimpl->cfg_solvfiles_path.empty()
566         ? (repoCachePath()/"solv") : _pimpl->cfg_solvfiles_path );
567   }
568
569   Pathname ZConfig::repoPackagesPath() const
570   {
571     return ( _pimpl->cfg_packages_path.empty()
572         ? (repoCachePath()/"packages") : _pimpl->cfg_packages_path );
573   }
574
575   ///////////////////////////////////////////////////////////////////
576
577   Pathname ZConfig::configPath() const
578   {
579     return ( _pimpl->cfg_config_path.empty()
580         ? Pathname("/etc/zypp") : _pimpl->cfg_config_path );
581   }
582
583   Pathname ZConfig::knownReposPath() const
584   {
585     return ( _pimpl->cfg_known_repos_path.empty()
586         ? (configPath()/"repos.d") : _pimpl->cfg_known_repos_path );
587   }
588
589   Pathname ZConfig::knownServicesPath() const
590   {
591     return ( _pimpl->cfg_known_services_path.empty()
592         ? (configPath()/"services.d") : _pimpl->cfg_known_repos_path );
593   }
594
595   Pathname ZConfig::vendorPath() const
596   {
597     return ( _pimpl->cfg_vendor_path.empty()
598         ? (configPath()/"vendors.d") : _pimpl->cfg_vendor_path );
599   }
600
601   Pathname ZConfig::productsPath() const
602   {
603     return ( _pimpl->cfg_products_path.empty()
604         ? (configPath()/"products.d") : _pimpl->cfg_products_path );
605   }
606
607   Pathname ZConfig::locksFile() const
608   {
609     return ( _pimpl->locks_file.empty()
610         ? (configPath()/"locks") : _pimpl->locks_file );
611   }
612
613   ///////////////////////////////////////////////////////////////////
614
615   bool ZConfig::repo_add_probe() const
616   {
617     return _pimpl->repo_add_probe;
618   }
619
620   unsigned ZConfig::repo_refresh_delay() const
621   {
622     return _pimpl->repo_refresh_delay;
623   }
624
625   bool ZConfig::download_use_deltarpm() const
626   { return _pimpl->download_use_deltarpm; }
627
628   bool ZConfig::download_use_deltarpm_always() const
629   { return download_use_deltarpm() && _pimpl->download_use_deltarpm_always; }
630
631   bool ZConfig::download_media_prefer_download() const
632   { return _pimpl->download_media_prefer_download.get(); }
633
634   void ZConfig::set_download_media_prefer_download( bool yesno_r )
635   { _pimpl->download_media_prefer_download.set( yesno_r ); }
636
637   void ZConfig::set_default_download_media_prefer_download()
638   { _pimpl->download_media_prefer_download.restoreToDefault(); }
639
640   long ZConfig::download_max_concurrent_connections() const
641   { return _pimpl->download_max_concurrent_connections; }
642
643   long ZConfig::download_min_download_speed() const
644   { return _pimpl->download_min_download_speed; }
645
646   long ZConfig::download_max_download_speed() const
647   { return _pimpl->download_max_download_speed; }
648
649   long ZConfig::download_max_silent_tries() const
650   { return _pimpl->download_max_silent_tries; }
651
652   bool ZConfig::solver_onlyRequires() const
653   { return _pimpl->solver_onlyRequires.get(); }
654
655   bool ZConfig::solver_allowVendorChange() const
656   { return _pimpl->solver_allowVendorChange.get(); }
657
658   Pathname ZConfig::solver_checkSystemFile() const
659   { return ( _pimpl->solver_checkSystemFile.empty()
660       ? (configPath()/"systemCheck") : _pimpl->solver_checkSystemFile ); }
661
662   std::set<IdString> ZConfig::multiversion() const
663   { return _pimpl->multiversion; }
664
665   void ZConfig::addMultiversion(std::string &name)
666   { _pimpl->multiversion.insert(IdString(name)); }
667
668   bool ZConfig::removeMultiversion(std::string &name)
669   { return _pimpl->multiversion.erase(IdString(name)); }
670
671   bool ZConfig::apply_locks_file() const
672   { return _pimpl->apply_locks_file; }
673
674   Pathname ZConfig::update_dataPath() const
675   {
676     return ( _pimpl->update_data_path.empty()
677         ? Pathname("/var/adm") : _pimpl->update_data_path );
678   }
679
680   Pathname ZConfig::update_messagesPath() const
681   {
682     return ( _pimpl->update_messages_path.empty()
683              ? Pathname(update_dataPath()/"update-messages") : _pimpl->update_messages_path );
684   }
685
686
687   Pathname ZConfig::update_scriptsPath() const
688   {
689     return ( _pimpl->update_scripts_path.empty()
690              ? Pathname(update_dataPath()/"update-scripts") : _pimpl->update_scripts_path );
691   }
692
693   ///////////////////////////////////////////////////////////////////
694
695   target::rpm::RpmInstFlags ZConfig::rpmInstallFlags() const
696   { return _pimpl->rpmInstallFlags; }
697
698
699   Pathname ZConfig::historyLogFile() const
700   {
701     return ( _pimpl->history_log_path.empty() ?
702         Pathname("/var/log/zypp/history") : _pimpl->history_log_path );
703   }
704
705
706   Pathname ZConfig::credentialsGlobalDir() const
707   {
708     return ( _pimpl->credentials_global_dir_path.empty() ?
709         Pathname("/etc/zypp/credentials.d") : _pimpl->credentials_global_dir_path );
710   }
711
712   Pathname ZConfig::credentialsGlobalFile() const
713   {
714     return ( _pimpl->credentials_global_file_path.empty() ?
715         Pathname("/etc/zypp/credentials.cat") : _pimpl->credentials_global_file_path );
716   }
717
718   ///////////////////////////////////////////////////////////////////
719
720   std::ostream & ZConfig::about( std::ostream & str ) const
721   {
722     str << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
723     str << "zypp.conf: '" << _pimpl->_parsedZyppConf << "'" << endl;
724     str << "TextLocale: '" << textLocale() << "' (" << defaultTextLocale() << ")" << endl;
725     str << "SystemArchitecture: '" << systemArchitecture() << "' (" << defaultSystemArchitecture() << ")" << endl;
726     return str;
727   }
728
729   /////////////////////////////////////////////////////////////////
730 } // namespace zypp
731 ///////////////////////////////////////////////////////////////////