1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/parser/susetags/ContentFileReader.cc
15 #include "zypp/base/LogTools.h"
16 #include "zypp/base/String.h"
17 #include "zypp/base/IOStream.h"
18 #include "zypp/base/UserRequestException.h"
19 #include "zypp/parser/ParseException.h"
21 #include "zypp/parser/susetags/ContentFileReader.h"
22 #include "zypp/parser/susetags/RepoIndex.h"
23 #include "zypp/data/ResolvableData.h"
24 #include "zypp/CapFactory.h"
26 #include "zypp/ZConfig.h"
29 #undef ZYPP_BASE_LOGGER_LOGGROUP
30 #define ZYPP_BASE_LOGGER_LOGGROUP "parser::susetags"
32 ///////////////////////////////////////////////////////////////////
34 { /////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////
37 { /////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////
40 { /////////////////////////////////////////////////////////////////
42 ///////////////////////////////////////////////////////////////////
44 // CLASS NAME : ContentFileReader::Impl
46 /** ContentFileReader implementation. */
47 struct ContentFileReader::Impl
50 Impl( const ContentFileReader & parent_r )
54 data::Product & product()
57 _product = new data::Product;
61 RepoIndex & repoindex()
64 _repoindex = new RepoIndex;
68 bool hasProduct() const
71 bool hasRepoIndex() const
72 { return _repoindex; }
74 data::Product_Ptr handoutProduct()
76 data::Product_Ptr ret;
82 RepoIndex_Ptr handoutRepoIndex()
85 ret.swap( _repoindex );
91 bool isRel( const std::string & rel_r ) const
103 bool setUrlList( std::list<Url> & list_r, const std::string & value ) const
106 std::list<std::string> urls;
107 if ( str::split( value, std::back_inserter(urls) ) )
109 for ( std::list<std::string>::const_iterator it = urls.begin();
110 it != urls.end(); ++it )
114 list_r.push_back( *it );
116 catch( const Exception & excpt_r )
118 WAR << *it << ": " << excpt_r << endl;
126 void setDependencies( data::DependencyList & deplist_r, const std::string & value ) const
128 std::list<std::string> words;
129 str::split( value, std::back_inserter( words ) );
131 for ( std::list<std::string>::const_iterator it = words.begin();
132 it != words.end(); ++it )
134 Resolvable::Kind kind( ResTraits<Package>::kind );
136 std::string name = *it;
137 std::string::size_type colon = name.find( ":" );
138 if ( colon != std::string::npos )
140 std::string skind( name, 0, colon );
141 name.erase( 0, colon+1 );
143 if ( skind == ResTraits<Pattern>::kind )
144 kind = ResTraits<Pattern>::kind;
145 else if ( skind == ResTraits<Patch>::kind )
146 kind = ResTraits<Patch>::kind;
147 else if ( skind == ResTraits<Product>::kind )
148 kind = ResTraits<Product>::kind;
149 else if ( skind == ResTraits<Selection>::kind )
150 kind = ResTraits<Selection>::kind;
151 else if ( skind != ResTraits<Package>::kind )
153 // colon but no kind ==> colon in a name
154 name = skind + ":" + name;
159 std::list<std::string>::const_iterator next = it;
160 if ( ++next != words.end()
161 && (*next).find_first_of( "<>=" ) != std::string::npos )
163 std::string op = *next;
164 if ( ++next != words.end() )
174 // Add the dependency
175 deplist_r.insert( capability::parse( kind, name ) );
179 bool setFileCheckSum( std::map<std::string, CheckSum> & map_r, const std::string & value ) const
182 std::vector<std::string> words;
183 if ( str::split( value, std::back_inserter( words ) ) == 3 )
185 map_r[words[2]] = CheckSum( words[0], words[1] );
195 std::string _inputname;
198 const ContentFileReader & _parent;
199 data::Product_Ptr _product;
200 RepoIndex_Ptr _repoindex;
202 ///////////////////////////////////////////////////////////////////
204 ///////////////////////////////////////////////////////////////////
206 // CLASS NAME : ContentFileReader
208 ///////////////////////////////////////////////////////////////////
210 ///////////////////////////////////////////////////////////////////
212 // METHOD NAME : ContentFileReader::ContentFileReader
213 // METHOD TYPE : Ctor
215 ContentFileReader::ContentFileReader()
218 ///////////////////////////////////////////////////////////////////
220 // METHOD NAME : ContentFileReader::~ContentFileReader
221 // METHOD TYPE : Dtor
223 ContentFileReader::~ContentFileReader()
226 ///////////////////////////////////////////////////////////////////
228 // METHOD NAME : ContentFileReader::beginParse
229 // METHOD TYPE : void
231 void ContentFileReader::beginParse()
233 _pimpl.reset( new Impl(*this) );
236 ///////////////////////////////////////////////////////////////////
238 // METHOD NAME : ContentFileReader::endParse
239 // METHOD TYPE : void
241 void ContentFileReader::endParse()
244 if ( _pimpl->hasProduct() )
246 if ( _productConsumer )
247 _productConsumer( _pimpl->handoutProduct() );
249 if ( _pimpl->hasRepoIndex() )
251 if ( _repoIndexConsumer )
252 _repoIndexConsumer( _pimpl->handoutRepoIndex() );
255 MIL << "[Content]" << endl;
259 ///////////////////////////////////////////////////////////////////
261 // METHOD NAME : ContentFileReader::userRequestedAbort
262 // METHOD TYPE : void
264 void ContentFileReader::userRequestedAbort( unsigned lineNo_r )
266 ZYPP_THROW( AbortRequestException( errPrefix( lineNo_r ) ) );
269 ///////////////////////////////////////////////////////////////////
271 // METHOD NAME : ContentFileReader::errPrefix
272 // METHOD TYPE : std::string
274 std::string ContentFileReader::errPrefix( unsigned lineNo_r,
275 const std::string & msg_r,
276 const std::string & line_r ) const
278 return str::form( "%s:%u:%s | %s",
279 _pimpl->_inputname.c_str(),
285 ///////////////////////////////////////////////////////////////////
287 // METHOD NAME : ContentFileReader::parse
288 // METHOD TYPE : void
290 void ContentFileReader::parse( const InputStream & input_r,
291 const ProgressData::ReceiverFnc & fnc_r )
293 MIL << "Start parsing " << input_r << endl;
294 if ( ! input_r.stream() )
296 std::ostringstream s;
297 s << "Can't read bad stream: " << input_r;
298 ZYPP_THROW( ParseException( s.str() ) );
301 _pimpl->_inputname = input_r.name();
303 ProgressData ticks( makeProgressData( input_r ) );
304 ticks.sendTo( fnc_r );
305 if ( ! ticks.toMin() )
306 userRequestedAbort( 0 );
308 Arch sysarch( ZConfig::instance().systemArchitecture() );
310 iostr::EachLine line( input_r );
311 for( ; line; line.next() )
313 // strip 1st word from line to separate tag and value.
314 std::string value( *line );
315 std::string key( str::stripFirstWord( value, /*ltrim_first*/true ) );
317 if ( key.empty() || *key.c_str() == '#' ) // empty or comment line
322 // strip modifier if exists
323 std::string modifier;
324 std::string::size_type pos = key.rfind( '.' );
325 if ( pos != std::string::npos )
327 modifier = key.substr( pos+1 );
332 // Product related data:
334 if ( key == "PRODUCT" )
336 std::replace( value.begin(), value.end(), ' ', '_' );
337 _pimpl->product().name = value;
339 else if ( key == "VERSION" )
341 _pimpl->product().edition = Edition( value );
343 else if ( key == "ARCH" )
345 // Default product arch is noarch. We update, if the
346 // ARCH.xxx tag is better than the current product arch
347 // and still compatible with the sysarch.
348 Arch carch( modifier );
349 if ( Arch::compare( _pimpl->product().arch, carch ) < 0
350 && carch.compatibleWith( sysarch ) )
352 _pimpl->product().arch = carch;
355 else if ( key == "DISTPRODUCT" )
357 _pimpl->product().distributionName = value;
359 else if ( key == "DISTVERSION" )
361 _pimpl->product().distributionEdition = Edition( value );
363 else if ( key == "VENDOR" )
365 _pimpl->product().vendor = value;
367 else if ( key == "LABEL" )
369 _pimpl->product().summary.setText( value, Locale(modifier) );
371 else if ( key == "SHORTLABEL" )
373 _pimpl->product().shortName.setText( value, Locale(modifier) );
375 else if ( key == "TYPE" )
377 _pimpl->product().type = value;
379 else if ( key == "RELNOTESURL" )
381 for( std::string::size_type pos = value.find("%a");
382 pos != std::string::npos;
383 pos = value.find("%a") )
385 value.replace( pos, 2, sysarch.asString() );
389 _pimpl->product().releasenotesUrl = value;
391 catch( const Exception & excpt_r )
393 WAR << errPrefix( line.lineNo(), excpt_r.asString(), *line ) << endl;
396 else if ( key == "UPDATEURLS" )
398 if ( _pimpl->setUrlList( _pimpl->product().updateUrls, value ) )
400 WAR << errPrefix( line.lineNo(), "Ignored malformed URL(s)", *line ) << endl;
403 else if ( key == "EXTRAURLS" )
405 if ( _pimpl->setUrlList( _pimpl->product().extraUrls, value ) )
407 WAR << errPrefix( line.lineNo(), "Ignored malformed URL(s)", *line ) << endl;
410 else if ( key == "OPTIONALURLS" )
412 if ( _pimpl->setUrlList( _pimpl->product().optionalUrls, value ) )
414 WAR << errPrefix( line.lineNo(), "Ignored malformed URL(s)", *line ) << endl;
417 else if ( key == "PREREQUIRES" )
419 _pimpl->setDependencies( _pimpl->product().deps[Dep::PREREQUIRES], value );
421 else if ( key == "REQUIRES" )
423 _pimpl->setDependencies( _pimpl->product().deps[Dep::REQUIRES], value );
425 else if ( key == "PROVIDES" )
427 _pimpl->setDependencies( _pimpl->product().deps[Dep::PROVIDES], value );
429 else if ( key == "CONFLICTS" )
431 _pimpl->setDependencies( _pimpl->product().deps[Dep::CONFLICTS], value );
433 else if ( key == "OBSOLETES" )
435 _pimpl->setDependencies( _pimpl->product().deps[Dep::OBSOLETES], value );
437 else if ( key == "RECOMMENDS" )
439 _pimpl->setDependencies( _pimpl->product().deps[Dep::RECOMMENDS], value );
441 else if ( key == "SUGGESTS" )
443 _pimpl->setDependencies( _pimpl->product().deps[Dep::SUGGESTS], value );
445 else if ( key == "SUPPLEMENTS" )
447 _pimpl->setDependencies( _pimpl->product().deps[Dep::SUPPLEMENTS], value );
449 else if ( key == "ENHANCES" )
451 _pimpl->setDependencies( _pimpl->product().deps[Dep::ENHANCES], value );
454 // ReppoIndex related data:
456 else if ( key == "DEFAULTBASE" )
458 _pimpl->repoindex().defaultBase = Arch(value);
460 else if ( key == "DESCRDIR" )
462 _pimpl->repoindex().descrdir = value;
464 else if ( key == "DATADIR" )
466 _pimpl->repoindex().datadir = value;
468 else if ( key == "FLAGS" )
470 str::split( value, std::back_inserter( _pimpl->repoindex().flags ) );
472 else if ( key == "KEY" )
474 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().signingKeys, value ) )
476 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [KEY algorithm checksum filename]", *line ) ) );
479 else if ( key == "LANGUAGE" )
481 _pimpl->repoindex().language;
483 else if ( key == "LINGUAS" )
485 std::set<std::string> strval;
486 str::split( value, std::inserter( strval, strval.end() ) );
487 for ( std::set<std::string>::const_iterator it = strval.begin(); it != strval.end(); ++it )
489 _pimpl->repoindex().languages.push_back( Locale(*it) );
492 else if ( key == "META" )
494 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().metaFileChecksums, value ) )
496 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
499 else if ( key == "HASH" )
501 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().mediaFileChecksums, value ) )
503 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
506 else if ( key == "TIMEZONE" )
508 _pimpl->repoindex().timezone = value;
511 { WAR << errPrefix( line.lineNo(), "Unknown tag", *line ) << endl; }
514 if ( ! ticks.set( input_r.stream().tellg() ) )
515 userRequestedAbort( line.lineNo() );
521 if ( _pimpl->hasProduct() )
523 // Insert a "Provides" _dist_name" == _dist_version"
524 if ( ! _pimpl->product().distributionName.empty() )
526 _pimpl->product().deps[Dep::PROVIDES].insert(
527 capability::parse( ResTraits<Product>::kind,
528 _pimpl->product().distributionName,
530 _pimpl->product().distributionEdition ) );
533 if ( ! ticks.toMax() )
534 userRequestedAbort( line.lineNo() );
537 MIL << "Done parsing " << input_r << endl;
540 /////////////////////////////////////////////////////////////////
541 } // namespace susetags
542 ///////////////////////////////////////////////////////////////////
543 /////////////////////////////////////////////////////////////////
544 } // namespace parser
545 ///////////////////////////////////////////////////////////////////
546 /////////////////////////////////////////////////////////////////
548 ///////////////////////////////////////////////////////////////////