libzypp  10.5.0
RepoInfo.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <vector>
00014 
00015 #include "zypp/base/Logger.h"
00016 #include "zypp/base/DefaultIntegral.h"
00017 #include "zypp/parser/xml/XmlEscape.h"
00018 
00019 #include "zypp/RepoInfo.h"
00020 #include "zypp/repo/RepoInfoBaseImpl.h"
00021 #include "zypp/repo/RepoMirrorList.h"
00022 #include "zypp/ExternalProgram.h"
00023 #include "zypp/media/MediaAccess.h"
00024 
00025 using namespace std;
00026 using zypp::xml::escape;
00027 
00029 namespace zypp
00030 { 
00031 
00033   //
00034   //    CLASS NAME : RepoInfo::Impl
00035   //
00037   struct RepoInfo::Impl : public repo::RepoInfoBase::Impl
00038   {
00039     Impl()
00040       : repo::RepoInfoBase::Impl()
00041       , gpgcheck(indeterminate)
00042       , keeppackages(indeterminate)
00043       , type(repo::RepoType::NONE_e)
00044       , emptybaseurls(false)
00045     {}
00046 
00047     ~Impl()
00048     {}
00049 
00050   public:
00051     static const unsigned defaultPriority = 99;
00052 
00053     void setProbedType( const repo::RepoType & t ) const
00054     {
00055       if ( type == repo::RepoType::NONE
00056            && t != repo::RepoType::NONE )
00057       {
00058         // lazy init!
00059         const_cast<Impl*>(this)->type = t;
00060       }
00061     }
00062 
00063   public:
00064     Pathname licenseTgz() const
00065     { return metadatapath.empty() ? Pathname() : metadatapath / path / "license.tar.gz"; }
00066 
00067     Url getmirrorListUrl() const
00068     { return replacer(mirrorlist_url); }
00069 
00070     Url &setmirrorListUrl()
00071     { return mirrorlist_url; }
00072 
00073     const std::set<Url> &baseUrls() const
00074     {
00075       if ( _baseUrls.empty() && ! (getmirrorListUrl().asString().empty()) )
00076       {
00077         emptybaseurls = true;
00078         repo::RepoMirrorList *rmirrorlist = NULL;
00079 
00080         DBG << "MetadataPath: " << metadatapath << endl;
00081         if( metadatapath.empty() )
00082           rmirrorlist = new repo::RepoMirrorList (getmirrorListUrl() );
00083         else
00084           rmirrorlist = new repo::RepoMirrorList (getmirrorListUrl(), metadatapath );
00085 
00086         std::vector<Url> rmurls = rmirrorlist->getUrls();
00087         delete rmirrorlist;
00088         rmirrorlist = NULL;
00089         _baseUrls.insert(rmurls.begin(), rmurls.end());
00090       }
00091       return _baseUrls;
00092     }
00093 
00094     std::set<Url> &baseUrls()
00095     { return _baseUrls; }
00096 
00097     bool baseurl2dump() const
00098     { return !emptybaseurls && !_baseUrls.empty(); }
00099 
00100   public:
00101     TriBool gpgcheck;
00102     TriBool keeppackages;
00103     Url gpgkey_url;
00104     repo::RepoType type;
00105     Pathname path;
00106     std::string service;
00107     std::string targetDistro;
00108     Pathname metadatapath;
00109     Pathname packagespath;
00110     DefaultIntegral<unsigned,defaultPriority> priority;
00111     mutable bool emptybaseurls;
00112     repo::RepoVariablesUrlReplacer replacer;
00113 
00114   private:
00115     Url mirrorlist_url;
00116     mutable std::set<Url> _baseUrls;
00117 
00118     friend Impl * rwcowClone<Impl>( const Impl * rhs );
00120     Impl * clone() const
00121     { return new Impl( *this ); }
00122   };
00124 
00126   inline std::ostream & operator<<( std::ostream & str, const RepoInfo::Impl & obj )
00127   {
00128     return str << "RepoInfo::Impl";
00129   }
00130 
00132   //
00133   //    CLASS NAME : RepoInfo
00134   //
00136 
00137   const RepoInfo RepoInfo::noRepo;
00138 
00140   //
00141   //    METHOD NAME : RepoInfo::RepoInfo
00142   //    METHOD TYPE : Ctor
00143   //
00144   RepoInfo::RepoInfo()
00145   : _pimpl( new Impl() )
00146   {}
00147 
00149   //
00150   //    METHOD NAME : RepoInfo::~RepoInfo
00151   //    METHOD TYPE : Dtor
00152   //
00153   RepoInfo::~RepoInfo()
00154   {
00155     //MIL << std::endl;
00156   }
00157 
00158   unsigned RepoInfo::priority() const
00159   { return _pimpl->priority; }
00160 
00161   unsigned RepoInfo::defaultPriority()
00162   { return Impl::defaultPriority; }
00163 
00164   void RepoInfo::setPriority( unsigned newval_r )
00165   { _pimpl->priority = newval_r ? newval_r : Impl::defaultPriority; }
00166 
00167   void RepoInfo::setGpgCheck( bool check )
00168   { _pimpl->gpgcheck = check; }
00169 
00170   void RepoInfo::setMirrorListUrl( const Url &url )
00171   { _pimpl->setmirrorListUrl() = url; }
00172 
00173   void RepoInfo::setGpgKeyUrl( const Url &url )
00174   { _pimpl->gpgkey_url = url; }
00175 
00176   void RepoInfo::addBaseUrl( const Url &url )
00177   { _pimpl->baseUrls().insert(url); }
00178 
00179   void RepoInfo::setBaseUrl( const Url &url )
00180   {
00181     _pimpl->baseUrls().clear();
00182     addBaseUrl(url);
00183   }
00184 
00185   void RepoInfo::setPath( const Pathname &path )
00186   { _pimpl->path = path; }
00187 
00188   void RepoInfo::setType( const repo::RepoType &t )
00189   { _pimpl->type = t; }
00190 
00191   void RepoInfo::setProbedType( const repo::RepoType &t ) const
00192   { _pimpl->setProbedType( t ); }
00193 
00194 
00195   void RepoInfo::setMetadataPath( const Pathname &path )
00196   { _pimpl->metadatapath = path; }
00197 
00198   void RepoInfo::setPackagesPath( const Pathname &path )
00199   { _pimpl->packagespath = path; }
00200 
00201   void RepoInfo::setKeepPackages( bool keep )
00202   { _pimpl->keeppackages = keep; }
00203 
00204   void RepoInfo::setService( const std::string& name )
00205   { _pimpl->service = name; }
00206 
00207   void RepoInfo::setTargetDistribution( const std::string & targetDistribution )
00208   { _pimpl->targetDistro = targetDistribution; }
00209 
00210   bool RepoInfo::gpgCheck() const
00211   { return indeterminate(_pimpl->gpgcheck) ? true : (bool)_pimpl->gpgcheck; }
00212 
00213   bool RepoInfo::keepPackages() const
00214   { return indeterminate(_pimpl->keeppackages) ? false : (bool)_pimpl->keeppackages; }
00215 
00216   Pathname RepoInfo::metadataPath() const
00217   { return _pimpl->metadatapath; }
00218 
00219   Pathname RepoInfo::packagesPath() const
00220   { return _pimpl->packagespath; }
00221 
00222   repo::RepoType RepoInfo::type() const
00223   { return _pimpl->type; }
00224 
00225   Url RepoInfo::mirrorListUrl() const
00226   { return _pimpl->getmirrorListUrl(); }
00227 
00228   Url RepoInfo::gpgKeyUrl() const
00229   { return _pimpl->gpgkey_url; }
00230 
00231   std::set<Url> RepoInfo::baseUrls() const
00232   {
00233     RepoInfo::url_set replaced_urls;
00234     for ( url_set::const_iterator it = _pimpl->baseUrls().begin();
00235           it != _pimpl->baseUrls().end();
00236           ++it )
00237     {
00238       replaced_urls.insert(_pimpl->replacer(*it));
00239     }
00240     return replaced_urls;
00241   }
00242 
00243   Pathname RepoInfo::path() const
00244   { return _pimpl->path; }
00245 
00246   std::string RepoInfo::service() const
00247   { return _pimpl->service; }
00248 
00249   std::string RepoInfo::targetDistribution() const
00250   { return _pimpl->targetDistro; }
00251 
00252   RepoInfo::urls_const_iterator RepoInfo::baseUrlsBegin() const
00253   {
00254     return make_transform_iterator( _pimpl->baseUrls().begin(),
00255                                     _pimpl->replacer );
00256     //return _pimpl->baseUrls.begin();
00257   }
00258 
00259   RepoInfo::urls_const_iterator RepoInfo::baseUrlsEnd() const
00260   {
00261     //return _pimpl->baseUrls.end();
00262     return make_transform_iterator( _pimpl->baseUrls().end(),
00263                                     _pimpl->replacer );
00264   }
00265 
00266   RepoInfo::urls_size_type RepoInfo::baseUrlsSize() const
00267   { return _pimpl->baseUrls().size(); }
00268 
00269   bool RepoInfo::baseUrlsEmpty() const
00270   { return _pimpl->baseUrls().empty(); }
00271 
00272   bool RepoInfo::baseUrlSet() const
00273   { return _pimpl->baseurl2dump(); }
00274 
00276 
00277   bool RepoInfo::hasLicense() const
00278   {
00279     Pathname licenseTgz( _pimpl->licenseTgz() );
00280     SEC << licenseTgz << endl;
00281     SEC << PathInfo(licenseTgz) << endl;
00282 
00283     return ! licenseTgz.empty() &&  PathInfo(licenseTgz).isFile();
00284   }
00285 
00286   std::string RepoInfo::getLicense( const Locale & lang_r )
00287   {
00288     LocaleSet avlocales( getLicenseLocales() );
00289     if ( avlocales.empty() )
00290       return std::string();
00291 
00292     Locale getLang( Locale::bestMatch( avlocales, lang_r ) );
00293     if ( getLang == Locale::noCode
00294          && avlocales.find( Locale::noCode ) == avlocales.end() )
00295     {
00296       WAR << "License.tar.gz contains no fallback text! " << *this << endl;
00297       // Using the fist locale instead of returning no text at all.
00298       // So the user might recognize that there is a license, even if he
00299       // can't read it.
00300       getLang = *avlocales.begin();
00301     }
00302 
00303     // now extract the license file.
00304     static const std::string licenseFileFallback( "license.txt" );
00305     std::string licenseFile( getLang == Locale::noCode
00306                              ? licenseFileFallback
00307                              : str::form( "license.%s.txt", getLang.code().c_str() ) );
00308 
00309     ExternalProgram::Arguments cmd;
00310     cmd.push_back( "tar" );
00311     cmd.push_back( "-x" );
00312     cmd.push_back( "-z" );
00313     cmd.push_back( "-O" );
00314     cmd.push_back( "-f" );
00315     cmd.push_back( _pimpl->licenseTgz().asString() ); // if it not exists, avlocales was empty.
00316     cmd.push_back( licenseFile );
00317 
00318     std::string ret;
00319     ExternalProgram prog( cmd, ExternalProgram::Discard_Stderr );
00320     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
00321     {
00322       ret += output;
00323     }
00324     prog.close();
00325     return ret;
00326   }
00327 
00328   LocaleSet RepoInfo::getLicenseLocales() const
00329   {
00330     Pathname licenseTgz( _pimpl->licenseTgz() );
00331     if ( licenseTgz.empty() || ! PathInfo( licenseTgz ).isFile() )
00332       return LocaleSet();
00333 
00334     ExternalProgram::Arguments cmd;
00335     cmd.push_back( "tar" );
00336     cmd.push_back( "-t" );
00337     cmd.push_back( "-z" );
00338     cmd.push_back( "-f" );
00339     cmd.push_back( licenseTgz.asString() );
00340 
00341     LocaleSet ret;
00342     ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
00343     for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() )
00344     {
00345       static const C_Str license( "license." );
00346       static const C_Str dotTxt( ".txt\n" );
00347       if ( str::hasPrefix( output, license ) && str::hasSuffix( output, dotTxt ) )
00348       {
00349         if ( output.size() <= license.size() +  dotTxt.size() ) // license.txt
00350           ret.insert( Locale() );
00351         else
00352           ret.insert( Locale( std::string( output.c_str()+license.size(), output.size()- license.size() - dotTxt.size() ) ) );
00353       }
00354       else
00355       {
00356         WAR << "  " << output;
00357       }
00358     }
00359     prog.close();
00360     return ret;
00361   }
00362 
00364 
00365   std::ostream & RepoInfo::dumpOn( std::ostream & str ) const
00366   {
00367     RepoInfoBase::dumpOn(str);
00368     if ( _pimpl->baseurl2dump() )
00369     {
00370       for ( urls_const_iterator it = baseUrlsBegin();
00371             it != baseUrlsEnd();
00372             ++it )
00373       {
00374         str << "- url         : " << *it << std::endl;
00375       }
00376     }
00377 
00378     // print if non empty value
00379     auto strif( [&] ( const std::string & tag_r, const std::string & value_r ) {
00380       if ( ! value_r.empty() )
00381         str << tag_r << value_r << std::endl;
00382     });
00383 
00384     strif( "- mirrorlist  : ", _pimpl->getmirrorListUrl().asString() );
00385     strif( "- path        : ", path().asString() );
00386     str << "- type        : " << type() << std::endl;
00387     str << "- priority    : " << priority() << std::endl;
00388     str << "- gpgcheck    : " << gpgCheck() << std::endl;
00389     strif( "- gpgkey      : ", gpgKeyUrl().asString() );
00390 
00391     if ( ! indeterminate(_pimpl->keeppackages) )
00392       str << "- keeppackages: " << keepPackages() << std::endl;
00393 
00394     strif( "- service     : ", service() );
00395     strif( "- targetdistro: ", targetDistribution() );
00396     strif( "- metadataPath: ", metadataPath().asString() );
00397     strif( "- packagesPath: ", packagesPath().asString() );
00398 
00399     return str;
00400   }
00401 
00402   std::ostream & RepoInfo::dumpAsIniOn( std::ostream & str ) const
00403   {
00404     RepoInfoBase::dumpAsIniOn(str);
00405 
00406     if ( _pimpl->baseurl2dump() )
00407     {
00408       str << "baseurl=";
00409       for ( url_set::const_iterator it = _pimpl->baseUrls().begin();
00410             it != _pimpl->baseUrls().end();
00411             ++it )
00412       {
00413         str << *it << endl;
00414       }
00415     }
00416 
00417     if ( ! _pimpl->path.empty() )
00418       str << "path="<< path() << endl;
00419 
00420     if ( ! (_pimpl->getmirrorListUrl().asString().empty()) )
00421       str << "mirrorlist=" << _pimpl->getmirrorListUrl() << endl;
00422 
00423     str << "type=" << type().asString() << endl;
00424 
00425     if ( priority() != defaultPriority() )
00426       str << "priority=" << priority() << endl;
00427 
00428     if (!indeterminate(_pimpl->gpgcheck))
00429       str << "gpgcheck=" << (gpgCheck() ? "1" : "0") << endl;
00430     if ( ! (gpgKeyUrl().asString().empty()) )
00431       str << "gpgkey=" <<gpgKeyUrl() << endl;
00432 
00433     if (!indeterminate(_pimpl->keeppackages))
00434       str << "keeppackages=" << keepPackages() << endl;
00435 
00436     if( ! service().empty() )
00437       str << "service=" << service() << endl;
00438 
00439     return str;
00440   }
00441 
00442   std::ostream & RepoInfo::dumpAsXMLOn( std::ostream & str) const
00443   { return dumpAsXMLOn(str, ""); }
00444 
00445   std::ostream & RepoInfo::dumpAsXMLOn( std::ostream & str, const std::string & content) const
00446   {
00447     string tmpstr;
00448     str
00449       << "<repo"
00450       << " alias=\"" << escape(alias()) << "\""
00451       << " name=\"" << escape(name()) << "\"";
00452     if (type() != repo::RepoType::NONE)
00453       str << " type=\"" << type().asString() << "\"";
00454     str
00455       << " enabled=\"" << enabled() << "\""
00456       << " autorefresh=\"" << autorefresh() << "\""
00457       << " gpgcheck=\"" << gpgCheck() << "\"";
00458     if (!(tmpstr = gpgKeyUrl().asString()).empty())
00459       str << " gpgkey=\"" << escape(tmpstr) << "\"";
00460     if (!(tmpstr = mirrorListUrl().asString()).empty())
00461       str << " mirrorlist=\"" << escape(tmpstr) << "\"";
00462     str << ">" << endl;
00463 
00464     if ( _pimpl->baseurl2dump() )
00465     {
00466       for (RepoInfo::urls_const_iterator urlit = baseUrlsBegin();
00467            urlit != baseUrlsEnd(); ++urlit)
00468         str << "<url>" << escape(urlit->asString()) << "</url>" << endl;
00469     }
00470 
00471     str << "</repo>" << endl;
00472     return str;
00473   }
00474 
00475 
00476   std::ostream & operator<<( std::ostream & str, const RepoInfo & obj )
00477   {
00478     return obj.dumpOn(str);
00479   }
00480 
00481 
00483 } // namespace zypp