Imported Upstream version 16.0.0
[platform/upstream/libzypp.git] / zypp / RepoInfo.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/RepoInfo.cc
10  *
11 */
12 #include <iostream>
13 #include <vector>
14
15 #include "zypp/base/LogTools.h"
16 #include "zypp/base/DefaultIntegral.h"
17 #include "zypp/parser/xml/XmlEscape.h"
18
19 #include "zypp/RepoInfo.h"
20 #include "zypp/TriBool.h"
21 #include "zypp/Pathname.h"
22 #include "zypp/ZConfig.h"
23 #include "zypp/repo/RepoMirrorList.h"
24 #include "zypp/ExternalProgram.h"
25 #include "zypp/media/MediaAccess.h"
26
27 #include "zypp/base/IOStream.h"
28 #include "zypp/base/InputStream.h"
29 #include "zypp/parser/xml/Reader.h"
30
31 using std::endl;
32 using zypp::xml::escape;
33
34 ///////////////////////////////////////////////////////////////////
35 namespace zypp
36 { /////////////////////////////////////////////////////////////////
37
38   ///////////////////////////////////////////////////////////////////
39   //
40   //    CLASS NAME : RepoInfo::Impl
41   //
42   /** RepoInfo implementation. */
43   struct RepoInfo::Impl
44   {
45     Impl()
46       : _gpgCheck( indeterminate )
47       , _repoGpgCheck( indeterminate )
48       , _pkgGpgCheck( indeterminate )
49       , _validRepoSignature( indeterminate )
50       , keeppackages(indeterminate)
51       , _mirrorListForceMetalink(false)
52       , type(repo::RepoType::NONE_e)
53       , emptybaseurls(false)
54     {}
55
56     ~Impl()
57     {}
58
59   public:
60     static const unsigned defaultPriority = 99;
61     static const unsigned noPriority = unsigned(-1);
62
63     void setProbedType( const repo::RepoType & t ) const
64     {
65       if ( type == repo::RepoType::NONE
66            && t != repo::RepoType::NONE )
67       {
68         // lazy init!
69         const_cast<Impl*>(this)->type = t;
70       }
71     }
72
73   public:
74     Pathname licenseTgz() const
75     { return metadatapath.empty() ? Pathname() : metadatapath / path / "license.tar.gz"; }
76
77     const RepoVariablesReplacedUrlList & baseUrls() const
78     {
79       const Url & mlurl( _mirrorListUrl.transformed() );        // Variables replaced!
80       if ( _baseUrls.empty() && ! mlurl.asString().empty() )
81       {
82         emptybaseurls = true;
83         DBG << "MetadataPath: " << metadatapath << endl;
84         repo::RepoMirrorList rmurls( mlurl, metadatapath, _mirrorListForceMetalink );
85         _baseUrls.raw().insert( _baseUrls.raw().end(), rmurls.getUrls().begin(), rmurls.getUrls().end() );
86       }
87       return _baseUrls;
88     }
89
90     RepoVariablesReplacedUrlList & baseUrls()
91     { return _baseUrls; }
92
93     bool baseurl2dump() const
94     { return !emptybaseurls && !_baseUrls.empty(); }
95
96
97     const std::set<std::string> & contentKeywords() const
98     { hasContent()/*init if not yet done*/; return _keywords.second; }
99
100     void addContent( const std::string & keyword_r )
101     { _keywords.second.insert( keyword_r ); if ( ! hasContent() ) _keywords.first = true; }
102
103     bool hasContent() const
104     {
105       if ( !_keywords.first && ! metadatapath.empty() )
106       {
107         // HACK directly check master index file until RepoManager offers
108         // some content probing and zypper uses it.
109         /////////////////////////////////////////////////////////////////
110         MIL << "Empty keywords...." << metadatapath << endl;
111         Pathname master;
112         if ( PathInfo( (master=metadatapath/"/repodata/repomd.xml") ).isFile() )
113         {
114           //MIL << "GO repomd.." << endl;
115           xml::Reader reader( master );
116           while ( reader.seekToNode( 2, "content" ) )
117           {
118             _keywords.second.insert( reader.nodeText().asString() );
119             reader.seekToEndNode( 2, "content" );
120           }
121           _keywords.first = true;       // valid content in _keywords even if empty
122         }
123         else if ( PathInfo( (master=metadatapath/"/content") ).isFile() )
124         {
125           //MIL << "GO content.." << endl;
126           iostr::forEachLine( InputStream( master ),
127                             [this]( int num_r, std::string line_r )->bool
128                             {
129                               if ( str::startsWith( line_r, "REPOKEYWORDS" ) )
130                               {
131                                 std::vector<std::string> words;
132                                 if ( str::split( line_r, std::back_inserter(words) ) > 1
133                                   && words[0].length() == 12 /*"REPOKEYWORDS"*/ )
134                                 {
135                                   this->_keywords.second.insert( ++words.begin(), words.end() );
136                                 }
137                                 return true; // mult. occurrances are ok.
138                               }
139                               return( ! str::startsWith( line_r, "META " ) );   // no need to parse into META section.
140                             } );
141           _keywords.first = true;       // valid content in _keywords even if empty
142         }
143         /////////////////////////////////////////////////////////////////
144       }
145       return _keywords.first;
146     }
147
148     bool hasContent( const std::string & keyword_r ) const
149     { return( hasContent() && _keywords.second.find( keyword_r ) != _keywords.second.end() ); }
150
151     /** Signature check result needs to be stored/retrieved from _metadatapath.
152      * Don't call them from outside validRepoSignature/setValidRepoSignature
153      */
154     //@{
155     TriBool internalValidRepoSignature() const
156     {
157       if ( ! indeterminate(_validRepoSignature) )               return _validRepoSignature;
158       // check metadata:
159       if ( ! metadatapath.empty() )
160       {
161         //TODO: a missing ".repo_gpgcheck" might be plaindir(no Downloader) or not yet refreshed signed repo!
162         TriBool linkval = triBoolFromPath( metadatapath / ".repo_gpgcheck" );
163         return linkval;
164       }
165       return indeterminate;
166     }
167
168     void internalSetValidRepoSignature( TriBool value_r )
169     {
170       if ( PathInfo(metadatapath).isDir() )
171       {
172         Pathname gpgcheckFile( metadatapath / ".repo_gpgcheck" );
173         if ( PathInfo(gpgcheckFile).isExist() )
174         {
175           TriBool linkval( indeterminate );
176           if ( triBoolFromPath( gpgcheckFile, linkval ) && linkval == value_r )
177             return;     // existing symlink fits value_r
178           else
179             filesystem::unlink( gpgcheckFile ); // will write a new one
180         }
181         filesystem::symlink( asString(value_r), gpgcheckFile );
182       }
183       _validRepoSignature = value_r;
184     }
185
186     bool triBoolFromPath( const Pathname & path_r, TriBool & ret_r ) const
187     {
188       static const Pathname truePath( "true" );
189       static const Pathname falsePath( "false" );
190       static const Pathname indeterminatePath( "indeterminate" );
191       Pathname linkval( filesystem::readlink( path_r ) );
192       bool known = true;
193       if ( linkval == truePath )
194         ret_r = true;
195       else if ( linkval == falsePath )
196         ret_r = false;
197       else if ( linkval == indeterminatePath )
198         ret_r = indeterminate;
199       else
200         known = false;
201       return known;
202     }
203
204     TriBool triBoolFromPath( const Pathname & path_r ) const
205     { TriBool ret(indeterminate); triBoolFromPath( path_r, ret ); return ret; }
206
207     //@}
208
209   public:
210     TriBool _gpgCheck;          ///< default gpgcheck behavior: Y/N/ZConf
211     TriBool _repoGpgCheck;      ///< need to check repo sign.: Y/N/(ZConf(Y/N/gpgCheck))
212     TriBool _pkgGpgCheck;       ///< need to check pkg sign.: Y/N/(ZConf(Y/N/gpgCheck && no valid repo sign.))
213   private:
214     TriBool _validRepoSignature;///< have  signed and valid repo metadata
215   public:
216     TriBool keeppackages;
217     RepoVariablesReplacedUrl _gpgKeyUrl;
218     RepoVariablesReplacedUrl _mirrorListUrl;
219     bool                     _mirrorListForceMetalink;
220     repo::RepoType type;
221     Pathname path;
222     std::string service;
223     std::string targetDistro;
224     Pathname metadatapath;
225     Pathname packagespath;
226     DefaultIntegral<unsigned,defaultPriority> priority;
227     mutable bool emptybaseurls;
228     repo::RepoVariablesUrlReplacer replacer;
229
230   private:
231     mutable RepoVariablesReplacedUrlList _baseUrls;
232     mutable std::pair<FalseBool, std::set<std::string> > _keywords;
233
234     friend Impl * rwcowClone<Impl>( const Impl * rhs );
235     /** clone for RWCOW_pointer */
236     Impl * clone() const
237     { return new Impl( *this ); }
238   };
239   ///////////////////////////////////////////////////////////////////
240
241   /** \relates RepoInfo::Impl Stream output */
242   inline std::ostream & operator<<( std::ostream & str, const RepoInfo::Impl & obj )
243   {
244     return str << "RepoInfo::Impl";
245   }
246
247   ///////////////////////////////////////////////////////////////////
248   //
249   //    CLASS NAME : RepoInfo
250   //
251   ///////////////////////////////////////////////////////////////////
252
253   const RepoInfo RepoInfo::noRepo;
254
255   RepoInfo::RepoInfo()
256   : _pimpl( new Impl() )
257   {}
258
259   RepoInfo::~RepoInfo()
260   {}
261
262   unsigned RepoInfo::priority() const
263   { return _pimpl->priority; }
264
265   unsigned RepoInfo::defaultPriority()
266   { return Impl::defaultPriority; }
267
268   unsigned RepoInfo::noPriority()
269   { return Impl::noPriority; }
270
271   void RepoInfo::setPriority( unsigned newval_r )
272   { _pimpl->priority = newval_r ? newval_r : Impl::defaultPriority; }
273
274
275   bool RepoInfo::gpgCheck() const
276   { return indeterminate(_pimpl->_gpgCheck) ? ZConfig::instance().gpgCheck() : (bool)_pimpl->_gpgCheck; }
277
278   void RepoInfo::setGpgCheck( TriBool value_r )
279   { _pimpl->_gpgCheck = value_r; }
280
281   void RepoInfo::setGpgCheck( bool value_r ) // deprecated legacy and for squid
282   { setGpgCheck( TriBool(value_r) ); }
283
284
285   bool RepoInfo::repoGpgCheck() const
286   {
287     if ( ! indeterminate(_pimpl->_repoGpgCheck) )               return _pimpl->_repoGpgCheck;
288     if ( ! indeterminate(ZConfig::instance().repoGpgCheck()) )  return ZConfig::instance().repoGpgCheck();
289     return gpgCheck();  // no preference: follow gpgCheck
290   }
291
292   void RepoInfo::setRepoGpgCheck( TriBool value_r )
293   { _pimpl->_repoGpgCheck = value_r; }
294
295
296   bool RepoInfo::pkgGpgCheck() const
297   {
298     if ( ! indeterminate(_pimpl->_pkgGpgCheck) )                return _pimpl->_pkgGpgCheck;
299     if ( ! indeterminate(ZConfig::instance().pkgGpgCheck()) )   return ZConfig::instance().pkgGpgCheck();
300     // no preference: follow gpgCheck and check package if repo signature not available or not checked
301     return gpgCheck() && ( !repoGpgCheck() || !(bool)validRepoSignature() );    // !(bool)TriBool ==> false or indeterminate
302   }
303
304   void RepoInfo::setPkgGpgCheck( TriBool value_r )
305   { _pimpl->_pkgGpgCheck = value_r; }
306
307   void RepoInfo::getRawGpgChecks( TriBool & g_r, TriBool & r_r, TriBool & p_r ) const
308   {
309     g_r = _pimpl->_gpgCheck;
310     r_r = _pimpl->_repoGpgCheck;
311     p_r = _pimpl->_pkgGpgCheck;
312   }
313
314   TriBool RepoInfo::validRepoSignature() const
315   {
316     TriBool ret = _pimpl->internalValidRepoSignature();
317     // keep indeterminate(=unsigned) but invalidate any signature if !repoGpgCheck
318     if ( !indeterminate(ret) && !repoGpgCheck() )
319       ret = false;
320     return ret;
321   }
322
323   void RepoInfo::setValidRepoSignature( TriBool value_r )
324   { _pimpl->internalSetValidRepoSignature( value_r ); }
325
326
327   void RepoInfo::setMirrorListUrl( const Url & url_r )  // Raw
328   { _pimpl->_mirrorListUrl.raw() = url_r; _pimpl->_mirrorListForceMetalink = false; }
329
330   void  RepoInfo::setMetalinkUrl( const Url & url_r )   // Raw
331   { _pimpl->_mirrorListUrl.raw() = url_r; _pimpl->_mirrorListForceMetalink = true; }
332
333   void RepoInfo::setGpgKeyUrl( const Url & url_r )
334   { _pimpl->_gpgKeyUrl.raw() = url_r; }
335
336   void RepoInfo::addBaseUrl( const Url & url_r )
337   {
338     for ( const auto & url : _pimpl->baseUrls().raw() ) // Raw unique!
339       if ( url == url_r )
340         return;
341     _pimpl->baseUrls().raw().push_back( url_r );
342   }
343
344   void RepoInfo::setBaseUrl( const Url & url_r )
345   {
346     _pimpl->baseUrls().raw().clear();
347     _pimpl->baseUrls().raw().push_back( url_r );
348   }
349
350   void RepoInfo::setBaseUrls( url_set urls )
351   { _pimpl->baseUrls().raw().swap( urls ); }
352
353   void RepoInfo::setPath( const Pathname &path )
354   { _pimpl->path = path; }
355
356   void RepoInfo::setType( const repo::RepoType &t )
357   { _pimpl->type = t; }
358
359   void RepoInfo::setProbedType( const repo::RepoType &t ) const
360   { _pimpl->setProbedType( t ); }
361
362
363   void RepoInfo::setMetadataPath( const Pathname &path )
364   { _pimpl->metadatapath = path; }
365
366   void RepoInfo::setPackagesPath( const Pathname &path )
367   { _pimpl->packagespath = path; }
368
369   void RepoInfo::setKeepPackages( bool keep )
370   { _pimpl->keeppackages = keep; }
371
372   void RepoInfo::setService( const std::string& name )
373   { _pimpl->service = name; }
374
375   void RepoInfo::setTargetDistribution( const std::string & targetDistribution )
376   { _pimpl->targetDistro = targetDistribution; }
377
378   bool RepoInfo::keepPackages() const
379   { return indeterminate(_pimpl->keeppackages) ? false : (bool)_pimpl->keeppackages; }
380
381   Pathname RepoInfo::metadataPath() const
382   { return _pimpl->metadatapath; }
383
384   Pathname RepoInfo::packagesPath() const
385   { return _pimpl->packagespath; }
386
387   repo::RepoType RepoInfo::type() const
388   { return _pimpl->type; }
389
390   Url RepoInfo::mirrorListUrl() const                   // Variables replaced!
391   { return _pimpl->_mirrorListUrl.transformed(); }
392
393   Url RepoInfo::rawMirrorListUrl() const                // Raw
394   { return _pimpl->_mirrorListUrl.raw(); }
395
396   Url RepoInfo::gpgKeyUrl() const                       // Variables replaced!
397   { return _pimpl->_gpgKeyUrl.transformed(); }
398
399   Url RepoInfo::rawGpgKeyUrl() const                    // Raw
400   {  return _pimpl->_gpgKeyUrl.raw(); }
401
402   RepoInfo::url_set RepoInfo::baseUrls() const          // Variables replaced!
403   { return _pimpl->baseUrls().transformed(); }
404
405   RepoInfo::url_set RepoInfo::rawBaseUrls() const       // Raw
406   { return _pimpl->baseUrls().raw(); }
407
408   Pathname RepoInfo::path() const
409   { return _pimpl->path; }
410
411   std::string RepoInfo::service() const
412   { return _pimpl->service; }
413
414   std::string RepoInfo::targetDistribution() const
415   { return _pimpl->targetDistro; }
416
417   Url RepoInfo::rawUrl() const
418   { return( _pimpl->baseUrls().empty() ? Url() : *_pimpl->baseUrls().rawBegin() ); }
419
420   RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const
421   { return _pimpl->baseUrls().transformedBegin(); }
422
423   RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const
424   { return _pimpl->baseUrls().transformedEnd(); }
425
426   RepoInfo::urls_size_type RepoInfo::baseUrlsSize() const
427   { return _pimpl->baseUrls().size(); }
428
429   bool RepoInfo::baseUrlsEmpty() const
430   { return _pimpl->baseUrls().empty(); }
431
432   bool RepoInfo::baseUrlSet() const
433   { return _pimpl->baseurl2dump(); }
434
435   const std::set<std::string> & RepoInfo::contentKeywords() const
436   { return _pimpl->contentKeywords(); }
437
438   void RepoInfo::addContent( const std::string & keyword_r )
439   { _pimpl->addContent( keyword_r ); }
440
441   bool RepoInfo::hasContent() const
442   { return _pimpl->hasContent(); }
443
444   bool RepoInfo::hasContent( const std::string & keyword_r ) const
445   { return _pimpl->hasContent( keyword_r ); }
446
447   ///////////////////////////////////////////////////////////////////
448
449   bool RepoInfo::hasLicense() const
450   {
451     Pathname licenseTgz( _pimpl->licenseTgz() );
452     return ! licenseTgz.empty() &&  PathInfo(licenseTgz).isFile();
453   }
454
455   bool RepoInfo::needToAcceptLicense() const
456   {
457     static const std::string noAcceptanceFile = "no-acceptance-needed\n";
458     bool accept = true;
459
460     Pathname licenseTgz( _pimpl->licenseTgz() );
461     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
462       return false;     // no licenses at all
463
464     ExternalProgram::Arguments cmd;
465     cmd.push_back( "tar" );
466     cmd.push_back( "-t" );
467     cmd.push_back( "-z" );
468     cmd.push_back( "-f" );
469     cmd.push_back( licenseTgz.asString() );
470
471     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
472     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
473     {
474       if ( output == noAcceptanceFile )
475       {
476         accept = false;
477       }
478     }
479     MIL << "License for " << name() << " has to be accepted: " << (accept?"true":"false" ) << endl;
480     return accept;
481   }
482
483   std::string RepoInfo::getLicense( const Locale & lang_r )
484   { return const_cast<const RepoInfo *>(this)->getLicense( lang_r );  }
485
486   std::string RepoInfo::getLicense( const Locale & lang_r ) const
487   {
488     LocaleSet avlocales( getLicenseLocales() );
489     if ( avlocales.empty() )
490       return std::string();
491
492     Locale getLang( Locale::bestMatch( avlocales, lang_r ) );
493     if ( !getLang && avlocales.find( Locale::noCode ) == avlocales.end() )
494     {
495       WAR << "License.tar.gz contains no fallback text! " << *this << endl;
496       // Using the fist locale instead of returning no text at all.
497       // So the user might recognize that there is a license, even if he
498       // can't read it.
499       getLang = *avlocales.begin();
500     }
501
502     // now extract the license file.
503     static const std::string licenseFileFallback( "license.txt" );
504     std::string licenseFile( !getLang ? licenseFileFallback
505                                       : str::form( "license.%s.txt", getLang.c_str() ) );
506
507     ExternalProgram::Arguments cmd;
508     cmd.push_back( "tar" );
509     cmd.push_back( "-x" );
510     cmd.push_back( "-z" );
511     cmd.push_back( "-O" );
512     cmd.push_back( "-f" );
513     cmd.push_back( _pimpl->licenseTgz().asString() ); // if it not exists, avlocales was empty.
514     cmd.push_back( licenseFile );
515
516     std::string ret;
517     ExternalProgram prog( cmd, ExternalProgram::Discard_Stderr );
518     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
519     {
520       ret += output;
521     }
522     prog.close();
523     return ret;
524   }
525
526   LocaleSet RepoInfo::getLicenseLocales() const
527   {
528     Pathname licenseTgz( _pimpl->licenseTgz() );
529     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
530       return LocaleSet();
531
532     ExternalProgram::Arguments cmd;
533     cmd.push_back( "tar" );
534     cmd.push_back( "-t" );
535     cmd.push_back( "-z" );
536     cmd.push_back( "-f" );
537     cmd.push_back( licenseTgz.asString() );
538
539     LocaleSet ret;
540     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
541     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
542     {
543       static const C_Str license( "license." );
544       static const C_Str dotTxt( ".txt\n" );
545       if ( str::hasPrefix( output, license ) && str::hasSuffix( output, dotTxt ) )
546       {
547         if ( output.size() <= license.size() +  dotTxt.size() ) // license.txt
548           ret.insert( Locale() );
549         else
550           ret.insert( Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) );
551       }
552     }
553     prog.close();
554     return ret;
555   }
556
557   ///////////////////////////////////////////////////////////////////
558
559   std::ostream & RepoInfo::dumpOn( std::ostream & str ) const
560   {
561     RepoInfoBase::dumpOn(str);
562     if ( _pimpl->baseurl2dump() )
563     {
564       for ( const auto & url : _pimpl->baseUrls().raw() )
565       {
566         str << "- url         : " << url << std::endl;
567       }
568     }
569
570     // print if non empty value
571     auto strif( [&] ( const std::string & tag_r, const std::string & value_r ) {
572       if ( ! value_r.empty() )
573         str << tag_r << value_r << std::endl;
574     });
575
576     strif( (_pimpl->_mirrorListForceMetalink ? "- metalink    : " : "- mirrorlist  : "), rawMirrorListUrl().asString() );
577     strif( "- path        : ", path().asString() );
578     str << "- type        : " << type() << std::endl;
579     str << "- priority    : " << priority() << std::endl;
580
581     // Yes No Default(Y) Default(N)
582 #define OUTS(T,B) ( indeterminate(T) ? (std::string("D(")+(B?"Y":"N")+")") : ((bool)T?"Y":"N") )
583     str << "- gpgcheck    : " << OUTS(_pimpl->_gpgCheck,gpgCheck())
584                               << " repo" << OUTS(_pimpl->_repoGpgCheck,repoGpgCheck())
585                               << " sig" << asString( validRepoSignature(), "?", "Y", "N" )
586                               << " pkg" << OUTS(_pimpl->_pkgGpgCheck,pkgGpgCheck())
587                               << std::endl;
588 #undef OUTS
589
590     strif( "- gpgkey      : ", rawGpgKeyUrl().asString() );
591
592     if ( ! indeterminate(_pimpl->keeppackages) )
593       str << "- keeppackages: " << keepPackages() << std::endl;
594
595     strif( "- service     : ", service() );
596     strif( "- targetdistro: ", targetDistribution() );
597     strif( "- metadataPath: ", metadataPath().asString() );
598     strif( "- packagesPath: ", packagesPath().asString() );
599
600     return str;
601   }
602
603   std::ostream & RepoInfo::dumpAsIniOn( std::ostream & str ) const
604   {
605     RepoInfoBase::dumpAsIniOn(str);
606
607     if ( _pimpl->baseurl2dump() )
608     {
609       str << "baseurl=";
610       std::string indent;
611       for ( const auto & url : _pimpl->baseUrls().raw() )
612       {
613         str << indent << url << endl;
614         if ( indent.empty() ) indent = "        ";      // "baseurl="
615       }
616     }
617
618     if ( ! _pimpl->path.empty() )
619       str << "path="<< path() << endl;
620
621     if ( ! (rawMirrorListUrl().asString().empty()) )
622       str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << rawMirrorListUrl() << endl;
623
624     str << "type=" << type().asString() << endl;
625
626     if ( priority() != defaultPriority() )
627       str << "priority=" << priority() << endl;
628
629     if ( ! indeterminate(_pimpl->_gpgCheck) )
630       str << "gpgcheck=" << (_pimpl->_gpgCheck ? "1" : "0") << endl;
631
632     if ( ! indeterminate(_pimpl->_repoGpgCheck) )
633       str << "repo_gpgcheck=" << (_pimpl->_repoGpgCheck ? "1" : "0") << endl;
634
635     if ( ! indeterminate(_pimpl->_pkgGpgCheck) )
636       str << "pkg_gpgcheck=" << (_pimpl->_pkgGpgCheck ? "1" : "0") << endl;
637
638     if ( ! (rawGpgKeyUrl().asString().empty()) )
639       str << "gpgkey=" << rawGpgKeyUrl() << endl;
640
641     if (!indeterminate(_pimpl->keeppackages))
642       str << "keeppackages=" << keepPackages() << endl;
643
644     if( ! service().empty() )
645       str << "service=" << service() << endl;
646
647     return str;
648   }
649
650   std::ostream & RepoInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const
651   {
652     std::string tmpstr;
653     str
654       << "<repo"
655       << " alias=\"" << escape(alias()) << "\""
656       << " name=\"" << escape(name()) << "\"";
657     if (type() != repo::RepoType::NONE)
658       str << " type=\"" << type().asString() << "\"";
659     str
660       << " priority=\"" << priority() << "\""
661       << " enabled=\"" << enabled() << "\""
662       << " autorefresh=\"" << autorefresh() << "\""
663       << " gpgcheck=\"" << gpgCheck() << "\""
664       << " repo_gpgcheck=\"" << repoGpgCheck() << "\""
665       << " pkg_gpgcheck=\"" << pkgGpgCheck() << "\"";
666     if (!(tmpstr = gpgKeyUrl().asString()).empty())
667       str << " gpgkey=\"" << escape(tmpstr) << "\"";
668     if (!(tmpstr = mirrorListUrl().asString()).empty())
669       str << (_pimpl->_mirrorListForceMetalink ? " metalink=\"" : " mirrorlist=\"") << escape(tmpstr) << "\"";
670     str << ">" << endl;
671
672     if ( _pimpl->baseurl2dump() )
673     {
674       for_( it, baseUrlsBegin(), baseUrlsEnd() )        // !transform iterator replaces variables
675         str << "<url>" << escape((*it).asString()) << "</url>" << endl;
676     }
677
678     str << "</repo>" << endl;
679     return str;
680   }
681
682
683   std::ostream & operator<<( std::ostream & str, const RepoInfo & obj )
684   {
685     return obj.dumpOn(str);
686   }
687
688
689   /////////////////////////////////////////////////////////////////
690 } // namespace zypp
691 ///////////////////////////////////////////////////////////////////