Imported Upstream version 15.21.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::setPath( const Pathname &path )
351   { _pimpl->path = path; }
352
353   void RepoInfo::setType( const repo::RepoType &t )
354   { _pimpl->type = t; }
355
356   void RepoInfo::setProbedType( const repo::RepoType &t ) const
357   { _pimpl->setProbedType( t ); }
358
359
360   void RepoInfo::setMetadataPath( const Pathname &path )
361   { _pimpl->metadatapath = path; }
362
363   void RepoInfo::setPackagesPath( const Pathname &path )
364   { _pimpl->packagespath = path; }
365
366   void RepoInfo::setKeepPackages( bool keep )
367   { _pimpl->keeppackages = keep; }
368
369   void RepoInfo::setService( const std::string& name )
370   { _pimpl->service = name; }
371
372   void RepoInfo::setTargetDistribution( const std::string & targetDistribution )
373   { _pimpl->targetDistro = targetDistribution; }
374
375   bool RepoInfo::keepPackages() const
376   { return indeterminate(_pimpl->keeppackages) ? false : (bool)_pimpl->keeppackages; }
377
378   Pathname RepoInfo::metadataPath() const
379   { return _pimpl->metadatapath; }
380
381   Pathname RepoInfo::packagesPath() const
382   { return _pimpl->packagespath; }
383
384   repo::RepoType RepoInfo::type() const
385   { return _pimpl->type; }
386
387   Url RepoInfo::mirrorListUrl() const                   // Variables replaced!
388   { return _pimpl->_mirrorListUrl.transformed(); }
389
390   Url RepoInfo::rawMirrorListUrl() const                // Raw
391   { return _pimpl->_mirrorListUrl.raw(); }
392
393   Url RepoInfo::gpgKeyUrl() const                       // Variables replaced!
394   { return _pimpl->_gpgKeyUrl.transformed(); }
395
396   Url RepoInfo::rawGpgKeyUrl() const                    // Raw
397   {  return _pimpl->_gpgKeyUrl.raw(); }
398
399   RepoInfo::url_set RepoInfo::baseUrls() const          // Variables replaced!
400   { return _pimpl->baseUrls().transformed(); }
401
402   RepoInfo::url_set RepoInfo::rawBaseUrls() const       // Raw
403   { return _pimpl->baseUrls().raw(); }
404
405   Pathname RepoInfo::path() const
406   { return _pimpl->path; }
407
408   std::string RepoInfo::service() const
409   { return _pimpl->service; }
410
411   std::string RepoInfo::targetDistribution() const
412   { return _pimpl->targetDistro; }
413
414   Url RepoInfo::rawUrl() const
415   { return( _pimpl->baseUrls().empty() ? Url() : *_pimpl->baseUrls().rawBegin() ); }
416
417   RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const
418   { return _pimpl->baseUrls().transformedBegin(); }
419
420   RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const
421   { return _pimpl->baseUrls().transformedEnd(); }
422
423   RepoInfo::urls_size_type RepoInfo::baseUrlsSize() const
424   { return _pimpl->baseUrls().size(); }
425
426   bool RepoInfo::baseUrlsEmpty() const
427   { return _pimpl->baseUrls().empty(); }
428
429   bool RepoInfo::baseUrlSet() const
430   { return _pimpl->baseurl2dump(); }
431
432   const std::set<std::string> & RepoInfo::contentKeywords() const
433   { return _pimpl->contentKeywords(); }
434
435   void RepoInfo::addContent( const std::string & keyword_r )
436   { _pimpl->addContent( keyword_r ); }
437
438   bool RepoInfo::hasContent() const
439   { return _pimpl->hasContent(); }
440
441   bool RepoInfo::hasContent( const std::string & keyword_r ) const
442   { return _pimpl->hasContent( keyword_r ); }
443
444   ///////////////////////////////////////////////////////////////////
445
446   bool RepoInfo::hasLicense() const
447   {
448     Pathname licenseTgz( _pimpl->licenseTgz() );
449     return ! licenseTgz.empty() &&  PathInfo(licenseTgz).isFile();
450   }
451
452   bool RepoInfo::needToAcceptLicense() const
453   {
454     static const std::string noAcceptanceFile = "no-acceptance-needed\n";
455     bool accept = true;
456
457     Pathname licenseTgz( _pimpl->licenseTgz() );
458     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
459       return false;     // no licenses at all
460
461     ExternalProgram::Arguments cmd;
462     cmd.push_back( "tar" );
463     cmd.push_back( "-t" );
464     cmd.push_back( "-z" );
465     cmd.push_back( "-f" );
466     cmd.push_back( licenseTgz.asString() );
467
468     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
469     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
470     {
471       if ( output == noAcceptanceFile )
472       {
473         accept = false;
474       }
475     }
476     MIL << "License for " << name() << " has to be accepted: " << (accept?"true":"false" ) << endl;
477     return accept;
478   }
479
480   std::string RepoInfo::getLicense( const Locale & lang_r )
481   { return const_cast<const RepoInfo *>(this)->getLicense( lang_r );  }
482
483   std::string RepoInfo::getLicense( const Locale & lang_r ) const
484   {
485     LocaleSet avlocales( getLicenseLocales() );
486     if ( avlocales.empty() )
487       return std::string();
488
489     Locale getLang( Locale::bestMatch( avlocales, lang_r ) );
490     if ( !getLang && avlocales.find( Locale::noCode ) == avlocales.end() )
491     {
492       WAR << "License.tar.gz contains no fallback text! " << *this << endl;
493       // Using the fist locale instead of returning no text at all.
494       // So the user might recognize that there is a license, even if he
495       // can't read it.
496       getLang = *avlocales.begin();
497     }
498
499     // now extract the license file.
500     static const std::string licenseFileFallback( "license.txt" );
501     std::string licenseFile( !getLang ? licenseFileFallback
502                                       : str::form( "license.%s.txt", getLang.c_str() ) );
503
504     ExternalProgram::Arguments cmd;
505     cmd.push_back( "tar" );
506     cmd.push_back( "-x" );
507     cmd.push_back( "-z" );
508     cmd.push_back( "-O" );
509     cmd.push_back( "-f" );
510     cmd.push_back( _pimpl->licenseTgz().asString() ); // if it not exists, avlocales was empty.
511     cmd.push_back( licenseFile );
512
513     std::string ret;
514     ExternalProgram prog( cmd, ExternalProgram::Discard_Stderr );
515     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
516     {
517       ret += output;
518     }
519     prog.close();
520     return ret;
521   }
522
523   LocaleSet RepoInfo::getLicenseLocales() const
524   {
525     Pathname licenseTgz( _pimpl->licenseTgz() );
526     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
527       return LocaleSet();
528
529     ExternalProgram::Arguments cmd;
530     cmd.push_back( "tar" );
531     cmd.push_back( "-t" );
532     cmd.push_back( "-z" );
533     cmd.push_back( "-f" );
534     cmd.push_back( licenseTgz.asString() );
535
536     LocaleSet ret;
537     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
538     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
539     {
540       static const C_Str license( "license." );
541       static const C_Str dotTxt( ".txt\n" );
542       if ( str::hasPrefix( output, license ) && str::hasSuffix( output, dotTxt ) )
543       {
544         if ( output.size() <= license.size() +  dotTxt.size() ) // license.txt
545           ret.insert( Locale() );
546         else
547           ret.insert( Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) );
548       }
549     }
550     prog.close();
551     return ret;
552   }
553
554   ///////////////////////////////////////////////////////////////////
555
556   std::ostream & RepoInfo::dumpOn( std::ostream & str ) const
557   {
558     RepoInfoBase::dumpOn(str);
559     if ( _pimpl->baseurl2dump() )
560     {
561       for ( const auto & url : _pimpl->baseUrls().raw() )
562       {
563         str << "- url         : " << url << std::endl;
564       }
565     }
566
567     // print if non empty value
568     auto strif( [&] ( const std::string & tag_r, const std::string & value_r ) {
569       if ( ! value_r.empty() )
570         str << tag_r << value_r << std::endl;
571     });
572
573     strif( (_pimpl->_mirrorListForceMetalink ? "- metalink    : " : "- mirrorlist  : "), rawMirrorListUrl().asString() );
574     strif( "- path        : ", path().asString() );
575     str << "- type        : " << type() << std::endl;
576     str << "- priority    : " << priority() << std::endl;
577
578     // Yes No Default(Y) Default(N)
579 #define OUTS(T,B) ( indeterminate(T) ? (std::string("D(")+(B?"Y":"N")+")") : ((bool)T?"Y":"N") )
580     str << "- gpgcheck    : " << OUTS(_pimpl->_gpgCheck,gpgCheck())
581                               << " repo" << OUTS(_pimpl->_repoGpgCheck,repoGpgCheck())
582                               << " sig" << asString( validRepoSignature(), "?", "Y", "N" )
583                               << " pkg" << OUTS(_pimpl->_pkgGpgCheck,pkgGpgCheck())
584                               << std::endl;
585 #undef OUTS
586
587     strif( "- gpgkey      : ", rawGpgKeyUrl().asString() );
588
589     if ( ! indeterminate(_pimpl->keeppackages) )
590       str << "- keeppackages: " << keepPackages() << std::endl;
591
592     strif( "- service     : ", service() );
593     strif( "- targetdistro: ", targetDistribution() );
594     strif( "- metadataPath: ", metadataPath().asString() );
595     strif( "- packagesPath: ", packagesPath().asString() );
596
597     return str;
598   }
599
600   std::ostream & RepoInfo::dumpAsIniOn( std::ostream & str ) const
601   {
602     RepoInfoBase::dumpAsIniOn(str);
603
604     if ( _pimpl->baseurl2dump() )
605     {
606       str << "baseurl=";
607       std::string indent;
608       for ( const auto & url : _pimpl->baseUrls().raw() )
609       {
610         str << indent << url << endl;
611         if ( indent.empty() ) indent = "        ";      // "baseurl="
612       }
613     }
614
615     if ( ! _pimpl->path.empty() )
616       str << "path="<< path() << endl;
617
618     if ( ! (rawMirrorListUrl().asString().empty()) )
619       str << (_pimpl->_mirrorListForceMetalink ? "metalink=" : "mirrorlist=") << rawMirrorListUrl() << endl;
620
621     str << "type=" << type().asString() << endl;
622
623     if ( priority() != defaultPriority() )
624       str << "priority=" << priority() << endl;
625
626     if ( ! indeterminate(_pimpl->_gpgCheck) )
627       str << "gpgcheck=" << (_pimpl->_gpgCheck ? "1" : "0") << endl;
628
629     if ( ! indeterminate(_pimpl->_repoGpgCheck) )
630       str << "repo_gpgcheck=" << (_pimpl->_repoGpgCheck ? "1" : "0") << endl;
631
632     if ( ! indeterminate(_pimpl->_pkgGpgCheck) )
633       str << "pkg_gpgcheck=" << (_pimpl->_pkgGpgCheck ? "1" : "0") << endl;
634
635     if ( ! (rawGpgKeyUrl().asString().empty()) )
636       str << "gpgkey=" << rawGpgKeyUrl() << endl;
637
638     if (!indeterminate(_pimpl->keeppackages))
639       str << "keeppackages=" << keepPackages() << endl;
640
641     if( ! service().empty() )
642       str << "service=" << service() << endl;
643
644     return str;
645   }
646
647   std::ostream & RepoInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const
648   {
649     std::string tmpstr;
650     str
651       << "<repo"
652       << " alias=\"" << escape(alias()) << "\""
653       << " name=\"" << escape(name()) << "\"";
654     if (type() != repo::RepoType::NONE)
655       str << " type=\"" << type().asString() << "\"";
656     str
657       << " priority=\"" << priority() << "\""
658       << " enabled=\"" << enabled() << "\""
659       << " autorefresh=\"" << autorefresh() << "\""
660       << " gpgcheck=\"" << gpgCheck() << "\""
661       << " repo_gpgcheck=\"" << repoGpgCheck() << "\""
662       << " pkg_gpgcheck=\"" << pkgGpgCheck() << "\"";
663     if (!(tmpstr = gpgKeyUrl().asString()).empty())
664       str << " gpgkey=\"" << escape(tmpstr) << "\"";
665     if (!(tmpstr = mirrorListUrl().asString()).empty())
666       str << (_pimpl->_mirrorListForceMetalink ? " metalink=\"" : " mirrorlist=\"") << escape(tmpstr) << "\"";
667     str << ">" << endl;
668
669     if ( _pimpl->baseurl2dump() )
670     {
671       for_( it, baseUrlsBegin(), baseUrlsEnd() )        // !transform iterator replaces variables
672         str << "<url>" << escape((*it).asString()) << "</url>" << endl;
673     }
674
675     str << "</repo>" << endl;
676     return str;
677   }
678
679
680   std::ostream & operator<<( std::ostream & str, const RepoInfo & obj )
681   {
682     return obj.dumpOn(str);
683   }
684
685
686   /////////////////////////////////////////////////////////////////
687 } // namespace zypp
688 ///////////////////////////////////////////////////////////////////