Imported Upstream version 1.12.45 34/109434/1 upstream/1.12.45
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Jan 2017 05:47:59 +0000 (14:47 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Jan 2017 05:48:00 +0000 (14:48 +0900)
Change-Id: I8d692343aa3c69f173a7443b07ab890dd810b71d
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
VERSION.cmake
package/zypper.changes
src/Table.cc
src/Table.h
src/callbacks/rpm.h
src/locks.cc
src/output/Out.cc
src/output/Out.h
src/output/xmlout.rnc

index b35012c..33248e7 100644 (file)
@@ -34,7 +34,7 @@
 #
 SET(VERSION_MAJOR "1")
 SET(VERSION_MINOR "12")
-SET(VERSION_PATCH "44")
+SET(VERSION_PATCH "45")
 
-# LAST RELEASED: 1.12.44
+# LAST RELEASED: 1.12.45
 #=======
index fb7b363..3ec022f 100644 (file)
@@ -1,4 +1,10 @@
 -------------------------------------------------------------------
+Wed Aug 10 16:50:48 CEST 2016 - ma@suse.de
+
+- locks: add parsable XML output (bsc#985390)
+- version 1.12.45
+
+-------------------------------------------------------------------
 Tue Jun 28 11:50:12 CEST 2016 - ma@suse.de
 
 - Update sle-zypper-po.tar.bz2 (bsc#986694)
index 8dafff9..275d649 100644 (file)
@@ -205,8 +205,8 @@ Table & Table::add( TableRow tr )
 
 Table & Table::setHeader( TableHeader tr )
 {
-  _has_header = true;
   _header = std::move(tr);
+  _has_header = !_header.empty();
   return *this;
 }
 
index 3f658c6..18bae4e 100644 (file)
@@ -68,6 +68,9 @@ public:
   { return addDetail( str::asString( val_r ) ); }
 
 
+  bool empty() const
+  { return _columns.empty(); }
+
   // return number of columns
   unsigned size() const
   { return _columns.size(); }
@@ -75,7 +78,6 @@ public:
   unsigned cols() const
   { return size(); }
 
-
   //! tab separated output
   std::ostream & dumbDumpTo( std::ostream & stream ) const;
   //! output with \a parent table attributes
index ff2aabb..23a612c 100644 (file)
@@ -46,71 +46,65 @@ namespace out
   ///////////////////////////////////////////////////////////////////
   struct FileConflictsListFormater
   {
-    typedef out::DefaultGapedListLayout ListLayout;
+    typedef out::DefaultGapedListLayout NormalLayout;
 
-    struct XmlFormater
-    {
-      std::string operator()( const sat::FileConflicts::Conflict & val_r ) const
-      { str::Str str; dumpAsXmlOn( str.stream(), val_r ); return str; }
-    };
+    std::string xmlListElement( const sat::FileConflicts::Conflict & val_r ) const
+    { str::Str str; dumpAsXmlOn( str.stream(), val_r ); return str; }
 
-    std::string operator()( const sat::FileConflicts::Conflict & val_r ) const
+    std::string listElement( const sat::FileConflicts::Conflict & val_r ) const
     { return asUserString( val_r ); }
   };
   ///////////////////////////////////////////////////////////////////
 
-  /** \relates SolvableListFormater Conversion to sat::Solvable */
-  template <class Tp_>
-  sat::Solvable asSolvable( const Tp_ & val_r )
-  { return sat::asSolvable( val_r ); }
-
-  sat::Solvable asSolvable( int val_r )                // e.g. satQueues use int as SolvabeId
-  { return sat::Solvable( val_r ); }
-
   ///////////////////////////////////////////////////////////////////
   /// \class SolvableListFormater
   /// \brief Printing Solvable based types in List (legacy format used in summary)
   ///////////////////////////////////////////////////////////////////
   struct SolvableListFormater
   {
-    typedef out::CompressedListLayout ListLayout;
+    typedef out::CompressedListLayout NormalLayout;
 
-    struct XmlFormater
-    {
-      template <class Tp_>
-      std::string operator()( const Tp_ & val_r ) const
-      { return operator()( makeResObject( asSolvable( val_r ) ) ); }
+    template <class Tp_>
+    std::string xmlListElement( const Tp_ & val_r ) const
+    { return xmlListElement( makeResObject( asSolvable( val_r ) ) ); }
 
-      std::string operator()( ResObject::Ptr val_r, ResObject::Ptr old_r = nullptr ) const
+    std::string xmlListElement( const ResObject::Ptr & val_r ) const
+    {
+      str::Str ret;
+      ret << "<solvable";
+      ret << " type=\""        << val_r->kind() << "\"";
+      ret << " name=\""        << val_r->name() << "\"";
+      ret << " edition=\""     << val_r->edition() << "\"";
+      ret << " arch=\""        << val_r->arch() << "\"";
       {
-       str::Str ret;
-       ret << "<solvable";
-       ret << " type=\""       << val_r->kind() << "\"";
-       ret << " name=\""       << val_r->name() << "\"";
-       ret << " edition=\""    << val_r->edition() << "\"";
-       ret << " arch=\""       << val_r->arch() << "\"";
-       {
-         const std::string & text( val_r->summary() );
-         if ( ! text.empty() )
-           ret << " summary=\"" << xml::escape( text ) << "\"";
-       }
-       {
-         const std::string & text( val_r->description() );
-         if ( ! text.empty() )
-           ret << ">\n" << "<description>" << xml::escape( text ) << "</description>" << "</solvable>";
-         else
-           ret << "/>";
-       }
-       return ret;
+       const std::string & text( val_r->summary() );
+       if ( ! text.empty() )
+         ret << " summary=\"" << xml::escape( text ) << "\"";
       }
-    };
+      {
+       const std::string & text( val_r->description() );
+       if ( ! text.empty() )
+         ret << ">\n" << "<description>" << xml::escape( text ) << "</description>" << "</solvable>";
+       else
+         ret << "/>";
+      }
+      return ret;
+    }
 
-    template <class Tp_>
-    std::string operator()( const Tp_ & val_r ) const
-    { return operator()( makeResObject( asSolvable( val_r ) ) ); }
+    template <class Tp>
+    std::string listElement( const Tp & val_r ) const
+    { return listElement( makeResObject( asSolvable( val_r ) ) ); }
 
-    std::string operator()( ResObject::Ptr val_r, ResObject::Ptr old_r = nullptr ) const
+    std::string listElement( const ResObject::Ptr & val_r ) const
     { return val_r->ident().asString(); }
+
+  private:
+    template <class Tp_>
+    static sat::Solvable asSolvable( const Tp_ & val_r )
+    { return sat::asSolvable( val_r ); }
+
+    static sat::Solvable asSolvable( int val_r )               // e.g. satQueues use int as SolvabeId
+    { return sat::Solvable( val_r ); }
   };
 
 } // namespace out
index 82517b8..5a13750 100644 (file)
 using namespace zypp;
 
 ///////////////////////////////////////////////////////////////////
-namespace
+namespace out
 {
-  inline std::string get_string_for_table( const std::set<std::string> & attrvals )
+  struct LocksTableFormater : public TableFormater
   {
-    std::string ret;
-    if ( attrvals.empty() )
-      ret = _("(any)");
-    else if ( attrvals.size() > 1 )
-      ret = _("(multiple)");
-    else
-      ret = *attrvals.begin();
-    return ret;
-  }
-
-  inline std::string getLockDetails( const PoolQuery & q )
-  {
-    if ( q.empty() )
-      return "";
-
-    PropertyTable p;
+  private:
+    /** LESS compare for MatchDetails */
+    struct MatchDetailCompare
     {
-      struct DoCompare
-      {
-       int operator()( const sat::Solvable & lhs, const sat::Solvable & rhs ) const
-       { return( doComapre( lhs, rhs ) < 0 ); }
+      bool operator()( const sat::Solvable & lhs, const sat::Solvable & rhs ) const
+      { return( doComapre( lhs, rhs ) < 0 ); }
 
-       int doComapre( const sat::Solvable & lhs, const sat::Solvable & rhs ) const
-       {
-         // return sat::compareByNVRA( lhs, rhs );
-         // do N(<) A(>) VR(>)
-         int res = sat::compareByN( lhs, rhs );                // ascending  l<r
-         if ( res == 0 )
-           res = rhs.arch().compare( lhs.arch() );             // descending r<l
+      int doComapre( const sat::Solvable & lhs, const sat::Solvable & rhs ) const
+      {
+       // do N(<) A(>) VR(>)
+       int res = sat::compareByN( lhs, rhs );                  // ascending  l<r
+       if ( res == 0 )
+         res = rhs.arch().compare( lhs.arch() );               // descending r<l
          if ( res == 0 )
            res = rhs.edition().compare( lhs.edition() );       // descending r<l
-         if ( res == 0 )
-           res = lhs.repository().asUserString().compare( rhs.repository().asUserString() );   // ascending  l<r
-         return res;
-       }
-      };
-      std::set<sat::Solvable,DoCompare> i;
-      std::set<sat::Solvable,DoCompare> a;
-      for ( const auto & solv : q )
-      { (solv.isSystem()?i:a).insert( solv ); }
-
-      std::vector<std::string> names;
-      names.reserve( std::max( i.size(), a.size() ) );
-
-      if ( ! i.empty() )
-      {
-       //names.clear();
-       for ( const auto & solv : i )
-       { names.push_back( solv.asUserString() ); }
-       // translators: property name; short; used like "Name: value"
-       p.add( _("Keep installed"), names );
+           if ( res == 0 )
+             res = lhs.repository().asUserString().compare( rhs.repository().asUserString() ); // ascending  l<r
+             return res;
       }
-      if ( ! a.empty() )
+    };
+    /** Ordered MatchDetails */
+    typedef std::set<sat::Solvable,MatchDetailCompare> MatchDetails;
+
+    /** MatchDetail representation */
+    struct MatchDetailFormater
+    {
+      std::string xmlListElement( const sat::Solvable & match_r ) const
       {
-       names.clear();
-       for ( const auto & solv : a )
-       { names.push_back( solv.asUserString() ); }
-       // translators: property name; short; used like "Name: value"
-       p.add( _("Do not install"), names );
+       str::Str str;
+       {
+         xmlout::Node lock( str.stream(), "match", {
+           { "kind",           match_r.kind()  },
+           { "name",           match_r.name()  },
+           { "edition",        match_r.edition()       },
+           { "arch",           match_r.arch()  },
+           { "installed",      match_r.isSystem()      },
+           { "repo",           match_r.repository().alias()    },
+         } );
+       }
+       return str;
       }
-    }
-    return str::Str() << p;
-  }
+    };
 
-} //namespace
-///////////////////////////////////////////////////////////////////
+  public:
+    std::string xmlListElement( const PoolQuery & q_r ) const
+    {
+      str::Str str;
+      // <lock>
+      {
+       ++_i;
+       xmlout::Node lock( str.stream(), "lock", { { "number", _i } } );
 
-void list_locks(Zypper & zypper)
-{
-  shared_ptr<ListLocksOptions> listLocksOptions = zypper.commandOptionsOrDefaultAs<ListLocksOptions>();
+       // <name> (solvable_name)
+       for ( const std::string & val : q_r.attribute( sat::SolvAttr::name ) )
+       { *xmlout::Node( *lock, "name" ) << val; }
+       // <name> (query_string)
+       for ( const std::string & val : q_r.strings() )
+       { *xmlout::Node( *lock, "name" ) << val; }
 
-  bool withSolvables = listLocksOptions->_withSolvables;
-  bool withMatches = withSolvables||listLocksOptions->_withMatches;
+       // <type>
+       for ( const ResKind & kind : q_r.kinds() )
+       { *xmlout::Node( *lock, "type" ) << kind; }
 
-  try
-  {
-    Locks & locks = Locks::instance();
-    locks.read( Pathname::assertprefix( zypper.globalOpts().root_dir, ZConfig::instance().locksFile() ) );
+       // <repo>
+       for ( const std::string & repo : q_r.repos() )
+       { *xmlout::Node( *lock, "repo" ) << repo; }
 
-    Table t;
+       if ( _withMatches )
+       {
+         // <matches>
+         xmlout::Node matches( *lock, "matches", xmlout::Node::optionalContent, { { "size", q_r.size() } } );
+         if ( _withSolvables && !q_r.empty() )
+         {
+           MatchDetails d;
+           getLockDetails( q_r, d );
+           xmlWriteContainer( *matches, d, MatchDetailFormater() );
+         }
+       }
+      }
+      return str;
+    }
 
-    TableHeader th;
-    th << "#" << _("Name");
-    if ( withMatches )
-      th << _("Matches");
-    th << _("Type") << _("Repository");
-    t << th;
+    TableHeader header() const
+    {
+      TableHeader th;
+      th << "#" << _("Name");
+      if ( _withMatches )
+       th << _("Matches");
+      th << _("Type") << _("Repository");
+      return th;
+    }
 
-    unsigned i = 0;
-    for ( const PoolQuery & q : locks )
+    TableRow row( const PoolQuery & q_r ) const
     {
       TableRow tr;
-      ++i;
 
       // #
-      tr << str::numstring( i );
+      ++_i;
+      tr << str::numstring( _i );
 
-      // name
-      const PoolQuery::StrContainer & nameStings( q.attribute( sat::SolvAttr::name ) );
-      const PoolQuery::StrContainer & globalStrings( q.strings() );
+      // Name
+      const PoolQuery::StrContainer & nameStings( q_r.attribute( sat::SolvAttr::name ) );
+      const PoolQuery::StrContainer & globalStrings( q_r.strings() );
 
       if ( nameStings.size() + globalStrings.size() > 1 )
         // translators: locks table value
@@ -132,40 +135,103 @@ void list_locks(Zypper & zypper)
         tr << *nameStings.begin();
 
       // opt Matches
-      if ( withMatches )
-       tr << q.size();
+      if ( _withMatches )
+       tr << q_r.size();
 
-      // type
+      // Type
       std::set<std::string> strings;
-      for ( const ResKind & kind : q.kinds() )
+      for ( const ResKind & kind : q_r.kinds() )
        strings.insert( kind.asString() );
       tr << get_string_for_table( strings );
 
-      // repo
+      // Repository
       strings.clear();
-      copy( q.repos().begin(), q.repos().end(), inserter(strings, strings.end()) );
+      copy( q_r.repos().begin(), q_r.repos().end(), inserter(strings, strings.end()) );
       tr << get_string_for_table( strings );
 
-      // opt Solvables
-      if ( withSolvables )
+      // opt Solvables as detail
+      if ( _withSolvables && !q_r.empty() )
       {
-       tr.addDetail( getLockDetails( q ) );
+       MatchDetails i;
+       MatchDetails a;
+       getLockDetails( q_r, i, a );
+
+       PropertyTable p;
+       {
+         std::vector<std::string> names;
+         names.reserve( std::max( i.size(), a.size() ) );
+         if ( ! i.empty() )
+         {
+           //names.clear();
+           for ( const auto & solv : i )
+           { names.push_back( solv.asUserString() ); }
+           // translators: property name; short; used like "Name: value"
+           p.add( _("Keep installed"), names );
+         }
+         if ( ! a.empty() )
+         {
+           names.clear();
+           for ( const auto & solv : a )
+           { names.push_back( solv.asUserString() ); }
+           // translators: property name; short; used like "Name: value"
+           p.add( _("Do not install"), names );
+         }
+       }
+       tr.addDetail( (str::Str() << p).str() );
       }
+      return tr;
+    }
+
+    LocksTableFormater( shared_ptr<ListLocksOptions> listLocksOptions_r )
+    : _withSolvables( listLocksOptions_r->_withSolvables )
+    , _withMatches( _withSolvables || listLocksOptions_r->_withMatches )
+    {}
 
-      t << tr;
+  private:
+    static std::string get_string_for_table( const std::set<std::string> & attrvals_r )
+    {
+      std::string ret;
+      if ( attrvals_r.empty() )
+       ret = _("(any)");
+      else if ( attrvals_r.size() > 1 )
+       ret = _("(multiple)");
+      else
+       ret = *attrvals_r.begin();
+      return ret;
     }
 
-    if (t.empty())
-      zypper.out().info(_("There are no package locks defined."));
-    else
-      cout << t;
+    static void getLockDetails( const PoolQuery & q_r, MatchDetails & i_r, MatchDetails & a_r )
+    { for ( const auto & solv : q_r ) { (solv.isSystem()?i_r:a_r).insert( solv ); } }
+
+    static void getLockDetails( const PoolQuery & q_r, MatchDetails & d_r )
+    { getLockDetails( q_r, d_r, d_r ); }
+
+  private:
+    bool _withSolvables        :1;     //< include match details (implies _withMatches)
+    bool _withMatches  :1;     //< include number of matches
+    mutable unsigned _i = 0;   //< Lock Number
+  };
+} //namespace out
+///////////////////////////////////////////////////////////////////
+
+void list_locks( Zypper & zypper )
+{
+  Locks & locks( Locks::instance() );
+  try
+  {
+    locks.read( Pathname::assertprefix( zypper.globalOpts().root_dir, ZConfig::instance().locksFile() ) );
   }
-  catch(const Exception & e)
+  catch( const Exception & e )
   {
-    ZYPP_CAUGHT(e);
-    zypper.out().error(e, _("Error reading the locks file:"));
-    zypper.setExitCode(ZYPPER_EXIT_ERR_ZYPP);
+    throw( Out::Error( ZYPPER_EXIT_ERR_ZYPP, _("Error reading the locks file:"), e ) );
   }
+
+  // show result
+  Out & out( zypper.out() );
+  out.gap();
+  out.table( "locks", locks.empty() ? _("There are no package locks defined.") : "",
+            locks, out::LocksTableFormater( zypper.commandOptionsOrDefaultAs<ListLocksOptions>() ) );
+  out.gap();
 }
 
 template <typename Target, typename Source>
index 4a85ea9..0ca9935 100644 (file)
 
 #include "Zypper.h"
 
+///////////////////////////////////////////////////////////////////
+namespace out
+{
+  unsigned defaultTermwidth()
+  { return Zypper::instance()->out().termwidth(); }
+} // namespace out
+///////////////////////////////////////////////////////////////////
+
 ////////////////////////////////////////////////////////////////////////////////
 //     class TermLine
 ////////////////////////////////////////////////////////////////////////////////
index 204e4a0..4123791 100644 (file)
 #include "utils/richtext.h"
 #include "output/prompt.h"
 
+inline char * asYesNo( bool val_r ) { return val_r ? _("Yes") : _("No"); }
+#include "Table.h"
+#define OSD ColorStream( std::cout, ColorContext::OSDEBUG )
+
 using namespace zypp;
 
-class Table;
 class Zypper;
 
-#define OSD ColorStream( std::cout, ColorContext::OSDEBUG )
-
-inline char * asYesNo( bool val_r )
-{ return val_r ? _("Yes") : _("No"); }
-
 ///////////////////////////////////////////////////////////////////
 namespace out
 {
   static constexpr unsigned termwidthUnlimited = 0u;
+  unsigned defaultTermwidth(); // Zypper::instance()->out().termwidth()
 } // namespace out
 ///////////////////////////////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////
 namespace out
 {
-  /** \relates ListFormater NORMAL representation of types in lists [no default] */
-  template <class Tp_>
-  std::string asListElement( const Tp_ & val_r );
-
-  /** \relates ListFormater XML representation of types in lists [no default] */
-  template <class Tp_>
-  std::string asXmlListElement( const Tp_ & val_r );
-
   ///////////////////////////////////////////////////////////////////
   /// \class ListLayout
   /// \brief Basic list layout
@@ -57,6 +48,8 @@ namespace out
   ///////////////////////////////////////////////////////////////////
   struct ListLayout
   {
+    template <class TFormater> struct Writer;
+
     ListLayout( bool singleline_r, bool wrapline_r, bool gaped_r, unsigned indent_r )
     : _singleline( singleline_r )
     , _wrapline( wrapline_r )
@@ -74,6 +67,7 @@ namespace out
     template <bool singleline_, bool wrapline_, bool gaped_, unsigned indent_>
     struct ListLayoutInit : public ListLayout { ListLayoutInit() : ListLayout( singleline_, wrapline_, gaped_, indent_ ) {} };
   }
+
   typedef detail::ListLayoutInit<true, false,false, 0U>        XmlListLayout;
   typedef detail::ListLayoutInit<true, true, false, 0U>        DefaultListLayout;      ///< one element per line, no indent
   typedef detail::ListLayoutInit<true, true, true,  0U>        DefaultGapedListLayout; ///< one element per line, no indent, gaped
@@ -82,29 +76,102 @@ namespace out
   typedef detail::ListLayoutInit<false,true, false, 2U>        CompressedListLayout;   ///< multiple elements per line, indented
 
   ///////////////////////////////////////////////////////////////////
-  /// \class ListFormater
-  /// \brief Default representation of types in Lists [asListElement|asXmlListElement]
+  /// \class TableLayout
+  /// \brief Basic table layout
   ///////////////////////////////////////////////////////////////////
-  struct ListFormater
+  struct TableLayout
   {
-    typedef DefaultListLayout ListLayout;      //< ListLayout for NORMAL lists
+    template <class TFormater> struct Writer;
+  };
 
-    struct XmlFormater                         //< XML representation of element
-    {
-      template <class Tp_>
-      std::string operator()( const Tp_ & val_r ) const
-      { return asXmlListElement( val_r ); }
-    };
+  typedef TableLayout  DefaultTableLayout;     ///< Simple Table
+
+  ///////////////////////////////////////////////////////////////////
+  // Either specialize per Type or define a custom Formater:
 
-    template <class Tp_>                       //< NORMAL representation of element
-    std::string operator()( const Tp_ & val_r ) const
+  /** \relates XmlFormater XML representation of types [no default] */
+  template <class Tp>
+  std::string asXmlListElement( const Tp & val_r );
+  inline std::string asXmlListElement( const std::string & val_r ){ return val_r; }
+  inline std::string asXmlListElement( const char * val_r )    { return val_r; }
+
+  /** \relates ListFormater NORMAL representation of types in lists [no default] */
+  template <class Tp>
+  std::string asListElement( const Tp & val_r );
+  inline std::string asListElement( const std::string & val_r )        { return val_r; }
+  inline std::string asListElement( const char * val_r )       { return val_r; }
+
+  /** \relates TableFormater NORMAL representation of types as TableHeader [no default] */
+  template <class Tp = void>
+  TableHeader asTableHeader();
+
+  template <>
+  inline TableHeader asTableHeader<void>()
+  { return TableHeader(); }
+
+  /** \relates TableFormater NORMAL representation of types as TableRow [no default] */
+  template <class Tp>
+  TableRow asTableRow( const Tp & val_r );
+
+  ///////////////////////////////////////////////////////////////////
+  /// \class XmlFormater
+  /// \brief XML representation of types in container [asXmlListElement]
+  ///////////////////////////////////////////////////////////////////
+  struct XmlFormater
+  {
+    template <class Tp>
+    std::string xmlListElement( const Tp & val_r ) const//< XML representation of element
+    { return asXmlListElement( val_r ); }
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  /// \class ListFormater
+  /// \brief Default representation of types in Lists [asListElement]
+  ///////////////////////////////////////////////////////////////////
+  struct ListFormater : public XmlFormater
+  {
+    typedef DefaultListLayout  NormalLayout;           //< ListLayout for NORMAL lists
+
+    template <class Tp>
+    std::string listElement( const Tp & val_r ) const  //< NORMAL representation of list element
     { return asListElement( val_r ); }
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  /// \class TableFormater
+  /// \brief Special list formater writing a Table [asTableHeader|asTableRow]
+  ///////////////////////////////////////////////////////////////////
+  struct TableFormater : public XmlFormater
+  {
+    typedef DefaultTableLayout NormalLayout;           //< NORMAL layout as Table
+
+    TableHeader header() const                         //< TableHeader for TableRow representation
+    { return asTableHeader<>(); }
+
+    template <class Tp>                                        //< Representation as TableRow
+    TableRow row( const Tp & val_r ) const
+    { return asTableRow( val_r ); }
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  /// \class XmlFormaterAdaptor
+  /// \brief Adaptor mapping xmlListElement->listElement for container XML output
+  ///////////////////////////////////////////////////////////////////
+   /** Adaptor */
+  template <class TFormater>
+  struct XmlFormaterAdaptor
+  {
+    typedef XmlListLayout      NormalLayout;           //< Layout as XML list
 
-    std::string operator()( const std::string & val_r ) const
-    { return val_r; }
+    template <class Tp>
+    std::string listElement( const Tp & val_r ) const  //< use TFormater::asXmlListElement
+    { return _formater.xmlListElement( val_r ); }
 
-    std::string operator()( const char * val_r ) const
-    { return val_r; }
+    XmlFormaterAdaptor( const TFormater & formater_r )
+    : _formater( formater_r )
+    {}
+  private:
+    const TFormater & _formater;
   };
 
 } // namespace out
@@ -113,65 +180,125 @@ namespace out
 ///////////////////////////////////////////////////////////////////
 namespace out
 {
-  namespace detail
+  ///////////////////////////////////////////////////////////////////
+  /// \class ListLayout::Writer
+  /// \brief Write out a List according to the layout
+  // TODO: wrap singlelines; support for attributed text;
+  ///////////////////////////////////////////////////////////////////
+  template <class TFormater>
+  struct ListLayout::Writer
   {
-    // TODO: wrap singlelines; support for atttibuted text;
-    struct BasicList
-    {
-      NON_COPYABLE( BasicList );
+    NON_COPYABLE( Writer );
+
+    Writer( std::ostream & str_r, ListLayout layout_r, const TFormater & formater_r )
+    : _str( str_r )
+    , _layout( layout_r )
+    , _formater( formater_r )
+    , _linewidth( defaultTermwidth() )
+    , _indent( _layout._indent, ' ' )
+    {}
 
-      BasicList( ListLayout layout_r, unsigned linewidth_r )
-      : _layout( std::move(layout_r) )
-      , _linewidth( linewidth_r )
-      , _indent( _layout._indent, ' ' )
-      , _cpos( 0U )
-      {}
+    ~Writer()
+    { if ( !_layout._singleline && _cpos ) _str << std::endl; }
 
-      ~BasicList()
-      { if ( !_layout._singleline && _cpos ) std::cout << std::endl; }
+    template <class Tp>
+    void operator<<( Tp && val_r ) const
+    {
+      const std::string & element( _formater.listElement( std::forward<Tp>(val_r) ) );
 
-      void print( const std::string & val_r )
+      if ( _layout._singleline )
+      {
+       if ( _layout._gaped )
+         _str << std::endl;
+       _str << _indent << element << std::endl;
+      }
+      else
       {
-       if ( _layout._singleline )
+       if ( _cpos != 0 && ! fitsOnLine( 1/*' '*/ + element.size() ) )
+         endLine();
+
+       if ( _cpos == 0 )
        {
-         if ( _layout._gaped )
-           std::cout << std::endl;
-         std::cout << _indent << val_r << std::endl;
+         if ( !_indent.empty() )
+           printAndCount( _indent );
        }
        else
-       {
-         if ( _cpos != 0 && ! fitsOnLine( 1/*' '*/ + val_r.size() ) )
-           endLine();
-
-         if ( _cpos == 0 )
-         {
-           if ( !_indent.empty() )
-             printAndCount( _indent );
-         }
-         else
-           printAndCount( " " );
-
-         printAndCount( val_r );
-       }
+         printAndCount( " " );
+
+       printAndCount( element );
       }
+    }
+
+  private:
+    bool fitsOnLine( unsigned size_r ) const
+    { return( !_layout._wrapline || _linewidth == out::termwidthUnlimited || _cpos + size_r <= _linewidth ); }
+
+    void printAndCount( const std::string & element_r ) const
+    { _cpos += element_r.size(); _str << element_r; }
+
+    void endLine() const
+    { _str << std::endl; _cpos = 0U; }
+
+  private:
+    std::ostream &     _str;
+    const ListLayout & _layout;
+    const TFormater &  _formater;
+    const unsigned     _linewidth;     ///< desired line width
+    const std::string  _indent;
+    mutable unsigned   _cpos = 0U;
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  /// \class TableLayout::Writer
+  /// \brief Write out a Table according to the layout
+  ///////////////////////////////////////////////////////////////////
+  template <class TFormater>
+  struct TableLayout::Writer
+  {
+    NON_COPYABLE( Writer );
+
+    Writer( std::ostream & str_r, const TableLayout & layout_r, const TFormater & formater_r )
+    : _str( str_r )
+    , _layout( layout_r )
+    , _formater( formater_r )
+    {}
 
-    private:
-      bool fitsOnLine( unsigned val_r )
-      { return( !_layout._wrapline || _linewidth == out::termwidthUnlimited || _cpos + val_r <= _linewidth ); }
+    ~Writer()
+    {
+      if ( !_t.empty() )
+      {
+       _t.setHeader( _formater.header() );
+       _str << _t;
+      }
+    }
 
-      void printAndCount( const std::string & val_r )
-      { _cpos += val_r.size(); std::cout << val_r; }
+    template <class Tp>
+    void operator<<( Tp && val_r ) const
+    { _t.add( _formater.row( std::forward<Tp>(val_r) ) ); }
+
+  private:
+    std::ostream &     _str;
+    const TableLayout &        _layout;
+    const TFormater &  _formater;
+    mutable Table      _t;
+  };
 
-      void endLine()
-      { std::cout << std::endl; _cpos = 0U; }
 
-    private:
-      const ListLayout _layout;
-      unsigned         _linewidth;     ///< desired line width
-      const std::string        _indent;
-      unsigned         _cpos;
-    };
+  /** Write formated container to stream */
+  template <class TContainer, class TFormater, class TLayout = typename TFormater::NormalLayout>
+  void writeContainer( std::ostream & str_r, const TContainer & container_r, const TFormater & formater_r, const TLayout & layout_r = TLayout() )
+  {
+    typedef typename TLayout::template Writer<TFormater> Writer;
+    Writer writer( str_r, layout_r, formater_r );
+    for ( auto && el : container_r )
+      writer << el;
   }
+
+  /** Write XML formated container to stream */
+  template <class TContainer, class TFormater>
+  void xmlWriteContainer( std::ostream & str_r, const TContainer & container_r, const TFormater & formater_r )
+  { writeContainer( str_r, container_r, out::XmlFormaterAdaptor<TFormater>(formater_r) ); }
+
 } // namespace out
 ///////////////////////////////////////////////////////////////////
 
@@ -358,74 +485,40 @@ public:
     { if ( out().typeNORMAL() && ! title_r.empty() ) std::cout << title_r << std::endl; }
   };
 
-  ///////////////////////////////////////////////////////////////////
-  /// \class List<ListFormater>
-  /// \brief Printing a list
-  ///////////////////////////////////////////////////////////////////
-  template <class ListFormater_ = out::ListFormater>
-  struct List : protected ParentOut
-  {
-    List( Out & out_r, ListFormater_ formater_r, out::ListLayout layout_r = typename ListFormater_::ListLayout() )
-    : ParentOut( out_r ), _formater( std::move(formater_r) ), _base( std::move(layout_r), out_r.termwidth() )
-    {}
-
-    template <class Tp_>
-    List & operator<<( Tp_ && val_r )
-    { _base.print( _formater( std::forward<Tp_>(val_r) ) ); return *this; }
-
-  private:
-    ListFormater_ _formater;
-    out::detail::BasicList _base;
-  };
-  ///////////////////////////////////////////////////////////////////
-
-public:
-  /** Write list from iterator pair */
-  template <class Iterator_, class ListFormater_ = out::ListFormater>
-  void list( Iterator_ begin_r, Iterator_ end_r, ListFormater_ && formater_r = ListFormater_() )
+private:
+  /** Write container creating a TitleNode with \c size="nnn" attribue and
+   * replacing optional \c %1% in \a title_r with size. */
+  template <class TContainer, class TFormater>
+  void container( const std::string & nodeName_r, const std::string & title_r,
+                 const TContainer & container_r, const TFormater & formater_r )
   {
+    TitleNode guard( XmlNode( *this, nodeName_r, XmlNode::Attr( "size", str::numstring( container_r.size() ) ) ),
+                    str::FormatNAC( title_r ) % container_r.size() );
     switch ( type() )
     {
       case TYPE_NORMAL:
-      {
-       List<ListFormater_> mlist( *this, std::forward<ListFormater_>(formater_r) );
-       for_( it, begin_r, end_r ) mlist << ( *it );
-      }
-      break;
+       writeContainer( std::cout, container_r, formater_r );
+       break;
       case TYPE_XML:
-      {
-       typedef typename ListFormater_::XmlFormater XmlFormater;
-       List<XmlFormater> mlist( *this, XmlFormater(), out::XmlListLayout() );
-       for_( it, begin_r, end_r ) mlist << ( *it );
-      }
-      break;
+       xmlWriteContainer( std::cout, container_r, formater_r );
+       break;
     }
   }
 
-  /** Write list from constainer */
-  template <class Container_, class ListFormater_ = out::ListFormater>
-  void list( const Container_ & container_r, ListFormater_ && formater_r = ListFormater_() )
-  { list( container_r.begin(), container_r.end(), std::forward<ListFormater_>(formater_r) ); }
-
-  /** Write list from iterator pair enclosed by a \ref Node */
-  template <class Iterator_, class ListFormater_ = out::ListFormater>
-  void list( XmlNode && node_r, Iterator_ begin_r, Iterator_ end_r, ListFormater_ && formater_r = ListFormater_() )
-  { XmlNode guard( std::move(node_r) ); list( begin_r, end_r, std::forward<ListFormater_>(formater_r) ); }
-
-  /** Write list from constainer enclosed by a \ref Node */
-  template <class Container_, class ListFormater_ = out::ListFormater>
-  void list( XmlNode && node_r, const Container_ & container_r, ListFormater_ && formater_r = ListFormater_() )
-  { XmlNode guard( std::move(node_r) ); list( container_r.begin(), container_r.end(), std::forward<ListFormater_>(formater_r) ); }
-
+public:
   /** Write list from container creating a TitleNode with \c size="nnn" attribue and
    * replacing optional \c %1% in \a title_r with size. */
-  template <class Container_, class ListFormater_ = out::ListFormater>
-  void list( const std::string & nodeName_r, const std::string & title_r, const Container_ & container_r, ListFormater_ && formater_r = ListFormater_() )
-  {
-    TitleNode guard( XmlNode( *this, nodeName_r, XmlNode::Attr( "size", str::numstring( container_r.size() ) ) ),
-                    str::FormatNAC( title_r ) % container_r.size() );
-    list( container_r, std::forward<ListFormater_>(formater_r) );
-  }
+  template <class TContainer, class TFormater = out::ListFormater>
+  void list( const std::string & nodeName_r, const std::string & title_r,
+            const TContainer & container_r, const TFormater & formater_r = TFormater() )
+  { container( nodeName_r, title_r, container_r, formater_r ); }
+
+  /** Write table from container creating a TitleNode with \c size="nnn" attribue and
+   * replacing optional \c %1% in \a title_r with size. */
+  template <class TContainer, class TFormater = out::TableFormater>
+  void table( const std::string & nodeName_r, const std::string & title_r,
+             const TContainer & container_r, const TFormater & formater_r = TFormater() )
+  { container( nodeName_r, title_r, container_r, formater_r ); }
 
 public:
   /** NORMAL: An empty line */
@@ -473,8 +566,8 @@ public:
     ~Info()
     { out().info( _str->str() ); }
 
-    template<class Tp_>
-    std::ostream & operator<<( const Tp_ & val )
+    template<class Tp>
+    std::ostream & operator<<( const Tp & val )
     { return (*_str) << val; /*return *this;*/ }
 
    private:
@@ -695,10 +788,11 @@ public:
     return ret;
   }
 
-protected:
   /** Width for formated output [0==unlimited]. */
   virtual unsigned termwidth() const { return out::termwidthUnlimited; }
 
+protected:
+
   /**
    * Determine whether the output is intended for the particular type.
    */
index 9a95045..469c759 100644 (file)
@@ -17,6 +17,7 @@ stream-element =
       selectable-list-element? |
       search-result-element? |   # for zypper search
       selectable-info-element? | # for zypper info
+      locks-list-element? |     # for zypper locks
 
       # random text can appear between tags - this text should be ignored
       text
@@ -207,6 +208,29 @@ selectable-info-element =
     )
   }
 
+locks-list-element =
+  element locks {
+    attribute size { xsd:integer },
+    element lock {
+      attribute number { xsd:integer },
+      element name { xsd:string }*,
+      element type { xsd:string }*,
+      element repo { xsd:string }*,
+      element matches {
+        attribute size { xsd:integer },
+        element match {
+          attribute arch { xsd:string },
+          attribute edition { xsd:string },
+          attribute installed { xsd:boolean },
+          attribute name { xsd:string },
+          attribute repo { xsd:string },
+          attribute kind { xsd:string }
+        }*
+      }?
+    }*
+  }
+
+
 # TODO
 common-selectable-info =
   attribute installed { xsd:boolean },
@@ -222,3 +246,5 @@ patch-selectable-info =
     "installed" | "not-installed" | "not-applicable" | "no-longer-applicable" |
     "applied" | "not-needed" | "broken" | "needed"
   }
+
+