PackagesParser.cc

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

Generated on Tue Nov 28 16:49:32 2006 for zypp by  doxygen 1.5.0