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

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