- Fixes on Capability creation.
authorMichael Andres <ma@suse.de>
Thu, 1 Dec 2005 15:13:08 +0000 (15:13 +0000)
committerMichael Andres <ma@suse.de>
Thu, 1 Dec 2005 15:13:08 +0000 (15:13 +0000)
- 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 [new file with mode: 0644]
devel/Example.createResolvable.cc
devel/Makefile.am
zypp/CapFactory.cc
zypp/Rel.cc
zypp/capability/Capabilities.h
zypp/capability/NullCap.h

diff --git a/devel/Example.createCapabilities.cc b/devel/Example.createCapabilities.cc
new file mode 100644 (file)
index 0000000..a7c087d
--- /dev/null
@@ -0,0 +1,332 @@
+#include <iostream>
+#include <ctime>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <zypp/base/Logger.h>
+#include <zypp/base/String.h>
+#include <zypp/base/PtrTypes.h>
+
+#include <zypp/CapFactory.h>
+#include <zypp/CapSet.h>
+
+using namespace std;
+using namespace zypp;
+using zypp::base::shared_ptr;
+
+// work around flaw in y2logview
+template<class _Tp>
+  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<class _Function>
+  _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<const std::string &, void>
+{
+  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<Failure> 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<Package>::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<EnhacedCollector::Failure>(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<Capability> );
+}
+
+/******************************************************************
+**
+**      FUNCTION NAME : main
+**      FUNCTION TYPE : int
+*/
+int main( int argc, char * argv[] )
+{
+  --argc;
+  ++argv;
+  if ( ! argc )
+    {
+      cerr << "Usage: Example.createCapabilities <packages file>" << 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<Measure> 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<Capability> );
+
+  INT << "===[END]============================================" << endl;
+  return 0;
+}
index 29493d0..e40be6a 100644 (file)
@@ -28,6 +28,7 @@ template<typename _Res>
 inline std::list<std::string> parseDeps()
 {
   const char * init[] = {
+    "xextra:/usr/X11R6/bin/Xvfb"
     "/bin/sh",
     "rpmlib(PayloadFilesHavePrefix) <= 4.0-1",
     "rpmlib(CompressedFileNames) <= 3.0.4-1",
index fc68036..a092b6f 100644 (file)
@@ -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
 
 ## ##################################################
 
index 64eb6f1..21bbbf8 100644 (file)
@@ -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 ) );
             }
index 3dbc511..7979d75 100644 (file)
@@ -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;
index 3509a64..f631b87 100644 (file)
@@ -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"
 
index 9ce6cdb..ef94aad 100644 (file)
@@ -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