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