From c2c7aa3c1e4d496aea33344214337ddb7fd03f94 Mon Sep 17 00:00:00 2001 From: Michael Andres Date: Thu, 1 Dec 2005 15:13:08 +0000 Subject: [PATCH] - Fixes on Capability creation. - New Example.createCapabilities.cc Dumb packages file parser, parsing all Capability definitions, builds Capabilities and collects parse errors for later evaluation. --- devel/Example.createCapabilities.cc | 332 ++++++++++++++++++++++++++++++++++++ devel/Example.createResolvable.cc | 1 + devel/Makefile.am | 5 +- zypp/CapFactory.cc | 9 + zypp/Rel.cc | 2 +- zypp/capability/Capabilities.h | 1 + zypp/capability/NullCap.h | 6 +- 7 files changed, 351 insertions(+), 5 deletions(-) create mode 100644 devel/Example.createCapabilities.cc diff --git a/devel/Example.createCapabilities.cc b/devel/Example.createCapabilities.cc new file mode 100644 index 0000000..a7c087d --- /dev/null +++ b/devel/Example.createCapabilities.cc @@ -0,0 +1,332 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace zypp; +using zypp::base::shared_ptr; + +// work around flaw in y2logview +template + void printOnHack( const _Tp & obj ) + { + MIL << obj << endl; + }; + +/////////////////////////////////////////////////////////////////// +// Just for the stats +struct Measure +{ + time_t _begin; + Measure() + : _begin( time(NULL) ) + { + USR << "START MEASURE..." << endl; + } + ~Measure() + { + USR << "DURATION: " << (time(NULL)-_begin) << " sec." << endl; + } +}; + +/////////////////////////////////////////////////////////////////// +// Print stream status +ostream & operator<<( ostream & str, const istream & obj ) { + return str + << (obj.good() ? 'g' : '_') + << (obj.eof() ? 'e' : '_') + << (obj.fail() ? 'F' : '_') + << (obj.bad() ? 'B' : '_'); +} + +/////////////////////////////////////////////////////////////////// +// Return one line from stream +std::string getline( std::istream & str ) +{ + static const unsigned tmpBuffLen = 1024; + static char tmpBuff[tmpBuffLen]; + string ret; + do { + str.clear(); + str.getline( tmpBuff, tmpBuffLen ); // always writes '\0' terminated + ret += tmpBuff; + } while( str.rdstate() == ios::failbit ); + + return ret; +} + +/////////////////////////////////////////////////////////////////// +// Simple lineparser: Call function do_r for each line. +template + _Function & forEachLine( std::istream & str_r, _Function & do_r ) + { + while ( str_r ) + { + std::string l = getline( str_r ); + if ( ! (str_r.fail() || str_r.bad()) ) + { + // l contains valid data to be consumed. + do_r( l ); + } + } + return do_r; + } + +/////////////////////////////////////////////////////////////////// +// Fits forEachLine. A simple 'do' function +void collect( const std::string & linre_r ) +{ + DBG << linre_r << endl; +} +/////////////////////////////////////////////////////////////////// +// Fits forEachLine. A simple 'do' functor counting lines as base. +/* + Line processing is prepared by providing 'virtual void doConsume(std::string)'. + That's what a derived Collector will overload. + */ +struct Collector : public std::unary_function +{ + unsigned _lineNo; + Collector() + : _lineNo( 0 ) + {} + virtual ~Collector() + {} + virtual void doConsume( const std::string & line_r ) + {} + void operator()( const std::string & line_r ) + { + ++_lineNo; + if ( ! (_lineNo % 10000) ) + DBG << "Got " << _lineNo << " lines..." << endl; + doConsume( line_r ); + } +}; +/////////////////////////////////////////////////////////////////// +// Fits forEachLine. An impatient collector ;) +struct ImpatientCollector : public Collector +{ + virtual void doConsume( const std::string & line_r ) + { + if ( _lineNo == 1234 ) + ZYPP_THROW( "takes to long" ); + } +}; +/////////////////////////////////////////////////////////////////// +// Fits forEachLine. Almost usefull collector. +/* + Note that it's still a functor 'void operator()( const std::string & )'. + + On every invocation the string is parsed into a Capability, and the + Capability is stored in a CapSet. + + Exceptions building the Capability are caught and collected in a + Failure list. It's a matter of taste whether to immediately abort, + or to parse to the end check for collected errors then. Room for + improvement. + + see enhacedCollectorUsage(). +*/ +struct EnhacedCollector : public Collector +{ + // Stores line number, original string and Exception + struct Failure + { + unsigned _lineNo; + std::string _line; + Exception _excpt; + Failure( unsigned lineNo_r, + const std::string & line_r, const Exception & excpt_r ) + : _lineNo( lineNo_r ), _line( line_r ), _excpt( excpt_r ) + {} + }; + + typedef std::list FailedList; + + CapFactory _factory; + unsigned _capLines; + CapSet _caps; + FailedList _failures; + + + EnhacedCollector() + : _capLines( 0 ) + {} + + void makeCap( const string & line_r ) + { + ++_capLines; // count attempts + try + { + // bulid Package deps. + _caps.insert( _factory.parse( ResTraits::kind, line_r ) ); + } + catch( Exception & excpt_r ) + { + _failures.push_back( Failure(_lineNo, line_r, excpt_r) ); + } + } + + virtual void doConsume( const std::string & line_r ) + { + makeCap( line_r ); + } +}; + +// Print a Failure +ostream & operator<<( ostream & str, const EnhacedCollector::Failure & obj ) +{ + return str << str::form( "[%u] \"%s\" ==> %s", + obj._lineNo, + obj._line.c_str(), + obj._excpt.asString().c_str() ); +} + +// Print EnhacedCollector stats +ostream & operator<<( ostream & str, const EnhacedCollector & obj ) +{ + str << "Lines parsed : " << obj._lineNo << endl; + str << "Cap lines : " << obj._capLines << endl; + str << "Capabilites : " << obj._caps.size() << endl; + str << "Parse errors : " << obj._failures.size() << endl; + if ( obj._failures.size() ) + { + copy( obj._failures.begin(), obj._failures.end(), + ostream_iterator(ERR,"\n") ); + //-something-we-should-not-do-unless-....---------^^^ + } + return str; +} + +/////////////////////////////////////////////////////////////////// +// Fits forEachLine. +/* + Within a packages file, not every line defines a Capability. So + EnhacedCollector is refined to turn Capability collection on and + off, as appropriate. A dumb version simply storing all Capabilities + defined somewhere in the packages file. +*/ +struct PackageParseCollector : public EnhacedCollector +{ + static std::string _rxStrDeps; + static str::regex _rxDepOn; + static str::regex _rxDepOff; + + str::smatch _what; + bool _consume; + + PackageParseCollector() + : _consume( false ) + {} + + bool matches( const string & line_r, const str::regex & rx_r ) + { + return str::regex_match( line_r.begin(), line_r.end(), rx_r ); + } + + virtual void doConsume( const std::string & line_r ) + { + if ( _consume ) + { + if ( matches( line_r, _rxDepOff ) ) + { + _consume = false; + } + else + { + EnhacedCollector::doConsume( line_r ); + } + } + else if ( matches( line_r, _rxDepOn ) ) + { + _consume = true; + } + } +}; + +std::string PackageParseCollector::_rxStrDeps( "(Req|Prq|Prv|Con|Obs)" ); +str::regex PackageParseCollector::_rxDepOn ( str::form( "\\+%s:", _rxStrDeps.c_str() ) ); +str::regex PackageParseCollector::_rxDepOff( str::form( "-%s:", _rxStrDeps.c_str() ) ); + +/****************************************************************** +** +** FUNCTION NAME : enhacedCollectorUsage +** FUNCTION TYPE : +*/ +void enhacedCollectorUsage() +{ + // EnhacedCollector: Simply collect strings which are expected to + // be Capabilities. Error handling is delayed by collecting failures. + EnhacedCollector collector; + collector( "" ); + collector( "foo baa kaa" ); + collector( "/bin/sh" ); + collector( "/bin/sh" ); + collector( "/bin/sh" ); + collector( "/bin/sh" ); + + MIL << collector << endl; + MIL << "Capabilities found:" << endl; + for_each( collector._caps.begin(), collector._caps.end(), + printOnHack ); +} + +/****************************************************************** +** +** FUNCTION NAME : main +** FUNCTION TYPE : int +*/ +int main( int argc, char * argv[] ) +{ + --argc; + ++argv; + if ( ! argc ) + { + cerr << "Usage: Example.createCapabilities " << endl; + return 1; + } + string file( argv[0] ); + + INT << "===[START]==========================================" << endl; + + // dump PackageParseCollector: open the file, and build Capabilities + // from each appropriate line. Collecting failures. + + ifstream str( file.c_str() ); + (str?DBG:ERR) << file << ": " << str << endl; + shared_ptr duration( new Measure ); + + PackageParseCollector datacollect; + try + { + forEachLine( str, datacollect ); + } + catch ( Exception & excpt_r ) + { + // Note: Exceptions building a Capability are caught. So this is + // something different. Maybe a bored ImpatientCollector. + ZYPP_CAUGHT( excpt_r ); + ERR << "Parse error at line " << datacollect._lineNo << ": " << excpt_r << endl; + return 1; + } + + duration.reset(); + DBG << file << ": " << str << endl; + + MIL << datacollect << endl; + MIL << "Capabilities found:" << endl; + for_each( datacollect._caps.begin(), datacollect._caps.end(), + printOnHack ); + + INT << "===[END]============================================" << endl; + return 0; +} diff --git a/devel/Example.createResolvable.cc b/devel/Example.createResolvable.cc index 29493d0..e40be6a 100644 --- a/devel/Example.createResolvable.cc +++ b/devel/Example.createResolvable.cc @@ -28,6 +28,7 @@ template inline std::list parseDeps() { const char * init[] = { + "xextra:/usr/X11R6/bin/Xvfb" "/bin/sh", "rpmlib(PayloadFilesHavePrefix) <= 4.0-1", "rpmlib(CompressedFileNames) <= 3.0.4-1", diff --git a/devel/Makefile.am b/devel/Makefile.am index fc68036..a092b6f 100644 --- a/devel/Makefile.am +++ b/devel/Makefile.am @@ -8,7 +8,9 @@ SUBDIRS = ## ################################################## -noinst_PROGRAMS = Example.createResolvable +noinst_PROGRAMS = \ + Example.createResolvable \ + Example.createCapabilities ## ################################################## @@ -17,6 +19,7 @@ LDADD = $(top_srcdir)/zypp/lib@PACKAGE@.la ## ################################################## Example_createResolvable_SOURCES = Example.createResolvable.cc +Example_createCapabilities_SOURCES = Example.createCapabilities.cc ## ################################################## diff --git a/zypp/CapFactory.cc b/zypp/CapFactory.cc index 64eb6f1..21bbbf8 100644 --- a/zypp/CapFactory.cc +++ b/zypp/CapFactory.cc @@ -146,6 +146,13 @@ namespace zypp static CapabilityImpl::Ptr buildNamed( const Resolvable::Kind & refers_r, const std::string & name_r ) { + // NullCap check first: + if ( name_r.empty() ) + { + // Singleton, so no need to put it into _uset !? + return capability::NullCap::instance(); + } + assertResKind( refers_r ); // file: /absolute/path @@ -243,6 +250,7 @@ namespace zypp try { // strval_r has at least two words which could make 'op edition'? + // improve regex! str::regex rx( "(.*[^ \t])([ \t]+)([^ \t]+)([ \t]+)([^ \t]+)" ); str::smatch what; if( str::regex_match( strval_r.begin(), strval_r.end(),what, rx ) ) @@ -258,6 +266,7 @@ namespace zypp { // So they don't make valid 'op edition' ZYPP_CAUGHT( excpt ); + DBG << "Trying named cap for: " << strval_r << endl; // See whether it makes a named cap. return Capability( Impl::buildNamed( refers_r, strval_r ) ); } diff --git a/zypp/Rel.cc b/zypp/Rel.cc index 3dbc511..7979d75 100644 --- a/zypp/Rel.cc +++ b/zypp/Rel.cc @@ -31,7 +31,7 @@ namespace if ( _table.empty() ) { // initialize it - _table["EQ"] = _table["eq"] = _table["=="] = Rel::EQ_e; + _table["EQ"] = _table["eq"] = _table["=="] = _table["="] = Rel::EQ_e; _table["NE"] = _table["ne"] = _table["!="] = Rel::NE_e; _table["LT"] = _table["lt"] = _table["<"] = Rel::LT_e; _table["LE"] = _table["le"] = _table["<="] = Rel::LE_e; diff --git a/zypp/capability/Capabilities.h b/zypp/capability/Capabilities.h index 3509a64..f631b87 100644 --- a/zypp/capability/Capabilities.h +++ b/zypp/capability/Capabilities.h @@ -16,6 +16,7 @@ #include "zypp/capability/FileCap.h" #include "zypp/capability/NamedCap.h" +#include "zypp/capability/NullCap.h" #include "zypp/capability/SplitCap.h" #include "zypp/capability/VersionedCap.h" diff --git a/zypp/capability/NullCap.h b/zypp/capability/NullCap.h index 9ce6cdb..ef94aad 100644 --- a/zypp/capability/NullCap.h +++ b/zypp/capability/NullCap.h @@ -9,8 +9,8 @@ /** \file zypp/capability/NullCap.h * */ -#ifndef ZYPP_CAPABILITY_NAMEDCAP_H -#define ZYPP_CAPABILITY_NAMEDCAP_H +#ifndef ZYPP_CAPABILITY_NULLCAP_H +#define ZYPP_CAPABILITY_NULLCAP_H #include "zypp/capability/CapabilityImpl.h" @@ -69,4 +69,4 @@ namespace zypp ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// -#endif // ZYPP_CAPABILITY_NAMEDCAP_H +#endif // ZYPP_CAPABILITY_NULLCAP_H -- 2.7.4