PackagesParser.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 
00014 #include <boost/regex.hpp>
00015 
00016 #include "zypp/base/Logger.h"
00017 
00018 #include "zypp/source/susetags/PackagesParser.h"
00019 #include "zypp/parser/tagfile/TagFileParser.h"
00020 #include "zypp/Arch.h"
00021 #include "zypp/Package.h"
00022 #include "zypp/CapFactory.h"
00023 #include "zypp/CapSet.h"
00024 
00025 #include "zypp/ZYppFactory.h"
00026 
00027 using std::endl;
00028 
00030 namespace zypp
00031 { 
00032 
00033   namespace source
00034   { 
00035 
00036     namespace susetags
00037     { 
00038 
00039       using namespace parser::tagfile;
00040 
00041 
00042       struct PackageDiskUsageParser : public parser::tagfile::TagFileParser
00043       {
00044         PkgDiskUsage result;
00045         NVRAD _current_nvrad;
00046         bool _pkg_pending;
00047         boost::regex sizeEntryRX;
00048 
00049         virtual void beginParse()
00050         {
00051           _pkg_pending = false;
00052           sizeEntryRX = boost::regex("^(.*/)[[:space:]]([[:digit:]]+)[[:space:]]([[:digit:]]+)[[:space:]]([[:digit:]]+)[[:space:]]([[:digit:]]+)$");
00053         }
00054 
00055         /* Consume SingleTag data. */
00056         virtual void consume( const SingleTag & stag_r )
00057         {
00058           if ( stag_r.name == "Pkg" )
00059           {
00060             std::vector<std::string> words;
00061             if ( str::split( stag_r.value, std::back_inserter(words) ) != 4 )
00062               ZYPP_THROW( ParseException( "packages.DU - Expected [name version release arch], got [" + stag_r.value +"]") );
00063 
00064             _pkg_pending = true;
00065             _current_nvrad = NVRAD( words[0], Edition(words[1],words[2]), Arch(words[3]) );
00066           }
00067           else if ( stag_r.name == "Ver" )
00068           {
00069             if (stag_r.value != "2.0")
00070               WAR << "packages.DU " << stag_r.name << "=" << stag_r.value << ", should be 2.0" << endl;
00071           }
00072           else
00073           {
00074             //ZYPP_THROW( ParseException( "Unknown tag" ) );
00075             ERR << "packages.DU - ERROR! found unexpected tag " << stag_r.name << std::endl;
00076           }
00077         }
00078 
00079         /* Consume MulitTag data. */
00080         virtual void consume( const MultiTag & mtag_r )
00081         {
00082           if ( ! _pkg_pending )
00083             return;
00084 
00085           if ( mtag_r.name == "Dir" )
00086           {
00087             DiskUsage usage;
00088             for (std::list<std::string>::const_iterator it = mtag_r.values.begin(); it != mtag_r.values.end(); ++it )
00089             {
00090               boost::smatch what;
00091               if(boost::regex_match(*it, what, sizeEntryRX, boost::match_extra))
00092               {
00093                 //zypp::parser::tagfile::dumpRegexpResults(what);
00094                 // build the disk usage info
00095                 usage.add( what[1], str::strtonum<unsigned int>(what[2]) + str::strtonum<unsigned int>(what[3]), str::strtonum<unsigned int>(what[4]) + str::strtonum<unsigned  int>(what[5]));
00096               }
00097               else
00098               {
00099                 ZYPP_THROW( ParseException( std::string("Error parsing package size entry") + "[" + *it + "]" ) );
00100               }
00101             }
00102             result[_current_nvrad] = usage;
00103             _pkg_pending = false;
00104           }
00105         }
00106 
00107         virtual void endParse()
00108         {
00109 
00110         }
00111       };
00112 
00113 
00114       struct PackagesParser : public parser::tagfile::TagFileParser
00115       {
00116         PkgContent _result;
00117 
00118         Source_Ref _source;
00119         SuseTagsImpl::Ptr _sourceImpl;
00120 
00121         bool _isPendingPkg;
00122         PkgImplPtr _pkgImpl;
00123         SrcPkgImplPtr _srcPkgImpl;
00124         NVRAD _nvrad;
00125         bool _isShared;
00126 
00127         Arch _system_arch;
00128 
00129         PackagesParser(Source_Ref source, SuseTagsImpl::Ptr sourceimpl)
00130                : _source( source )
00131                , _sourceImpl( sourceimpl )
00132                , _isPendingPkg( false )
00133                , _isShared( false )
00134         {
00135             ZYpp::Ptr z = getZYpp();
00136             _system_arch = z->architecture();
00137         }
00138 
00139         PkgContent result() const
00140         { return _result; }
00141 
00142         void collectPkg()
00143         {
00144           if ( _isPendingPkg )
00145           {
00146             _pkgImpl->_sourceImpl = _sourceImpl;
00147             // if the package does not depend on other package for its data
00148             // then use its own nvrad as an index
00149             if ( !_isShared )
00150             {
00151               _pkgImpl->_data_index =  _pkgImpl->_nvra;
00152               _sourceImpl->_is_shared[ _pkgImpl->_nvra] = false;
00153             }
00154             else
00155             {
00156               _sourceImpl->_is_shared[ _pkgImpl->_nvra] = true;
00157             }
00158           
00159             if (_srcPkgImpl == NULL                                     // only if its not a src/nosrc
00160                 && _nvrad.arch.compatibleWith( _system_arch ) )
00161             {
00162               _result.insert( PkgContent::value_type( _nvrad, _pkgImpl ) );
00163             }
00164             _isPendingPkg = false;
00165           }
00166         }
00167 
00168         void collectDeps( const std::list<std::string> & depstr_r, CapSet & capset )
00169         {
00170           for ( std::list<std::string>::const_iterator it = depstr_r.begin();
00171                 it != depstr_r.end(); ++it )
00172           {
00173             try {
00174               capset.insert( CapFactory().parse( ResTraits<Package>::kind, *it ) );
00175             }
00176             catch (Exception & excpt_r) {
00177               ZYPP_THROW( ParseException("Bad source ["+ _source.alias() +"] at URL:[" + _source.url().asString() + "]. Can't parse capability: [" + *it + "]" ) );
00178             }
00179           }
00180         }
00181 
00182         /* Consume SingleTag data. */
00183         virtual void consume( const SingleTag & stag_r )
00184         {
00185           if ( stag_r.name == "Pkg" )
00186           {
00187             // reset
00188             // this means this is either the first package, or we just finished parsing a package and a new one is starting
00189             // collect previous pending package if needed
00190             collectPkg();
00191             // reset
00192             _isShared = false;
00193             std::vector<std::string> words;
00194             str::split( stag_r.value, std::back_inserter(words) );
00195 
00196             if ( str::split( stag_r.value, std::back_inserter(words) ) != 4 )
00197               ZYPP_THROW( ParseException("Bad source ["+ _source.alias() +"] at URL:[" + _source.url().asString() + "]. error, we expected NVRA here, got: " + stag_r.value ) );
00198 
00199             std::string arch = words[3];
00200 #warning read comment in file
00201             // warning: according to autobuild, this is the wrong check
00202             //  a 'src/norsrc' packages is determined by _not_ having a "=Src:" tag in packages
00203             // However, the 'arch' string we're checking here must be remembered since
00204             // it determines the directory below the <DATADIR> where the real package
00205             // can be found.
00206             if (arch == "src"
00207                 || arch == "nosrc")
00208             {
00209                 arch = "noarch";
00210                 _srcPkgImpl = SrcPkgImplPtr( new source::susetags::SuseTagsSrcPackageImpl( _source ) );
00211             }
00212             else
00213                 _srcPkgImpl = NULL;
00214 
00215             _pkgImpl = PkgImplPtr( new source::susetags::SuseTagsPackageImpl( _source ) );
00216             _nvrad = NVRAD( words[0], Edition( words[1], words[2] ), Arch( arch ) );
00217             _pkgImpl->_nvra = NVRA( words[0], Edition( words[1], words[2] ), Arch( arch ) );
00218 
00219             _isPendingPkg = true;
00220 
00221           }
00222           else if ( stag_r.name == "Cks" )
00223           {
00224             std::vector<std::string> words;
00225             if ( str::split( stag_r.value, std::back_inserter(words) ) != 2 )
00226               ZYPP_THROW( ParseException("Bad source ["+ _source.alias() +"] at URL:[" + _source.url().asString() + "]. Key: [" + stag_r.name + "] - Expected [type checksum], got [" + stag_r.value +"]"));
00227 
00228             _pkgImpl->_checksum = CheckSum(words[0], words[1]);
00229           }
00230           else if ( stag_r.name == "Shr" )
00231           {
00232             // shared description tags
00233             std::vector<std::string> words;
00234             str::split( stag_r.value, std::back_inserter(words) );
00235 
00236             if ( str::split( stag_r.value, std::back_inserter(words) ) != 4 )
00237               ZYPP_THROW( ParseException("Bad source ["+ _source.alias() +"] at URL:[" + _source.url().asString() + "]. Shr tag is wrong, expected NVRA, got: " + stag_r.value ) );
00238 
00239             std::string arch = words[3];
00240             NVRA shared_desc( words[0], Edition( words[1], words[2] ), Arch(arch));
00241             XXX << "package " << _nvrad << " shares data with " << shared_desc << std::endl;
00242             _isShared = true;
00243             _pkgImpl->_data_index = shared_desc;
00244             // mark the refering package as a package providing data to others
00245             // because we cant filter those by architecture to save memory
00246             // or we run in missing package descriptions for x86_64 packages
00247             // which depends on a ppc package for its data.
00248             _sourceImpl->_provides_shared_data[ _pkgImpl->_data_index] = true;
00249           }
00250           if ( stag_r.name == "Grp" )
00251           {
00252             _pkgImpl->_group = stag_r.value;
00253           }
00254           if ( stag_r.name == "Lic" )
00255           {
00256             _pkgImpl->_license = stag_r.value;
00257           }
00258           if ( stag_r.name == "Tim" )
00259           {
00260             _pkgImpl->_buildtime = Date(str::strtonum<time_t>(stag_r.value));
00261           }
00262           if ( stag_r.name == "Siz" )
00263           {
00264             std::vector<std::string> words;
00265             if ( str::split( stag_r.value, std::back_inserter(words) ) != 2 )
00266               ZYPP_THROW( ParseException("Bad source ["+ _source.alias() +"] at URL:[" + _source.url().asString() + "]. Siz tag wrong. Got [" + stag_r.value + "]" ) );
00267 
00268             _pkgImpl->_archivesize = str::strtonum<unsigned long>(words[0]);
00269             _pkgImpl->_size = str::strtonum<unsigned long>(words[1]);
00270           }
00271           if ( stag_r.name == "Loc" )
00272           {
00273             std::vector<std::string> words;
00274             unsigned int howmany = str::split( stag_r.value, std::back_inserter(words) );
00275             _pkgImpl->_media_number = 1;
00276             if ( howmany >= 2 )
00277             {
00278               _pkgImpl->_media_number = str::strtonum<unsigned int>(words[0]);
00279               // if a 3rd value is given, use it as the directory specifier, else default to the architecture
00280               _pkgImpl->_location = _sourceImpl->sourceDir( (howmany > 2) ? words[2] : _nvrad.arch.asString() ) + words[1];
00281             }
00282             else
00283             {
00284                 ZYPP_THROW( ParseException("Bad source ["+ _source.alias() +"] at URL:[" + _source.url().asString() + "]. Bad [Loc] tag. Got: [" + stag_r.value + "]"));
00285             }
00286             // ignore path
00287           }
00288         }
00289 
00290         /* Consume MulitTag data. */
00291         virtual void consume( const MultiTag & mtag_r )
00292         {
00293           if ( ! _isPendingPkg )
00294             return;
00295 
00296           if ( mtag_r.name == "Prv" )
00297             {
00298               collectDeps( mtag_r.values, _nvrad[Dep::PROVIDES] );
00299             }
00300           else if ( mtag_r.name == "Prq" )
00301             {
00302               collectDeps( mtag_r.values, _nvrad[Dep::PREREQUIRES] );
00303             }
00304           else if ( mtag_r.name == "Req" )
00305             {
00306               collectDeps( mtag_r.values, _nvrad[Dep::REQUIRES] );
00307             }
00308           else if ( mtag_r.name == "Con" )
00309             {
00310               collectDeps( mtag_r.values, _nvrad[Dep::CONFLICTS] );
00311             }
00312           else if ( mtag_r.name == "Obs" )
00313             {
00314               collectDeps( mtag_r.values, _nvrad[Dep::OBSOLETES] );
00315             }
00316           else if ( mtag_r.name == "Rec" )
00317             {
00318               collectDeps( mtag_r.values, _nvrad[Dep::RECOMMENDS] );
00319             }
00320           else if ( mtag_r.name == "Sup" )
00321             {
00322               collectDeps( mtag_r.values, _nvrad[Dep::SUPPLEMENTS] );
00323             }
00324           else if ( mtag_r.name == "Sug" )
00325             {
00326               collectDeps( mtag_r.values, _nvrad[Dep::SUGGESTS] );
00327             }
00328           else if ( mtag_r.name == "Fre" )
00329             {
00330               collectDeps( mtag_r.values, _nvrad[Dep::FRESHENS] );
00331             }
00332           else if ( mtag_r.name == "Enh" )
00333             {
00334               collectDeps( mtag_r.values, _nvrad[Dep::ENHANCES] );
00335             }
00336           else if ( mtag_r.name == "Key" )
00337             {
00338                _pkgImpl->_keywords = mtag_r.values;
00339             }
00340           else if ( mtag_r.name == "Aut" )
00341             {
00342               // MultiTag is a Set but author is a list
00343               _pkgImpl->_authors = mtag_r.values;
00344             }
00345         }
00346 
00347         virtual void endParse()
00348         {
00349           // collect last package if there is one
00350           collectPkg();
00351         }
00352       };
00353 
00355 
00356       PkgContent parsePackages( Source_Ref source_r, SuseTagsImpl::Ptr sourceImpl_r, const Pathname & file_r )
00357       {
00358         MIL << "Starting to parse packages " << file_r << std::endl;
00359         PackagesParser p( source_r, sourceImpl_r );
00360         try
00361         {
00362           p.parse( file_r );
00363         }
00364         catch(zypp::parser::tagfile::ParseException &e)
00365         {
00366           ZYPP_CAUGHT(e);
00367           ERR <<  "Source [" << source_r.alias() << "] at URL:[" << source_r.url().asString() << "] has a broken packages file." << std::endl;
00368           ZYPP_RETHROW(e);
00369         }
00370         return p.result();
00371       }
00372 
00373       PkgDiskUsage parsePackagesDiskUsage( const Pathname & file_r )
00374       {
00375         MIL << "Starting to parse packages disk usage " << file_r << std::endl;
00376         PackageDiskUsageParser duParser;
00377         try
00378         {
00379           duParser.parse(file_r);
00380         }
00381         catch(zypp::parser::tagfile::ParseException &e)
00382         {
00383           ZYPP_CAUGHT(e);
00384           ERR <<  "Broken disk usage file " << file_r << ". Ignoring." << std::endl;
00385           ZYPP_RETHROW(e);
00386         }
00387         return duParser.result;
00388       }
00389 
00391     } // namespace susetags
00394   } // namespace source
00397 } // namespace zypp

Generated on Thu Jul 6 00:07:24 2006 for zypp by  doxygen 1.4.6