no using namespace
[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/Logger.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/repo/RepoMirrorList.h"
23 #include "zypp/ExternalProgram.h"
24 #include "zypp/media/MediaAccess.h"
25
26 using std::endl;
27 using zypp::xml::escape;
28
29 ///////////////////////////////////////////////////////////////////
30 namespace zypp
31 { /////////////////////////////////////////////////////////////////
32
33   ///////////////////////////////////////////////////////////////////
34   //
35   //    CLASS NAME : RepoInfo::Impl
36   //
37   /** RepoInfo implementation. */
38   struct RepoInfo::Impl
39   {
40     Impl()
41       : gpgcheck(indeterminate)
42       , keeppackages(indeterminate)
43       , type(repo::RepoType::NONE_e)
44       , emptybaseurls(false)
45     {}
46
47     ~Impl()
48     {}
49
50   public:
51     static const unsigned defaultPriority = 99;
52
53     void setProbedType( const repo::RepoType & t ) const
54     {
55       if ( type == repo::RepoType::NONE
56            && t != repo::RepoType::NONE )
57       {
58         // lazy init!
59         const_cast<Impl*>(this)->type = t;
60       }
61     }
62
63   public:
64     Pathname licenseTgz() const
65     { return metadatapath.empty() ? Pathname() : metadatapath / path / "license.tar.gz"; }
66
67     Url getmirrorListUrl() const
68     { return replacer(mirrorlist_url); }
69
70     Url &setmirrorListUrl()
71     { return mirrorlist_url; }
72
73     const std::set<Url> &baseUrls() const
74     {
75       if ( _baseUrls.empty() && ! (getmirrorListUrl().asString().empty()) )
76       {
77         emptybaseurls = true;
78         repo::RepoMirrorList *rmirrorlist = NULL;
79
80         DBG << "MetadataPath: " << metadatapath << endl;
81         if( metadatapath.empty() )
82           rmirrorlist = new repo::RepoMirrorList (getmirrorListUrl() );
83         else
84           rmirrorlist = new repo::RepoMirrorList (getmirrorListUrl(), metadatapath );
85
86         std::vector<Url> rmurls = rmirrorlist->getUrls();
87         delete rmirrorlist;
88         rmirrorlist = NULL;
89         _baseUrls.insert(rmurls.begin(), rmurls.end());
90       }
91       return _baseUrls;
92     }
93
94     std::set<Url> &baseUrls()
95     { return _baseUrls; }
96
97     bool baseurl2dump() const
98     { return !emptybaseurls && !_baseUrls.empty(); }
99
100   public:
101     TriBool gpgcheck;
102     TriBool keeppackages;
103     Url gpgkey_url;
104     repo::RepoType type;
105     Pathname path;
106     std::string service;
107     std::string targetDistro;
108     Pathname metadatapath;
109     Pathname packagespath;
110     DefaultIntegral<unsigned,defaultPriority> priority;
111     mutable bool emptybaseurls;
112     repo::RepoVariablesUrlReplacer replacer;
113
114   private:
115     Url mirrorlist_url;
116     mutable std::set<Url> _baseUrls;
117
118     friend Impl * rwcowClone<Impl>( const Impl * rhs );
119     /** clone for RWCOW_pointer */
120     Impl * clone() const
121     { return new Impl( *this ); }
122   };
123   ///////////////////////////////////////////////////////////////////
124
125   /** \relates RepoInfo::Impl Stream output */
126   inline std::ostream & operator<<( std::ostream & str, const RepoInfo::Impl & obj )
127   {
128     return str << "RepoInfo::Impl";
129   }
130
131   ///////////////////////////////////////////////////////////////////
132   //
133   //    CLASS NAME : RepoInfo
134   //
135   ///////////////////////////////////////////////////////////////////
136
137   const RepoInfo RepoInfo::noRepo;
138
139   ///////////////////////////////////////////////////////////////////
140   //
141   //    METHOD NAME : RepoInfo::RepoInfo
142   //    METHOD TYPE : Ctor
143   //
144   RepoInfo::RepoInfo()
145   : _pimpl( new Impl() )
146   {}
147
148   ///////////////////////////////////////////////////////////////////
149   //
150   //    METHOD NAME : RepoInfo::~RepoInfo
151   //    METHOD TYPE : Dtor
152   //
153   RepoInfo::~RepoInfo()
154   {
155     //MIL << std::endl;
156   }
157
158   unsigned RepoInfo::priority() const
159   { return _pimpl->priority; }
160
161   unsigned RepoInfo::defaultPriority()
162   { return Impl::defaultPriority; }
163
164   void RepoInfo::setPriority( unsigned newval_r )
165   { _pimpl->priority = newval_r ? newval_r : Impl::defaultPriority; }
166
167   void RepoInfo::setGpgCheck( bool check )
168   { _pimpl->gpgcheck = check; }
169
170   void RepoInfo::setMirrorListUrl( const Url &url )
171   { _pimpl->setmirrorListUrl() = url; }
172
173   void RepoInfo::setGpgKeyUrl( const Url &url )
174   { _pimpl->gpgkey_url = url; }
175
176   void RepoInfo::addBaseUrl( const Url &url )
177   { _pimpl->baseUrls().insert(url); }
178
179   void RepoInfo::setBaseUrl( const Url &url )
180   {
181     _pimpl->baseUrls().clear();
182     addBaseUrl(url);
183   }
184
185   void RepoInfo::setPath( const Pathname &path )
186   { _pimpl->path = path; }
187
188   void RepoInfo::setType( const repo::RepoType &t )
189   { _pimpl->type = t; }
190
191   void RepoInfo::setProbedType( const repo::RepoType &t ) const
192   { _pimpl->setProbedType( t ); }
193
194
195   void RepoInfo::setMetadataPath( const Pathname &path )
196   { _pimpl->metadatapath = path; }
197
198   void RepoInfo::setPackagesPath( const Pathname &path )
199   { _pimpl->packagespath = path; }
200
201   void RepoInfo::setKeepPackages( bool keep )
202   { _pimpl->keeppackages = keep; }
203
204   void RepoInfo::setService( const std::string& name )
205   { _pimpl->service = name; }
206
207   void RepoInfo::setTargetDistribution( const std::string & targetDistribution )
208   { _pimpl->targetDistro = targetDistribution; }
209
210   bool RepoInfo::gpgCheck() const
211   { return indeterminate(_pimpl->gpgcheck) ? true : (bool)_pimpl->gpgcheck; }
212
213   bool RepoInfo::keepPackages() const
214   { return indeterminate(_pimpl->keeppackages) ? false : (bool)_pimpl->keeppackages; }
215
216   Pathname RepoInfo::metadataPath() const
217   { return _pimpl->metadatapath; }
218
219   Pathname RepoInfo::packagesPath() const
220   { return _pimpl->packagespath; }
221
222   repo::RepoType RepoInfo::type() const
223   { return _pimpl->type; }
224
225   Url RepoInfo::mirrorListUrl() const
226   { return _pimpl->getmirrorListUrl(); }
227
228   Url RepoInfo::gpgKeyUrl() const
229   { return _pimpl->gpgkey_url; }
230
231   std::set<Url> RepoInfo::baseUrls() const
232   {
233     RepoInfo::url_set replaced_urls;
234     for ( url_set::const_iterator it = _pimpl->baseUrls().begin();
235           it != _pimpl->baseUrls().end();
236           ++it )
237     {
238       replaced_urls.insert(_pimpl->replacer(*it));
239     }
240     return replaced_urls;
241   }
242
243   Pathname RepoInfo::path() const
244   { return _pimpl->path; }
245
246   std::string RepoInfo::service() const
247   { return _pimpl->service; }
248
249   std::string RepoInfo::targetDistribution() const
250   { return _pimpl->targetDistro; }
251
252   RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const
253   {
254     return make_transform_iterator( _pimpl->baseUrls().begin(),
255                                     _pimpl->replacer );
256     //return _pimpl->baseUrls.begin();
257   }
258
259   RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const
260   {
261     //return _pimpl->baseUrls.end();
262     return make_transform_iterator( _pimpl->baseUrls().end(),
263                                     _pimpl->replacer );
264   }
265
266   RepoInfo::urls_size_type RepoInfo::baseUrlsSize() const
267   { return _pimpl->baseUrls().size(); }
268
269   bool RepoInfo::baseUrlsEmpty() const
270   { return _pimpl->baseUrls().empty(); }
271
272   bool RepoInfo::baseUrlSet() const
273   { return _pimpl->baseurl2dump(); }
274
275   ///////////////////////////////////////////////////////////////////
276
277   bool RepoInfo::hasLicense() const
278   {
279     Pathname licenseTgz( _pimpl->licenseTgz() );
280     SEC << licenseTgz << endl;
281     SEC << PathInfo(licenseTgz) << endl;
282
283     return ! licenseTgz.empty() &&  PathInfo(licenseTgz).isFile();
284   }
285
286   bool RepoInfo::needToAcceptLicense() const
287   {
288     static const std::string noAcceptanceFile = "no-acceptance-needed\n";
289     bool accept = true;
290
291     Pathname licenseTgz( _pimpl->licenseTgz() );
292     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
293       return false;     // no licenses at all
294
295     ExternalProgram::Arguments cmd;
296     cmd.push_back( "tar" );
297     cmd.push_back( "-t" );
298     cmd.push_back( "-z" );
299     cmd.push_back( "-f" );
300     cmd.push_back( licenseTgz.asString() );
301
302     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
303     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
304     {
305       if ( output == noAcceptanceFile )
306       {
307         accept = false;
308       }
309     }
310     MIL << "License for " << this->name() << " has to be accepted: " << (accept?"true":"false" ) << endl;
311     return accept;
312   }
313
314   std::string RepoInfo::getLicense( const Locale & lang_r )
315   {
316     LocaleSet avlocales( getLicenseLocales() );
317     if ( avlocales.empty() )
318       return std::string();
319
320     Locale getLang( Locale::bestMatch( avlocales, lang_r ) );
321     if ( getLang == Locale::noCode
322          && avlocales.find( Locale::noCode ) == avlocales.end() )
323     {
324       WAR << "License.tar.gz contains no fallback text! " << *this << endl;
325       // Using the fist locale instead of returning no text at all.
326       // So the user might recognize that there is a license, even if he
327       // can't read it.
328       getLang = *avlocales.begin();
329     }
330
331     // now extract the license file.
332     static const std::string licenseFileFallback( "license.txt" );
333     std::string licenseFile( getLang == Locale::noCode
334                              ? licenseFileFallback
335                              : str::form( "license.%s.txt", getLang.code().c_str() ) );
336
337     ExternalProgram::Arguments cmd;
338     cmd.push_back( "tar" );
339     cmd.push_back( "-x" );
340     cmd.push_back( "-z" );
341     cmd.push_back( "-O" );
342     cmd.push_back( "-f" );
343     cmd.push_back( _pimpl->licenseTgz().asString() ); // if it not exists, avlocales was empty.
344     cmd.push_back( licenseFile );
345
346     std::string ret;
347     ExternalProgram prog( cmd, ExternalProgram::Discard_Stderr );
348     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
349     {
350       ret += output;
351     }
352     prog.close();
353     return ret;
354   }
355
356   LocaleSet RepoInfo::getLicenseLocales() const
357   {
358     Pathname licenseTgz( _pimpl->licenseTgz() );
359     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
360       return LocaleSet();
361
362     ExternalProgram::Arguments cmd;
363     cmd.push_back( "tar" );
364     cmd.push_back( "-t" );
365     cmd.push_back( "-z" );
366     cmd.push_back( "-f" );
367     cmd.push_back( licenseTgz.asString() );
368
369     LocaleSet ret;
370     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
371     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
372     {
373       static const C_Str license( "license." );
374       static const C_Str dotTxt( ".txt\n" );
375       if ( str::hasPrefix( output, license ) && str::hasSuffix( output, dotTxt ) )
376       {
377         if ( output.size() <= license.size() +  dotTxt.size() ) // license.txt
378           ret.insert( Locale() );
379         else
380           ret.insert( Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) );
381       }
382     }
383     prog.close();
384     return ret;
385   }
386
387   ///////////////////////////////////////////////////////////////////
388
389   std::ostream & RepoInfo::dumpOn( std::ostream & str ) const
390   {
391     RepoInfoBase::dumpOn(str);
392     if ( _pimpl->baseurl2dump() )
393     {
394       for ( urls_const_iterator it = baseUrlsBegin();
395             it != baseUrlsEnd();
396             ++it )
397       {
398         str << "- url         : " << *it << std::endl;
399       }
400     }
401
402     // print if non empty value
403     auto strif( [&] ( const std::string & tag_r, const std::string & value_r ) {
404       if ( ! value_r.empty() )
405         str << tag_r << value_r << std::endl;
406     });
407
408     strif( "- mirrorlist  : ", _pimpl->getmirrorListUrl().asString() );
409     strif( "- path        : ", path().asString() );
410     str << "- type        : " << type() << std::endl;
411     str << "- priority    : " << priority() << std::endl;
412     str << "- gpgcheck    : " << gpgCheck() << std::endl;
413     strif( "- gpgkey      : ", gpgKeyUrl().asString() );
414
415     if ( ! indeterminate(_pimpl->keeppackages) )
416       str << "- keeppackages: " << keepPackages() << std::endl;
417
418     strif( "- service     : ", service() );
419     strif( "- targetdistro: ", targetDistribution() );
420     strif( "- metadataPath: ", metadataPath().asString() );
421     strif( "- packagesPath: ", packagesPath().asString() );
422
423     return str;
424   }
425
426   std::ostream & RepoInfo::dumpAsIniOn( std::ostream & str ) const
427   {
428     RepoInfoBase::dumpAsIniOn(str);
429
430     if ( _pimpl->baseurl2dump() )
431     {
432       str << "baseurl=";
433       for ( url_set::const_iterator it = _pimpl->baseUrls().begin();
434             it != _pimpl->baseUrls().end();
435             ++it )
436       {
437         str << *it << endl;
438       }
439     }
440
441     if ( ! _pimpl->path.empty() )
442       str << "path="<< path() << endl;
443
444     if ( ! (_pimpl->getmirrorListUrl().asString().empty()) )
445       str << "mirrorlist=" << _pimpl->getmirrorListUrl() << endl;
446
447     str << "type=" << type().asString() << endl;
448
449     if ( priority() != defaultPriority() )
450       str << "priority=" << priority() << endl;
451
452     if (!indeterminate(_pimpl->gpgcheck))
453       str << "gpgcheck=" << (gpgCheck() ? "1" : "0") << endl;
454     if ( ! (gpgKeyUrl().asString().empty()) )
455       str << "gpgkey=" <<gpgKeyUrl() << endl;
456
457     if (!indeterminate(_pimpl->keeppackages))
458       str << "keeppackages=" << keepPackages() << endl;
459
460     if( ! service().empty() )
461       str << "service=" << service() << endl;
462
463     return str;
464   }
465
466   std::ostream & RepoInfo::dumpAsXmlOn( std::ostream & str, const std::string & content ) const
467   {
468     std::string tmpstr;
469     str
470       << "<repo"
471       << " alias=\"" << escape(alias()) << "\""
472       << " name=\"" << escape(name()) << "\"";
473     if (type() != repo::RepoType::NONE)
474       str << " type=\"" << type().asString() << "\"";
475     str
476       << " priority=\"" << priority() << "\""
477       << " enabled=\"" << enabled() << "\""
478       << " autorefresh=\"" << autorefresh() << "\""
479       << " gpgcheck=\"" << gpgCheck() << "\"";
480     if (!(tmpstr = gpgKeyUrl().asString()).empty())
481       str << " gpgkey=\"" << escape(tmpstr) << "\"";
482     if (!(tmpstr = mirrorListUrl().asString()).empty())
483       str << " mirrorlist=\"" << escape(tmpstr) << "\"";
484     str << ">" << endl;
485
486     if ( _pimpl->baseurl2dump() )
487     {
488       for (RepoInfo::urls_const_iterator urlit = baseUrlsBegin();
489            urlit != baseUrlsEnd(); ++urlit)
490         str << "<url>" << escape(urlit->asString()) << "</url>" << endl;
491     }
492
493     str << "</repo>" << endl;
494     return str;
495   }
496
497
498   std::ostream & operator<<( std::ostream & str, const RepoInfo & obj )
499   {
500     return obj.dumpOn(str);
501   }
502
503
504   /////////////////////////////////////////////////////////////////
505 } // namespace zypp
506 ///////////////////////////////////////////////////////////////////