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