ContentFileReader.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 
00015 #include "zypp/base/LogTools.h"
00016 #include "zypp/base/String.h"
00017 #include "zypp/base/IOStream.h"
00018 #include "zypp/base/UserRequestException.h"
00019 #include "zypp/parser/ParseException.h"
00020 
00021 #include "zypp/parser/susetags/ContentFileReader.h"
00022 #include "zypp/parser/susetags/RepoIndex.h"
00023 #include "zypp/data/ResolvableData.h"
00024 #include "zypp/CapFactory.h"
00025 
00026 #include "zypp/ZConfig.h"
00027 
00028 using std::endl;
00029 #undef  ZYPP_BASE_LOGGER_LOGGROUP
00030 #define ZYPP_BASE_LOGGER_LOGGROUP "parser::susetags"
00031 
00033 namespace zypp
00034 { 
00035 
00036   namespace parser
00037   { 
00038 
00039     namespace susetags
00040     { 
00041 
00043       //
00044       //        CLASS NAME : ContentFileReader::Impl
00045       //
00047       struct ContentFileReader::Impl
00048       {
00049         public:
00050           Impl( const ContentFileReader & parent_r )
00051           : _parent( parent_r )
00052           {}
00053 
00054           data::Product & product()
00055           {
00056             if ( !_product )
00057               _product = new data::Product;
00058             return *_product;
00059           }
00060 
00061           RepoIndex & repoindex()
00062           {
00063             if ( !_repoindex )
00064               _repoindex = new RepoIndex;
00065             return *_repoindex;
00066           }
00067 
00068           bool hasProduct() const
00069           { return _product; }
00070 
00071           bool hasRepoIndex() const
00072           { return _repoindex; }
00073 
00074           data::Product_Ptr handoutProduct()
00075           {
00076             data::Product_Ptr ret;
00077             ret.swap( _product );
00078             _product = 0;
00079             return ret;
00080           }
00081 
00082           RepoIndex_Ptr handoutRepoIndex()
00083           {
00084             RepoIndex_Ptr ret;
00085             ret.swap( _repoindex );
00086             _repoindex = 0;
00087             return ret;
00088           }
00089 
00090         public:
00091           bool isRel( const std::string & rel_r ) const
00092           {
00093             try
00094             {
00095               Rel( rel_r );
00096               return true;
00097             }
00098             catch (...)
00099             {}
00100             return false;
00101           }
00102 
00103           bool setUrlList( std::list<Url> & list_r, const std::string & value ) const
00104           {
00105             bool errors = false;
00106             std::list<std::string> urls;
00107             if ( str::split( value, std::back_inserter(urls) ) )
00108             {
00109               for ( std::list<std::string>::const_iterator it = urls.begin();
00110                     it != urls.end(); ++it )
00111               {
00112                 try
00113                 {
00114                   list_r.push_back( *it );
00115                 }
00116                 catch( const Exception & excpt_r )
00117                 {
00118                   WAR << *it << ": " << excpt_r << endl;
00119                   errors = true;
00120                 }
00121               }
00122             }
00123             return errors;
00124           }
00125 
00126           void setDependencies( data::DependencyList & deplist_r, const std::string & value ) const
00127           {
00128             std::list<std::string> words;
00129             str::split( value, std::back_inserter( words ) );
00130 
00131             for ( std::list<std::string>::const_iterator it = words.begin();
00132                   it != words.end(); ++it )
00133             {
00134               Resolvable::Kind kind( ResTraits<Package>::kind );
00135 
00136               std::string name = *it;
00137               std::string::size_type colon = name.find( ":" );
00138               if ( colon != std::string::npos )
00139               {
00140                 std::string skind( name, 0, colon );
00141                 name.erase( 0, colon+1 );
00142 
00143                 if ( skind == ResTraits<Pattern>::kind )
00144                   kind = ResTraits<Pattern>::kind;
00145                 else if ( skind == ResTraits<Patch>::kind )
00146                   kind = ResTraits<Patch>::kind;
00147                 else if ( skind == ResTraits<Product>::kind )
00148                   kind = ResTraits<Product>::kind;
00149                 else if ( skind == ResTraits<Selection>::kind )
00150                   kind = ResTraits<Selection>::kind;
00151                 else if ( skind != ResTraits<Package>::kind )
00152                 {
00153                   // colon but no kind ==> colon in a name
00154                   name = skind + ":" + name;
00155                 }
00156               }
00157 
00158               // check for Rel:
00159               std::list<std::string>::const_iterator next = it;
00160               if ( ++next != words.end()
00161                    && (*next).find_first_of( "<>=" ) != std::string::npos )
00162               {
00163                 std::string op = *next;
00164                 if ( ++next != words.end() )
00165                 {
00166                   name += " ";
00167                   name += op;
00168                   name += " ";
00169                   name += *next;
00170                   it = next;
00171                 }
00172               }
00173 
00174               // Add the dependency
00175               deplist_r.insert( capability::parse( kind, name ) );
00176             }
00177           }
00178 
00179           bool setFileCheckSum( std::map<std::string, CheckSum> & map_r, const std::string & value ) const
00180           {
00181             bool error = false;
00182             std::vector<std::string> words;
00183             if ( str::split( value, std::back_inserter( words ) ) == 3 )
00184             {
00185               map_r[words[2]] = CheckSum( words[0], words[1] );
00186             }
00187             else
00188             {
00189               error = true;
00190             }
00191             return error;
00192           }
00193 
00194         public:
00195           std::string _inputname;
00196 
00197         private:
00198           const ContentFileReader & _parent;
00199           data::Product_Ptr  _product;
00200           RepoIndex_Ptr      _repoindex;
00201       };
00203 
00205       //
00206       //        CLASS NAME : ContentFileReader
00207       //
00209 
00211       //
00212       //        METHOD NAME : ContentFileReader::ContentFileReader
00213       //        METHOD TYPE : Ctor
00214       //
00215       ContentFileReader::ContentFileReader()
00216       {}
00217 
00219       //
00220       //        METHOD NAME : ContentFileReader::~ContentFileReader
00221       //        METHOD TYPE : Dtor
00222       //
00223       ContentFileReader::~ContentFileReader()
00224       {}
00225 
00227       //
00228       //        METHOD NAME : ContentFileReader::beginParse
00229       //        METHOD TYPE : void
00230       //
00231       void ContentFileReader::beginParse()
00232       {
00233         _pimpl.reset( new Impl(*this) );
00234       }
00235 
00237       //
00238       //        METHOD NAME : ContentFileReader::endParse
00239       //        METHOD TYPE : void
00240       //
00241       void ContentFileReader::endParse()
00242       {
00243         // consume oldData
00244         if ( _pimpl->hasProduct() )
00245         {
00246           if ( _productConsumer )
00247             _productConsumer( _pimpl->handoutProduct() );
00248         }
00249         if ( _pimpl->hasRepoIndex() )
00250         {
00251           if ( _repoIndexConsumer )
00252             _repoIndexConsumer( _pimpl->handoutRepoIndex() );
00253         }
00254 
00255         MIL << "[Content]" << endl;
00256         _pimpl.reset();
00257       }
00258 
00260       //
00261       //        METHOD NAME : ContentFileReader::userRequestedAbort
00262       //        METHOD TYPE : void
00263       //
00264       void ContentFileReader::userRequestedAbort( unsigned lineNo_r )
00265       {
00266         ZYPP_THROW( AbortRequestException( errPrefix( lineNo_r ) ) );
00267       }
00268 
00270       //
00271       //        METHOD NAME : ContentFileReader::errPrefix
00272       //        METHOD TYPE : std::string
00273       //
00274       std::string ContentFileReader::errPrefix( unsigned lineNo_r,
00275                                                 const std::string & msg_r,
00276                                                 const std::string & line_r ) const
00277       {
00278         return str::form( "%s:%u:%s | %s",
00279                           _pimpl->_inputname.c_str(),
00280                           lineNo_r,
00281                           line_r.c_str(),
00282                           msg_r.c_str() );
00283       }
00284 
00286       //
00287       //        METHOD NAME : ContentFileReader::parse
00288       //        METHOD TYPE : void
00289       //
00290       void ContentFileReader::parse( const InputStream & input_r,
00291                                      const ProgressData::ReceiverFnc & fnc_r )
00292       {
00293         MIL << "Start parsing " << input_r << endl;
00294         if ( ! input_r.stream() )
00295         {
00296           std::ostringstream s;
00297           s << "Can't read bad stream: " << input_r;
00298           ZYPP_THROW( ParseException( s.str() ) );
00299         }
00300         beginParse();
00301         _pimpl->_inputname = input_r.name();
00302 
00303         ProgressData ticks( makeProgressData( input_r ) );
00304         ticks.sendTo( fnc_r );
00305         if ( ! ticks.toMin() )
00306           userRequestedAbort( 0 );
00307 
00308         Arch sysarch( ZConfig::instance().systemArchitecture() );
00309 
00310         iostr::EachLine line( input_r );
00311         for( ; line; line.next() )
00312         {
00313           // strip 1st word from line to separate tag and value.
00314           std::string value( *line );
00315           std::string key( str::stripFirstWord( value, /*ltrim_first*/true ) );
00316 
00317           if ( key.empty() || *key.c_str() == '#' ) // empty or comment line
00318           {
00319             continue;
00320           }
00321 
00322           // strip modifier if exists
00323           std::string modifier;
00324           std::string::size_type pos = key.rfind( '.' );
00325           if ( pos != std::string::npos )
00326           {
00327             modifier = key.substr( pos+1 );
00328             key.erase( pos );
00329           }
00330 
00331           //
00332           // Product related data:
00333           //
00334           if ( key == "PRODUCT" )
00335           {
00336             std::replace( value.begin(), value.end(), ' ', '_' );
00337             _pimpl->product().name = value;
00338           }
00339           else if ( key == "VERSION" )
00340           {
00341             _pimpl->product().edition = value;
00342           }
00343           else if ( key == "ARCH" )
00344           {
00345             // Default product arch is noarch. We update, if the
00346             // ARCH.xxx tag is better than the current product arch
00347             // and still compatible with the sysarch.
00348             Arch carch( modifier );
00349             if ( Arch::compare( _pimpl->product().arch, carch ) < 0
00350                  &&  carch.compatibleWith( sysarch ) )
00351             {
00352               _pimpl->product().arch = carch;
00353             }
00354           }
00355           else if ( key == "DISTPRODUCT" )
00356           {
00357             _pimpl->product().distributionName = value;
00358           }
00359           else if ( key == "DISTVERSION" )
00360           {
00361             _pimpl->product().distributionEdition = value;
00362           }
00363           else if ( key == "VENDOR" )
00364           {
00365             _pimpl->product().vendor = value;
00366           }
00367           else if ( key == "LABEL" )
00368           {
00369             _pimpl->product().summary.setText( value, Locale(modifier) );
00370           }
00371           else if ( key == "SHORTLABEL" )
00372           {
00373             _pimpl->product().shortName.setText( value, Locale(modifier) );
00374           }
00375           else if ( key == "TYPE" )
00376           {
00377             _pimpl->product().type = value;
00378           }
00379           else if ( key == "RELNOTESURL" )
00380           {
00381             for( std::string::size_type pos = value.find("%a");
00382                  pos != std::string::npos;
00383                  pos = value.find("%a") )
00384             {
00385               value.replace( pos, 2, sysarch.asString() );
00386             }
00387             try
00388             {
00389               _pimpl->product().releasenotesUrl = value;
00390             }
00391             catch( const Exception & excpt_r )
00392             {
00393               WAR << errPrefix( line.lineNo(), excpt_r.asString(), *line ) << endl;
00394             }
00395           }
00396           else if ( key == "UPDATEURLS" )
00397           {
00398             if ( _pimpl->setUrlList( _pimpl->product().updateUrls, value ) )
00399             {
00400               WAR << errPrefix( line.lineNo(), "Ignored malformed URL(s)", *line ) << endl;
00401             }
00402           }
00403           else if ( key == "EXTRAURLS" )
00404           {
00405             if ( _pimpl->setUrlList( _pimpl->product().extraUrls, value ) )
00406             {
00407               WAR << errPrefix( line.lineNo(), "Ignored malformed URL(s)", *line ) << endl;
00408             }
00409           }
00410           else if ( key == "OPTIONALURLS" )
00411           {
00412             if ( _pimpl->setUrlList( _pimpl->product().optionalUrls, value ) )
00413             {
00414               WAR << errPrefix( line.lineNo(), "Ignored malformed URL(s)", *line ) << endl;
00415             }
00416           }
00417           else if ( key == "PREREQUIRES" )
00418           {
00419             _pimpl->setDependencies( _pimpl->product().deps[Dep::PREREQUIRES], value );
00420           }
00421           else if ( key == "REQUIRES" )
00422           {
00423             _pimpl->setDependencies( _pimpl->product().deps[Dep::REQUIRES], value );
00424           }
00425           else if ( key == "PROVIDES" )
00426           {
00427             _pimpl->setDependencies( _pimpl->product().deps[Dep::PROVIDES], value );
00428           }
00429           else if ( key == "CONFLICTS" )
00430           {
00431             _pimpl->setDependencies( _pimpl->product().deps[Dep::CONFLICTS], value );
00432           }
00433           else if ( key == "OBSOLETES" )
00434           {
00435             _pimpl->setDependencies( _pimpl->product().deps[Dep::OBSOLETES], value );
00436           }
00437           else if ( key == "RECOMMENDS" )
00438           {
00439             _pimpl->setDependencies( _pimpl->product().deps[Dep::RECOMMENDS], value );
00440           }
00441           else if ( key == "SUGGESTS" )
00442           {
00443             _pimpl->setDependencies( _pimpl->product().deps[Dep::SUGGESTS], value );
00444           }
00445           else if ( key == "SUPPLEMENTS" )
00446           {
00447             _pimpl->setDependencies( _pimpl->product().deps[Dep::SUPPLEMENTS], value );
00448           }
00449           else if ( key == "ENHANCES" )
00450           {
00451             _pimpl->setDependencies( _pimpl->product().deps[Dep::ENHANCES], value );
00452           }
00453           //
00454           // ReppoIndex related data:
00455           //
00456           else if ( key == "DEFAULTBASE" )
00457           {
00458             _pimpl->repoindex().defaultBase = Arch(value);
00459           }
00460           else if ( key == "DESCRDIR" )
00461           {
00462             _pimpl->repoindex().descrdir = value;
00463           }
00464           else if ( key == "DATADIR" )
00465           {
00466             _pimpl->repoindex().datadir = value;
00467           }
00468           else if ( key == "FLAGS" )
00469           {
00470             str::split( value, std::back_inserter( _pimpl->repoindex().flags ) );
00471           }
00472           else if ( key == "KEY" )
00473           {
00474             if ( _pimpl->setFileCheckSum( _pimpl->repoindex().signingKeys, value ) )
00475             {
00476               ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [KEY algorithm checksum filename]", *line ) ) );
00477             }
00478           }
00479           else if ( key == "LANGUAGE" )
00480           {
00481             _pimpl->repoindex().language;
00482           }
00483           else if ( key == "LINGUAS" )
00484           {
00485             std::set<std::string> strval;
00486             str::split( value, std::inserter( strval, strval.end() ) );
00487             for ( std::set<std::string>::const_iterator it = strval.begin(); it != strval.end(); ++it )
00488             {
00489               _pimpl->repoindex().languages.push_back( Locale(*it) );
00490             }
00491           }
00492           else if ( key == "META" )
00493           {
00494             if ( _pimpl->setFileCheckSum( _pimpl->repoindex().metaFileChecksums, value ) )
00495             {
00496               ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
00497             }
00498           }
00499           else if ( key == "HASH" )
00500           {
00501             if ( _pimpl->setFileCheckSum( _pimpl->repoindex().mediaFileChecksums, value ) )
00502             {
00503               ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
00504             }
00505           }
00506           else if ( key == "TIMEZONE" )
00507           {
00508             _pimpl->repoindex().timezone = value;
00509           }
00510           else
00511           { WAR << errPrefix( line.lineNo(), "Unknown tag", *line ) << endl; }
00512 
00513 
00514           if ( ! ticks.set( input_r.stream().tellg() ) )
00515             userRequestedAbort( line.lineNo() );
00516         }
00517 
00518         //
00519         // post processing
00520         //
00521         if ( _pimpl->hasProduct() )
00522         {
00523           // Insert a "Provides" _dist_name" == _dist_version"
00524           if ( ! _pimpl->product().distributionName.empty() )
00525           {
00526             _pimpl->product().deps[Dep::PROVIDES].insert(
00527                 capability::parse( ResTraits<Product>::kind,
00528                                    _pimpl->product().distributionName,
00529                                    Rel::EQ,
00530                                    _pimpl->product().distributionEdition ) );
00531           }
00532         }
00533         if ( ! ticks.toMax() )
00534           userRequestedAbort( line.lineNo() );
00535 
00536         endParse();
00537         MIL << "Done parsing " << input_r << endl;
00538       }
00539 
00541     } // namespace susetags
00544   } // namespace parser
00547 } // namespace zypp

Generated on Tue Sep 25 19:23:02 2007 for libzypp by  doxygen 1.5.3