00001
00002
00003
00004
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
00056
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
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
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
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 }
00190
00191
00192
00193 try
00194 {
00195
00196
00197
00198 Arch sysarch( getZYpp()->architecture() );
00199 Arch prodarch( Arch_noarch );
00200
00201
00202
00203 std::map< std::string, std::list<std::string> >::const_iterator it = prodImpl->_arch.find( sysarch.asString() );
00204
00205
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 )) {
00213 continue;
00214 }
00215 if (arch.compare( prodarch ) > 0) {
00216 prodarch = arch;
00217 it = it1;
00218 }
00219 }
00220 }
00221
00222
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() );
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()) {
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 }
00347 }
00350 }