ProductMetadataParser.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 #include <sstream>
00015 
00016 #include <boost/tokenizer.hpp>
00017 #include <boost/algorithm/string.hpp>
00018 
00019 #include "zypp/ZYppFactory.h"
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/base/Exception.h"
00022 #include "zypp/base/PtrTypes.h"
00023 #include "zypp/base/String.h"
00024 
00025 #include "zypp/CapFactory.h"
00026 
00027 #include "zypp/source/susetags/ProductMetadataParser.h"
00028 #include "zypp/source/susetags/SuseTagsProductImpl.h"
00029 #include <boost/regex.hpp>
00030 
00031 #undef ZYPP_BASE_LOGGER_LOGGROUP
00032 #define ZYPP_BASE_LOGGER_LOGGROUP "ProductMetadataParser"
00033 
00034 using namespace std;
00035 using namespace boost;
00036 
00037 typedef find_iterator<string::iterator> string_find_iterator;
00038 
00040 namespace zypp
00041 { 
00042 
00043   namespace source
00044   { 
00045 
00046     namespace susetags
00047     { 
00048       ProductMetadataParser::ProductMetadataParser()
00049       {
00050         prodImpl = new SuseTagsProductImpl;
00051       }
00052 
00054       //
00055       //        METHOD NAME : Parser::parse
00056       //        METHOD TYPE : void
00057       //
00058       void ProductMetadataParser::parse( const Pathname & file_r, Source_Ref source_r )
00059       {
00060         std::ifstream file(file_r.asString().c_str());
00061 
00062         if (!file) {
00063             ZYPP_THROW (Exception("Can't read product file :" + file_r.asString()));
00064         }
00065 
00066         std::string buffer;
00067         volatile_content = false;
00068         while(file && !file.eof())
00069         {
00070           getline(file, buffer);
00071           boost::regex e("^(([A-Z]+)(\\.([_A-Z0-9a-z]+)){0,1}) (.+)$");
00072           boost::smatch what;
00073           if(boost::regex_match(buffer, what, e, boost::match_extra))
00074           {
00075             if ( what.size() < 5 )
00076               std::cout << "ups!!!!" << std::endl;
00077 
00078             std::string key = what[2];
00079             std::string value = what[5];
00080             std::string modifier = what[4];
00081             if(key == "PRODUCT")
00082               prodImpl->_name = value;
00083             else if(key == "VERSION")
00084               prodImpl->_version = value;
00085             else if(key == "DISTPRODUCT")
00086               prodImpl->_dist = value;
00087             else if(key == "DISTVERSION")
00088               prodImpl->_dist_version = value;
00089              else if(key == "BASEPRODUCT")
00090               prodImpl->_base_product = value;
00091             else if(key == "BASEVERSION")
00092               prodImpl->_base_version = value;
00093             else if(key == "YOUTYPE")
00094               prodImpl->_you_type = value;
00095             else if(key == "VENDOR")
00096               prodImpl->_vendor = value;
00097             else if(key == "SHORTLABEL")
00098               prodImpl->_shortlabel = value;
00099             else if(key == "RELNOTESURL")
00100             {
00101                 // Url class throws in case of invalid URL
00102                 try
00103                 {
00104                     Url url (value) ;
00105                     prodImpl->_release_notes_url = url;
00106                 }
00107                 catch( ... )
00108                 {
00109                     prodImpl->_release_notes_url = Url();
00110                 }
00111             }
00112             else if(key == "UPDATEURLS")
00113             {
00114                 std::list<std::string> items;
00115                 boost::algorithm::split(items, value, is_space());
00116                 std::list<std::string>::const_iterator
00117                     b = items.begin(),
00118                     e = items.end(),
00119                     i;
00120                 for (i = b; i != e; ++i)
00121                 {
00122                     // Url class throws in case of invalid URL
00123                     try
00124                     {
00125                         Url url = *i;
00126                         prodImpl->_update_urls.push_back( url );
00127                     }
00128                     catch( ... )
00129                     {
00130                         // do not add
00131                     }
00132                 }
00133             }
00134             else if(key == "ARCH")
00135               parseLine( key, modifier, value, prodImpl->_arch);
00136             else if(key == "DEFAULTBASE")
00137               prodImpl->_default_base = value;
00138             else if(key == "PREREQUIRES")
00139               parseDependencies( key, value, prodImpl->_deps, Dep::PREREQUIRES);
00140             else if(key == "REQUIRES")
00141               parseDependencies( key, value, prodImpl->_deps, Dep::REQUIRES);
00142             else if(key == "PROVIDES")
00143               parseDependencies( key, value, prodImpl->_deps, Dep::PROVIDES);
00144             else if(key == "CONFLICTS")
00145               parseDependencies( key, value, prodImpl->_deps, Dep::CONFLICTS);
00146             else if(key == "OBSOLETES")
00147               parseDependencies( key, value, prodImpl->_deps, Dep::OBSOLETES);
00148             else if(key == "RECOMMENDS")
00149               parseDependencies( key, value, prodImpl->_deps, Dep::RECOMMENDS);
00150             else if(key == "SUGGESTS")
00151               parseDependencies( key, value, prodImpl->_deps, Dep::SUGGESTS);
00152             else if(key == "SUPPLEMENTS")
00153               parseDependencies( key, value, prodImpl->_deps, Dep::SUPPLEMENTS);
00154             else if(key == "ENHANCES")
00155               parseDependencies( key, value, prodImpl->_deps, Dep::ENHANCES);
00156             else if(key == "LINGUAS")
00157               parseLine( key, value, prodImpl->_languages);
00158             else if(key == "LABEL")
00159               parseLine( key, modifier, value, prodImpl->_summary);
00160             else if(key == "DESCRDIR")
00161               prodImpl->_description_dir = value;
00162             else if(key == "DATADIR")
00163               prodImpl->_data_dir = value;
00164             else if(key == "FLAGS")
00165               parseLine( key, value, prodImpl->_flags);
00166             else if(key == "LANGUAGE")
00167               prodImpl->_language = value;
00168             else if(key == "TIMEZONE")
00169               prodImpl->_timezone = value;
00170             else if(key == "META")
00171               parseFileCheckSum( key, value, prodImpl->_descr_files_checksums);
00172             else if(key == "KEY")
00173               parseFileCheckSum( key, value, prodImpl->_signing_keys);
00174             else if(key == "VOLATILE_CONTENT")
00175               volatile_content = true;
00176             else
00177               DBG << "Unknown key [" << key << "] with value [" << value << "]" << std::endl;
00178           }
00179           else if (!buffer.empty())
00180           {
00181             DBG << "** No Match found:  " << buffer << std::endl;
00182           }
00183         } // end while
00184         // finished parsing, store result
00185         // Collect basic Resolvable data
00186 
00187         try
00188         {
00189           // calculate product architecture by looking through ARCH.xxx lines (key of prodImpl->_arch)
00190           //  and taking the 'best' (first) architectures.
00191 
00192           Arch sysarch( getZYpp()->architecture() );
00193           Arch prodarch( Arch_noarch );         // default to noarch
00194 
00195           // find matching ARCH.xxx line
00196 
00197           std::map< std::string, std::list<std::string> >::const_iterator it = prodImpl->_arch.find( sysarch.asString() );
00198 
00199           // if no matching ARCH.xxx line found, search best matching
00200 
00201           if (it == prodImpl->_arch.end()) {
00202             WAR << "Product does not fully support systems architecture (" << sysarch << ")" << endl;
00203 
00204             for (std::map< std::string, std::list<std::string> >::const_iterator it1 = prodImpl->_arch.begin(); it1 != prodImpl->_arch.end(); ++it1) {
00205               Arch arch( it1->first );
00206               if (!arch.compatibleWith( sysarch )) {    // filter out incompatbile ones
00207                 continue;
00208               }
00209               if (arch.compare( prodarch ) > 0) {       // found better than current
00210                 prodarch = arch;                        //  set new current
00211                 it = it1;
00212               }
00213             }
00214           }
00215 
00216           // oops, still no match found ?
00217 
00218           if (it == prodImpl->_arch.end()
00219               || it->second.empty())
00220           {
00221             ERR << "Product incompatible with systems architecture (" << sysarch << ")" << endl;
00222           }
00223           else {
00224             MIL << "Found matching/best arch " << it->first << endl;
00225 
00226             prodarch = Arch( it->second.front() );      // first arch of matching ARCH.xxx line is best
00227           }
00228 
00229           MIL << "Product arch is " << prodarch << endl;
00230 
00231           NVRAD dataCollect( prodImpl->_dist, Edition( prodImpl->_dist_version ), prodarch, prodImpl->_deps );
00232           result = detail::makeResolvableFromImpl( dataCollect, prodImpl );
00233         }
00234         catch (const Exception & excpt_r)
00235         {
00236           ZYPP_THROW(Exception("Error creating product: " + excpt_r.msg()));
00237         }
00238 
00239         prodImpl->_source = source_r;
00240         prodImpl->_category = source_r.baseSource() ? "base" : "add-on";
00241         INT << "Product category set to " << prodImpl->_category << endl;
00242       }
00243 
00244       void ProductMetadataParser::parseLine( const string &key, const string &modif, const string &value, map< string, list<string> > &container)
00245       {
00246         if ( modif.size() == 0)
00247           parseLine( key, value, container["default"]);
00248         else
00249           parseLine( key, value, container[modif]);
00250       }
00251 
00252       void ProductMetadataParser::parseLine( const std::string &key, const std::string &lang, const std::string &value, TranslatedText &container)
00253       {
00254         if ( lang.size() == 0)
00255           container.setText(value, Locale());
00256         else
00257           container.setText(value, Locale(lang));
00258       }
00259 
00260       void ProductMetadataParser::parseLine( const string &key, const string &modif, const string &value, map< string, string > &container)
00261       {
00262         if( modif.size() == 0)
00263           container["default"] = value;
00264         else
00265           container[modif] = value;
00266       }
00267 
00268       void ProductMetadataParser::parseLine( const string &key, const string &value, std::list<std::string> &container)
00269       {
00270           str::split( value, std::back_inserter(container), " ");
00271       }
00272 
00273       void ProductMetadataParser::parseDependencies( const string &key, const string &value, Dependencies & deps, Dep deptag )
00274       {
00275           std::list<std::string> splitted;
00276           str::split( value, std::back_inserter(splitted), " ");
00277           Resolvable::Kind kind;
00278           std::string name;
00279           CapFactory f;
00280           for (std::list<std::string>::const_iterator it = splitted.begin(); it != splitted.end(); ++it) {
00281             string name = *it;
00282             string::size_type colon = name.find(":");
00283             kind  = ResTraits<Package>::kind;
00284             if (colon != string::npos) {
00285                 string skind( name, 0, colon );
00286                 name.erase( 0, colon+1 );
00287                 DBG << "kind " << skind << ", name " << name << endl;
00288                 if (skind == "pattern") kind = ResTraits<Pattern>::kind;
00289                 else if (skind == "patch") kind = ResTraits<Patch>::kind;
00290                 else if (skind == "selection") kind = ResTraits<Selection>::kind;
00291                 else if (skind == "product") kind = ResTraits<Product>::kind;
00292                 else if (skind != "package") ERR << "Bad kind in content::" << key << " '" << skind << "'" << endl;
00293             }
00294             std::list<std::string>::const_iterator next = it;
00295             ++next;
00296             if (next != splitted.end()) {                       // check for "op edition"
00297                 string val = *next;
00298                 if (val.find_first_of("<>=") != string::npos)
00299                 {
00300                     if (++next != splitted.end()) {
00301                         name += val;
00302                         name += *next;
00303                         it = next;
00304                     }
00305                 }
00306             }
00307             try {
00308                 deps[deptag].insert( f.parse( kind, name ) );
00309             }
00310             catch (Exception & excpt_r) {
00311                 ZYPP_CAUGHT( excpt_r );
00312                 ERR << "Ignoring invalid " << key << " entry '" << name << "'" << endl;
00313             }
00314           }
00315       }
00316       
00317       void ProductMetadataParser::parseFileCheckSum( const std::string &key, const std::string &value, std::map<std::string, CheckSum> &container)
00318       {
00319         std::list<std::string> splitted;
00320         str::split( value, std::back_inserter(splitted), " ");
00321         if (splitted.size() != 3)
00322         {
00323           ERR << "Parse error in checksum. Expected [type checksum file], got [" << value << "]" << std::endl;
00324         }
00325         else
00326         {
00327           std::string checksum_type = splitted.front();
00328           splitted.pop_front();
00329           std::string checksum_str = splitted.front();
00330           splitted.pop_front();
00331           std::string filename = splitted.front();
00332           splitted.pop_front();
00333           MIL << "Checksum for " << filename << " is " << checksum_str << " (" << checksum_type << ")" << std::endl;
00334           container[filename] = CheckSum(checksum_type, checksum_str);
00335         }
00336       }
00338     } // namespace susetags
00341   } // namespace source
00344 } // namespace zypp

Generated on Thu May 4 16:03:26 2006 for zypp by  doxygen 1.4.6