Hello community,

here is the log from the commit of package libzypp for openSUSE:Factory checked 
in at 2013-11-24 12:11:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libzypp (Old)
 and      /work/SRC/openSUSE:Factory/.libzypp.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libzypp"

Changes:
--------
--- /work/SRC/openSUSE:Factory/libzypp/libzypp.changes  2013-11-07 
08:42:32.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.libzypp.new/libzypp.changes     2013-11-24 
12:11:31.000000000 +0100
@@ -1,0 +2,11 @@
+Wed Nov 20 16:32:30 CET 2013 - m...@suse.de
+
+- Extend commit plugin to send the transaction list (Fate#316203)
+- Add base/Json.h: JSON encoder for e.g. sending data to plugins
+- Re-evaluate dropped packages list on upgrade, even if product 
+  remains unchanged (bnc#849251).
+- Add ppc64le architecture
+- Add m68k architecture
+- version 14.2.0 (2)
+
+-------------------------------------------------------------------

Old:
----
  libzypp-14.1.1.tar.bz2

New:
----
  libzypp-14.2.0.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libzypp.spec ++++++
--- /var/tmp/diff_new_pack.dA1FSs/_old  2013-11-24 12:11:32.000000000 +0100
+++ /var/tmp/diff_new_pack.dA1FSs/_new  2013-11-24 12:11:32.000000000 +0100
@@ -23,7 +23,7 @@
 Summary:        Package, Patch, Pattern, and Product Management
 License:        GPL-2.0+
 Group:          System/Packages
-Version:        14.1.1
+Version:        14.2.0
 Release:        0
 Source:         %{name}-%{version}.tar.bz2
 Source1:        %{name}-rpmlintrc
@@ -32,7 +32,7 @@
 
 # Features we provide (update doc/autoinclude/FeatureTest.doc):
 Provides:       libzypp(plugin) = 0
-Provides:       libzypp(plugin:commit) = 0
+Provides:       libzypp(plugin:commit) = 1
 Provides:       libzypp(plugin:services) = 0
 Provides:       libzypp(plugin:system) = 0
 Provides:       libzypp(plugin:urlresolver) = 0

++++++ libzypp-14.1.1.tar.bz2 -> libzypp-14.2.0.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/VERSION.cmake 
new/libzypp-14.2.0/VERSION.cmake
--- old/libzypp-14.1.1/VERSION.cmake    2013-10-25 15:21:46.000000000 +0200
+++ new/libzypp-14.2.0/VERSION.cmake    2013-11-20 16:37:43.000000000 +0100
@@ -59,10 +59,10 @@
 #   See './mkChangelog -h' for help.
 #
 SET(LIBZYPP_MAJOR "14")
-SET(LIBZYPP_COMPATMINOR "0")
-SET(LIBZYPP_MINOR "1")
-SET(LIBZYPP_PATCH "1")
+SET(LIBZYPP_COMPATMINOR "2")
+SET(LIBZYPP_MINOR "2")
+SET(LIBZYPP_PATCH "0")
 #
-# LAST RELEASED: 14.1.1 (0)
+# LAST RELEASED: 14.2.0 (2)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/doc/autoinclude/Plugin-Commit.doc 
new/libzypp-14.2.0/doc/autoinclude/Plugin-Commit.doc
--- old/libzypp-14.1.1/doc/autoinclude/Plugin-Commit.doc        2013-03-20 
09:29:29.000000000 +0100
+++ new/libzypp-14.2.0/doc/autoinclude/Plugin-Commit.doc        2013-11-20 
16:37:43.000000000 +0100
@@ -7,7 +7,7 @@
 <HR><!-- 
====================================================================== -->
 \section intro Introduction
 
-This is a statefull plugin executed during \ref zypp::ZYpp::commit. At the 
beginning of a commit all plugins found in \c /usr/lib/zypp/plugins/commit are 
launched. The plugins will receive messages as commit proceeds. Unless 
otherwise specified messages received need to be confirmed by sending an \c ACC 
message. Sending back an \c ERROR message execution of the plugin will be 
canceled.
+This is a statefull plugin executed during \ref zypp::ZYpp::commit. At the 
beginning of a commit all plugins found in \c /usr/lib/zypp/plugins/commit are 
launched. The plugins will receive messages as commit proceeds. Unless 
otherwise specified messages received need to be confirmed by sending an \c ACC 
message. Sending back an unexpected or \c ERROR message execution of the plugin 
will be canceled.
 
 If you have e.g. \c zypp-plugin-python installed a basic commit plugin could 
look like this:
 
@@ -52,6 +52,58 @@
 
 
 <HR><!-- 
====================================================================== -->
+\section commitbegin COMMITBEGIN (added in v1)
+\verbatim
+COMMITBEGIN
+
+{
+"TransactionStepList": [ <TransactionStep>,... ]
+}
+^@
+\endverbatim
+Sent before installation actually starts. The body contains a JSON encoded 
object providing the \c TransactionStepList, basically the list of 
install/remove actions the the commit is going to perform. Each \c 
TransactionStep is encoded as JSON object:
+\verbatim
+<TransactionStep> = {
+  "type":     <TypeString>    # [optional]
+  "stage":    <StageString>   # [optional]
+  "solvable": <Solvable>
+}
+
+<TypeString> = <missing>      # ignore; implicit or non-package actions
+            | "-"            # remove
+            | "+"            # install
+            | "M"            # multi version install; install keeping the old 
version; e.g. kernel
+
+<StageString> = <missing>     # todo
+              | "ok"          # done
+              | "err"         # failed
+
+<Solvable> = {
+  "n": <string>               # name
+  "e": <number>               # epoch if not 0 [optional]
+  "v": <string>               # version
+  "r": <string>               # release
+  "a": <string>               # architecture
+}
+\endverbatim
+
+\see \ref zypp::sat::Transaction::Step
+
+<HR><!-- 
====================================================================== -->
+\section commitend COMMITEND (added in v1)
+\verbatim
+COMMITEND
+
+{
+"TransactionStepList": [ <TransactionStep>,... ]
+}
+^@
+\endverbatim
+Sent at the end of commit. The body contains a JSON encoded object providing 
the final \c TransactionStepList. The \c StepStage indicates whether the action 
succeeded, failed or was skipped (still 'todo').
+
+\see \ref commitbegin
+
+<HR><!-- 
====================================================================== -->
 \section pluginend PLUGINEND
 \verbatim
 PLUGINEND
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/libzypp.spec.cmake 
new/libzypp-14.2.0/libzypp.spec.cmake
--- old/libzypp-14.1.1/libzypp.spec.cmake       2013-07-11 11:12:43.000000000 
+0200
+++ new/libzypp-14.2.0/libzypp.spec.cmake       2013-11-20 16:37:43.000000000 
+0100
@@ -32,7 +32,7 @@
 
 # Features we provide (update doc/autoinclude/FeatureTest.doc):
 Provides:       libzypp(plugin) = 0
-Provides:       libzypp(plugin:commit) = 0
+Provides:       libzypp(plugin:commit) = 1
 Provides:       libzypp(plugin:services) = 0
 Provides:       libzypp(plugin:system) = 0
 Provides:       libzypp(plugin:urlresolver) = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/package/libzypp.changes 
new/libzypp-14.2.0/package/libzypp.changes
--- old/libzypp-14.1.1/package/libzypp.changes  2013-10-25 15:21:46.000000000 
+0200
+++ new/libzypp-14.2.0/package/libzypp.changes  2013-11-20 16:37:43.000000000 
+0100
@@ -1,4 +1,15 @@
 -------------------------------------------------------------------
+Wed Nov 20 16:32:30 CET 2013 - m...@suse.de
+
+- Extend commit plugin to send the transaction list (Fate#316203)
+- Add base/Json.h: JSON encoder for e.g. sending data to plugins
+- Re-evaluate dropped packages list on upgrade, even if product 
+  remains unchanged (bnc#849251).
+- Add ppc64le architecture
+- Add m68k architecture
+- version 14.2.0 (2)
+
+-------------------------------------------------------------------
 Fri Oct 25 14:21:31 CEST 2013 - m...@suse.de
 
 - Always properly initialize pool storage (bnc#846565)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/tests/zypp/PluginFrame_test.cc 
new/libzypp-14.2.0/tests/zypp/PluginFrame_test.cc
--- old/libzypp-14.1.1/tests/zypp/PluginFrame_test.cc   2013-03-20 
09:29:30.000000000 +0100
+++ new/libzypp-14.2.0/tests/zypp/PluginFrame_test.cc   2013-11-20 
16:37:43.000000000 +0100
@@ -50,12 +50,14 @@
   h.addHeader( "" ); // empty KV in header is ok, if you like it
   BOOST_CHECK_EQUAL( (g == h), false );
 
-  h.addHeader( "a", "a1" );
-  h.addHeader( "a", "a2" );
-  h.addHeader( "b", "b1" );
-  h.addHeader( "b", "b2" );
-  h.addHeader( "c", "c1" );
-  h.addHeader( "c", "c1" );
+  h.addHeader({
+    { "a", "a1" },
+    { "a", "a2" },
+    { "b", "b1" },
+    { "b", "b2" },
+    { "c", "c1" },
+    { "c", "c1" }
+  });
   BOOST_CHECK_EQUAL( h.headerSize(), 7 );
 
   h.setHeader( "b", "b" ); // replaces existing 'b:" headers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/Arch.cc 
new/libzypp-14.2.0/zypp/Arch.cc
--- old/libzypp-14.1.1/zypp/Arch.cc     2013-07-02 12:20:05.000000000 +0200
+++ new/libzypp-14.2.0/zypp/Arch.cc     2013-11-14 11:57:43.000000000 +0100
@@ -137,78 +137,86 @@
 namespace zypp
 { /////////////////////////////////////////////////////////////////
 
-  ///////////////////////////////////////////////////////////////////
-  namespace
-  { /////////////////////////////////////////////////////////////////
-
-    // Builtin architecture STRING VALUES to be
-    // used in defCompatibleWith below!
-    //
-    // const IdString  _foo( "foo" );
-    //
-    // NOTE: Builtin CLASS Arch CONSTANTS are defined below.
-    //       You have to change them accordingly.
-    //
-    // NOTE: Thake care CompatBits::IntT is able to provide one
-    //       bit for each architecture.
-    //
-#define DEF_BUILTIN(A) static inline const IdString & _##A () { static 
IdString __str(#A); return __str; }
-    DEF_BUILTIN( noarch );
+  // Builtin architecture STRING VALUES to be
+  // used in defCompatibleWith below!
+  //
+  // const IdString  _foo( "foo" );
+  // const Arch Arch_foo( _foo() );
+  //
+  // NOTE: Builtin CLASS Arch CONSTANTS are defined below.
+  //       You have to change them accordingly in Arch.h.
+  //
+  // NOTE: Thake care CompatBits::IntT is able to provide one
+  //       bit for each architecture.
+  //
+  #define DEF_BUILTIN(A) \
+  namespace { static inline const IdString & _##A () { static IdString 
__str(#A); return __str; } } \
+  const Arch Arch_##A( _##A() )
+
+  DEF_BUILTIN( noarch );
+
+  DEF_BUILTIN( i386 );
+  DEF_BUILTIN( i486 );
+  DEF_BUILTIN( i586 );
+  DEF_BUILTIN( i686 );
+  DEF_BUILTIN( athlon );
+  DEF_BUILTIN( x86_64 );
+
+  DEF_BUILTIN( pentium3 );
+  DEF_BUILTIN( pentium4 );
+
+  DEF_BUILTIN( s390 );
+  DEF_BUILTIN( s390x );
+
+  DEF_BUILTIN( ppc );
+  DEF_BUILTIN( ppc64 );
+  DEF_BUILTIN( ppc64p7 );
+
+  DEF_BUILTIN( ppc64le );
+
+  DEF_BUILTIN( ia64 );
+
+  DEF_BUILTIN( alphaev67 );
+  DEF_BUILTIN( alphaev6 );
+  DEF_BUILTIN( alphapca56 );
+  DEF_BUILTIN( alphaev56 );
+  DEF_BUILTIN( alphaev5 );
+  DEF_BUILTIN( alpha );
+
+  DEF_BUILTIN( sparc64v );
+  DEF_BUILTIN( sparcv9v );
+  DEF_BUILTIN( sparc64 );
+  DEF_BUILTIN( sparcv9 );
+  DEF_BUILTIN( sparcv8 );
+  DEF_BUILTIN( sparc );
+
+  DEF_BUILTIN( aarch64 );
+  DEF_BUILTIN( armv7tnhl );
+  DEF_BUILTIN( armv7thl );
+  DEF_BUILTIN( armv7nhl );
+  DEF_BUILTIN( armv7hl );
+  DEF_BUILTIN( armv7l );
+  DEF_BUILTIN( armv6hl );
+  DEF_BUILTIN( armv6l );
+  DEF_BUILTIN( armv5tejl );
+  DEF_BUILTIN( armv5tel );
+  DEF_BUILTIN( armv5l );
+  DEF_BUILTIN( armv4tl );
+  DEF_BUILTIN( armv4l );
+  DEF_BUILTIN( armv3l );
 
-    DEF_BUILTIN( i386 );
-    DEF_BUILTIN( i486 );
-    DEF_BUILTIN( i586 );
-    DEF_BUILTIN( i686 );
-    DEF_BUILTIN( athlon );
-    DEF_BUILTIN( x86_64 );
-
-    DEF_BUILTIN( pentium3 );
-    DEF_BUILTIN( pentium4 );
-
-    DEF_BUILTIN( s390 );
-    DEF_BUILTIN( s390x );
-
-    DEF_BUILTIN( ppc );
-    DEF_BUILTIN( ppc64 );
-    DEF_BUILTIN( ppc64p7 );
-
-    DEF_BUILTIN( ia64 );
-
-    DEF_BUILTIN( alphaev67 );
-    DEF_BUILTIN( alphaev6 );
-    DEF_BUILTIN( alphapca56 );
-    DEF_BUILTIN( alphaev56 );
-    DEF_BUILTIN( alphaev5 );
-    DEF_BUILTIN( alpha );
-
-    DEF_BUILTIN( sparc64v );
-    DEF_BUILTIN( sparcv9v );
-    DEF_BUILTIN( sparc64 );
-    DEF_BUILTIN( sparcv9 );
-    DEF_BUILTIN( sparcv8 );
-    DEF_BUILTIN( sparc );
-
-    DEF_BUILTIN( aarch64 );
-    DEF_BUILTIN( armv7tnhl );
-    DEF_BUILTIN( armv7thl );
-    DEF_BUILTIN( armv7nhl );
-    DEF_BUILTIN( armv7hl );
-    DEF_BUILTIN( armv7l );
-    DEF_BUILTIN( armv6hl );
-    DEF_BUILTIN( armv6l );
-    DEF_BUILTIN( armv5tejl );
-    DEF_BUILTIN( armv5tel );
-    DEF_BUILTIN( armv5l );
-    DEF_BUILTIN( armv4tl );
-    DEF_BUILTIN( armv4l );
-    DEF_BUILTIN( armv3l );
+  DEF_BUILTIN( sh3 );
 
-    DEF_BUILTIN( sh3 );
+  DEF_BUILTIN( sh4 );
+  DEF_BUILTIN( sh4a );
 
-    DEF_BUILTIN( sh4 );
-    DEF_BUILTIN( sh4a );
+  DEF_BUILTIN(m68k);
 #undef DEF_BUILTIN
 
+  ///////////////////////////////////////////////////////////////////
+  namespace
+  { /////////////////////////////////////////////////////////////////
+
     ///////////////////////////////////////////////////////////////////
     //
     // CLASS NAME : CompatSet
@@ -302,6 +310,8 @@
         defCompatibleWith( _ppc64(),           _noarch(),_ppc() );
         defCompatibleWith( _ppc64p7(),         _noarch(),_ppc(),_ppc64() );
         //
+        defCompatibleWith( _ppc64le(),         _noarch() );
+        //
         defCompatibleWith( _alpha(),           _noarch() );
         defCompatibleWith( _alphaev5(),                _noarch(),_alpha() );
         defCompatibleWith( _alphaev56(),       _noarch(),_alpha(),_alphaev5() 
);
@@ -336,6 +346,8 @@
         //
         defCompatibleWith( _sh4(),             _noarch() );
         defCompatibleWith( _sh4a(),            _noarch(),_sh4() );
+
+        defCompatibleWith(_m68k(),             _noarch());
         //
         ///////////////////////////////////////////////////////////////////
         // dumpOn( USR ) << endl;
@@ -402,60 +414,7 @@
   ///////////////////////////////////////////////////////////////////
 
   const Arch Arch_empty ( IdString::Empty );
-  const Arch Arch_noarch( _noarch() );
-
-  const Arch Arch_i386( _i386() );
-  const Arch Arch_i486( _i486() );
-  const Arch Arch_i586( _i586() );
-  const Arch Arch_i686( _i686() );
-  const Arch Arch_athlon( _athlon() );
-  const Arch Arch_x86_64( _x86_64() );
-
-  const Arch Arch_pentium3( _pentium3() );
-  const Arch Arch_pentium4( _pentium4() );
-
-  const Arch Arch_s390( _s390() );
-  const Arch Arch_s390x( _s390x() );
-
-  const Arch Arch_ppc( _ppc() );
-  const Arch Arch_ppc64( _ppc64() );
-  const Arch Arch_ppc64p7( _ppc64p7() );
-
-  const Arch Arch_ia64( _ia64() );
-
-  const Arch Arch_alphaev67( _alphaev67() );
-  const Arch Arch_alphaev6( _alphaev6() );
-  const Arch Arch_alphapca56( _alphapca56() );
-  const Arch Arch_alphaev56( _alphaev56() );
-  const Arch Arch_alphaev5( _alphaev5() );
-  const Arch Arch_alpha( _alpha() );
-
-  const Arch Arch_sparc64v( _sparc64v() );
-  const Arch Arch_sparc64( _sparc64() );
-  const Arch Arch_sparcv9v( _sparcv9v() );
-  const Arch Arch_sparcv9( _sparcv9() );
-  const Arch Arch_sparcv8( _sparcv8() );
-  const Arch Arch_sparc( _sparc() );
-
-  const Arch Arch_aarch64( _aarch64() );
-  const Arch Arch_armv7tnhl( _armv7tnhl() );
-  const Arch Arch_armv7thl( _armv7thl() );
-  const Arch Arch_armv7nhl ( _armv7nhl() );
-  const Arch Arch_armv7hl ( _armv7hl() );
-  const Arch Arch_armv7l( _armv7l() );
-  const Arch Arch_armv6hl ( _armv6hl() );
-  const Arch Arch_armv6l( _armv6l() );
-  const Arch Arch_armv5tejl( _armv5tejl() );
-  const Arch Arch_armv5tel( _armv5tel() );
-  const Arch Arch_armv5l( _armv5l() );
-  const Arch Arch_armv4tl( _armv4tl() );
-  const Arch Arch_armv4l( _armv4l() );
-  const Arch Arch_armv3l( _armv3l() );
-
-  const Arch Arch_sh3( _sh3() );
-
-  const Arch Arch_sh4( _sh4() );
-  const Arch Arch_sh4a( _sh4a() );
+  // remaining Arch_* constants are defined by DEF_BUILTIN above.
 
   ///////////////////////////////////////////////////////////////////
   //
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/Arch.h 
new/libzypp-14.2.0/zypp/Arch.h
--- old/libzypp-14.1.1/zypp/Arch.h      2013-07-02 12:02:15.000000000 +0200
+++ new/libzypp-14.2.0/zypp/Arch.h      2013-11-14 11:57:43.000000000 +0100
@@ -188,6 +188,9 @@
   extern const Arch Arch_s390;
 
   /** \relates Arch */
+  extern const Arch Arch_ppc64le;
+
+  /** \relates Arch */
   extern const Arch Arch_ppc64p7;
   /** \relates Arch */
   extern const Arch Arch_ppc64;
@@ -259,6 +262,9 @@
   extern const Arch Arch_sh4;
   /** \relates Arch */
   extern const Arch Arch_sh4a;
+
+  /** \relates Arch */
+  extern const Arch Arch_m68k;
   //@}
 
   ///////////////////////////////////////////////////////////////////
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/CMakeLists.txt 
new/libzypp-14.2.0/zypp/CMakeLists.txt
--- old/libzypp-14.1.1/zypp/CMakeLists.txt      2013-05-16 12:07:02.000000000 
+0200
+++ new/libzypp-14.2.0/zypp/CMakeLists.txt      2013-11-20 16:37:43.000000000 
+0100
@@ -239,6 +239,7 @@
   base/IOStream.h
   base/InputStream.h
   base/Iterator.h
+  base/Json.h
   base/LogControl.h
   base/LogTools.h
   base/Logger.h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/PluginFrame.cc 
new/libzypp-14.2.0/zypp/PluginFrame.cc
--- old/libzypp-14.1.1/zypp/PluginFrame.cc      2013-03-20 09:29:30.000000000 
+0100
+++ new/libzypp-14.2.0/zypp/PluginFrame.cc      2013-11-20 16:37:43.000000000 
+0100
@@ -17,6 +17,9 @@
 
 using std::endl;
 
+#undef  ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
+
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
@@ -35,10 +38,17 @@
       Impl( const std::string & command_r )
       { setCommand( command_r ); }
 
-      Impl( const std::string & command_r, const std::string body_r )
+      Impl( const std::string & command_r, const std::string & body_r )
        : _body( body_r )
       { setCommand( command_r ); }
 
+      Impl( const std::string & command_r, HeaderInitializerList contents_r )
+      { setCommand( command_r ); addHeader( contents_r ); }
+
+      Impl( const std::string & command_r, const std::string & body_r, 
HeaderInitializerList contents_r )
+       : _body( body_r )
+      { setCommand( command_r ); addHeader( contents_r ); }
+
       Impl( std::istream & stream_r );
 
     public:
@@ -122,6 +132,12 @@
        _header.insert( mkHeaderPair( key_r, value_r ) );
       }
 
+      void addHeader( HeaderInitializerList contents_r )
+      {
+       for ( const auto & el : contents_r )
+         addHeader( el.first, el.second );
+      }
+
       void clearHeader( const std::string & key_r )
       {
        _header.erase( key_r );
@@ -234,6 +250,12 @@
     return _val;
   }
 
+  const std::string & PluginFrame::enomethodCommand()
+  {
+    static std::string _val( "_ENOMETHOD" );
+    return _val;
+  }
+
   PluginFrame::PluginFrame()
     : _pimpl( Impl::nullimpl() )
   {}
@@ -242,10 +264,18 @@
     : _pimpl( new Impl( command_r ) )
   {}
 
-  PluginFrame::PluginFrame( const std::string & command_r, const std::string 
body_r )
+  PluginFrame::PluginFrame( const std::string & command_r, const std::string & 
body_r )
     : _pimpl( new Impl( command_r, body_r ) )
   {}
 
+  PluginFrame::PluginFrame( const std::string & command_r, 
HeaderInitializerList contents_r )
+    : _pimpl( new Impl( command_r, contents_r ) )
+  {}
+
+  PluginFrame::PluginFrame( const std::string & command_r, const std::string & 
body_r, HeaderInitializerList contents_r )
+    : _pimpl( new Impl( command_r, body_r, contents_r ) )
+  {}
+
   PluginFrame::PluginFrame( std::istream & stream_r )
     : _pimpl( new Impl( stream_r ) )
   {}
@@ -292,6 +322,9 @@
   void PluginFrame::addHeader( const std::string & key_r, const std::string & 
value_r )
   { _pimpl->addHeader( key_r, value_r ); }
 
+  void PluginFrame::addHeader( HeaderInitializerList contents_r )
+  { _pimpl->addHeader( contents_r ); }
+
   void PluginFrame::clearHeader( const std::string & key_r )
   { _pimpl->clearHeader( key_r ); }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/PluginFrame.h 
new/libzypp-14.2.0/zypp/PluginFrame.h
--- old/libzypp-14.1.1/zypp/PluginFrame.h       2013-10-10 08:21:33.000000000 
+0200
+++ new/libzypp-14.2.0/zypp/PluginFrame.h       2013-11-20 16:37:43.000000000 
+0100
@@ -42,11 +42,15 @@
     friend std::ostream & operator<<( std::ostream & str, const PluginFrame & 
obj );
     friend bool operator==( const PluginFrame & lhs, const PluginFrame & rhs );
 
+    typedef const std::initializer_list<std::pair<std::string,std::string>> & 
HeaderInitializerList;
+
     public:
       /** "ACK" command. */
       static const std::string & ackCommand();
       /** "ERROR" command. */
       static const std::string & errorCommand();
+      /** "_ENOMETHOD" command. */
+      static const std::string & enomethodCommand();
 
     public:
       /** Default exception type */
@@ -63,7 +67,17 @@
       /** Ctor taking command and body
        * \throw PluginFrameException If \ref setCommand throws
        */
-      PluginFrame( const std::string & command_r, const std::string body_r );
+      PluginFrame( const std::string & command_r, const std::string & body_r );
+
+      /** Ctor taking the command and a HeaderInitializerList
+       * \throw PluginFrameException If \ref setCommand throws
+       */
+      PluginFrame( const std::string & command_r, HeaderInitializerList 
contents_r );
+
+      /** Ctor taking command, body and a HeaderInitializerList
+       * \throw PluginFrameException If \ref setCommand throws
+       */
+      PluginFrame( const std::string & command_r, const std::string & body_r, 
HeaderInitializerList contents_r );
 
       /** Ctor reading frame data from a stream
        * \throw PluginFrameException On error reading from stream
@@ -96,6 +110,10 @@
       bool isErrorCommand() const
       {return command() == errorCommand(); }
 
+      /** Convenience to identify an _ENOMETHOD command. */
+      bool isEnomethodCommand() const
+      {return command() == enomethodCommand(); }
+
       /** Return the frame body. */
       const std::string & body() const;
 
@@ -189,11 +207,20 @@
        */
       void setHeader( const std::string & key_r, const std::string & value_r = 
std::string() );
 
+      /** Set a new header list
+       * \throw PluginFrameException If key contains illegal chars (\c NL or 
\c :)
+       * \throw PluginFrameException If value contains illegal chars (\c NL)
+       */
+      void setHeader( HeaderInitializerList contents_r )
+      { headerList().clear(); addHeader( contents_r ); }
+
       /** Add header for \c key_r leaving already existing headers for \c 
key_r unchanged.
        * \throw PluginFrameException If key contains illegal chars (\c NL or 
\c :)
        * \throw PluginFrameException If value contains illegal chars (\c NL)
        */
       void addHeader( const std::string & key_r, const std::string & value_r = 
std::string() );
+      /** \overload taking an initializer_list */
+      void addHeader( HeaderInitializerList contents_r );
 
       /** Remove all headers for \c key_r. */
       void clearHeader( const std::string & key_r );
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/PluginScript.cc 
new/libzypp-14.2.0/zypp/PluginScript.cc
--- old/libzypp-14.1.1/zypp/PluginScript.cc     2013-04-29 10:53:30.000000000 
+0200
+++ new/libzypp-14.2.0/zypp/PluginScript.cc     2013-11-20 16:37:43.000000000 
+0100
@@ -27,6 +27,9 @@
 
 using std::endl;
 
+#undef  ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
+
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
@@ -166,8 +169,7 @@
   /** \relates PluginScrip::Impl Stream output */
   inline std::ostream & operator<<( std::ostream & str, const 
PluginScript::Impl & obj )
   {
-    return dumpRangeLine( str << "PluginScript[" << obj.getPid() << "] " << 
obj.script(),
-                         obj.args().begin(), obj.args().end() );
+    return str << "PluginScript[" << obj.getPid() << "] " << obj.script();
   }
 
   ///////////////////////////////////////////////////////////////////
@@ -217,7 +219,7 @@
     _lastReturn.reset();
     _lastExecError.clear();
 
-    DBG << *this << endl;
+    dumpRangeLine( DBG << *this, _args.begin(), _args.end() ) << endl;
   }
 
   int PluginScript::Impl::close()
@@ -267,7 +269,7 @@
       frame_r.writeTo( datas );
       datas.str().swap( data );
     }
-    DBG << "->send " << frame_r << endl;
+    DBG << *this << " ->send " << frame_r << endl;
 
     if ( PLUGIN_DEBUG )
     {
@@ -421,7 +423,7 @@
     // DBG << " <-read " << data.size() << endl;
     std::istringstream datas( data );
     PluginFrame ret( datas );
-    DBG << "<-" << ret << endl;
+    DBG << *this << " <-" << ret << endl;
     return ret;
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/base/Json.h 
new/libzypp-14.2.0/zypp/base/Json.h
--- old/libzypp-14.1.1/zypp/base/Json.h 1970-01-01 01:00:00.000000000 +0100
+++ new/libzypp-14.2.0/zypp/base/Json.h 2013-11-20 16:37:43.000000000 +0100
@@ -0,0 +1,383 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/base/Json.h
+ *
+*/
+#ifndef ZYPP_BASE_JSON_H
+#define ZYPP_BASE_JSON_H
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+#include <list>
+#include <set>
+#include <map>
+
+#include "zypp/base/Easy.h"
+#include "zypp/base/String.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  namespace json
+  {
+    // JSN Keywords
+    inline static const std::string & nullJSON()       { static const 
std::string _s( "null" );  return _s; }
+    inline static const std::string & trueJSON()       { static const 
std::string _s( "true" );  return _s; }
+    inline static const std::string & falseJSON()      { static const 
std::string _s( "false" ); return _s; }
+
+    ///////////////////////////////////////////////////////////////////
+    namespace detail
+    {
+      inline std::string strEncode( std::string val_r )
+      {
+       typedef unsigned char uchar;
+
+       std::string::size_type add = 2; // enclosing "s
+       for_( r, val_r.begin(), val_r.end() )
+       {
+         if ( uchar(*r) < 32u )
+         {
+           switch ( *r )
+           {
+             case '\b':
+             case '\f':
+             case '\n':
+             case '\r':
+             case '\t':
+               add += 1;       // "\c"
+               break;
+             default:
+               add += 5;       // "\uXXXX"
+               break;
+           }
+         }
+         else
+         {
+           switch ( *r )
+           {
+             case '"':
+             case '/':
+             case '\\':
+               add += 1;       // \-escape
+               break;
+           }
+         }
+       }
+
+       val_r.resize( val_r.size() + add, '@' );
+       auto w( val_r.rbegin() );
+       auto r( w + add );
+
+       *w++ = '"';
+       for ( ; r != val_r.rend(); ++r )
+       {
+         if ( uchar(*r) < 32u )
+         {
+           static const char * digit = "0123456789abcdef";
+           switch ( *r )
+           {
+             case '\b':        // "\c"
+               *w++ = 'b';
+               *w++ = '\\';
+               break;
+             case '\f':        // "\c"
+               *w++ = 'f';
+               *w++ = '\\';
+               break;
+             case '\n':        // "\c"
+               *w++ = 'n';
+               *w++ = '\\';
+               break;
+             case '\r':        // "\c"
+               *w++ = 'r';
+               *w++ = '\\';
+               break;
+             case '\t':        // "\c"
+               *w++ = 't';
+               *w++ = '\\';
+               break;
+             default:          // "\uXXXX"
+               *w++ = digit[uchar(*r) % 15];
+               *w++ = digit[uchar(*r) / 16];
+               *w++ = '0';
+               *w++ = '0';
+               *w++ = 'u';
+               *w++ = '\\';
+               break;
+           }
+         }
+         else
+         {
+           switch ( (*w++ = *r) )
+           {
+             case '"':
+             case '/':
+             case '\\':        // \-escape
+               *w++ = '\\';
+               break;
+           }
+         }
+       }
+       *w++ = '"';
+       return val_r;
+      }
+    } // namespace detail
+    ///////////////////////////////////////////////////////////////////
+
+    // null
+    inline std::string toJSON( void )                  { return nullJSON(); }
+    inline std::string toJSON( std::nullptr_t )                { return 
nullJSON(); }
+
+    // bool
+    inline std::string toJSON( bool val_r  )           { return val_r ? 
trueJSON() : falseJSON(); }
+    inline std::string toJSON( const void * val_r )    { return val_r ? 
trueJSON() : falseJSON(); }
+
+    // numbers
+    inline std::string toJSON( short val_r )           { return 
str::numstring( val_r ); }
+    inline std::string toJSON( unsigned short val_r )  { return 
str::numstring( val_r ); }
+    inline std::string toJSON( int val_r )             { return 
str::numstring( val_r ); }
+    inline std::string toJSON( unsigned val_r )                { return 
str::numstring( val_r ); }
+    inline std::string toJSON( long val_r )            { return 
str::numstring( val_r ); }
+    inline std::string toJSON( unsigned long val_r )   { return 
str::numstring( val_r ); }
+    inline std::string toJSON( long long val_r )       { return 
str::numstring( val_r ); }
+    inline std::string toJSON( unsigned long long val_r ){ return 
str::numstring( val_r ); }
+
+    // strings
+    inline std::string toJSON( const char val_r )      { return 
detail::strEncode( std::string( 1, val_r ) ); }
+    inline std::string toJSON( const char * val_r )    { return val_r ? 
detail::strEncode( val_r ) : nullJSON(); }
+    inline std::string toJSON( const std::string & val_r ){ return 
detail::strEncode( val_r ); }
+
+    // container to Array
+    template <class V> std::string toJSON( const std::vector<V> & cont_r );
+    template <class V> std::string toJSON( const std::list<V> & cont_r );
+    template <class V> std::string toJSON( const std::set<V> & cont_r );
+
+    // map to Object
+    template <class K, class V> std::string toJSON( const std::map<K,V> & 
cont_r );
+
+    /** Type to JSON string representation.
+     * This can be implemented as non-static memberfunction \c asJSON,
+     * or as non-memberfunction \c toJSON;
+     * \code
+     *   class Type;
+     *   std::string Type::asJSON() const;
+     *   std::string toJSON( const Type & );
+     * \endcode
+     */
+    template <class T>
+    std::string toJSON( const T & val_r ) { return val_r.asJSON(); }
+
+    ///////////////////////////////////////////////////////////////////
+    /// \class Value
+    /// \brief JSON representation of datatypes via \ref toJSON
+    /// \code
+    ///   namespace mynamspace
+    ///   {
+    ///     struct Mydata
+    ///     {...};
+    ///
+    ///     std::string toJSON( const Mydata & )
+    ///     { return json::Array{ "answer", 42 }.asJSON(); }
+    ///   }
+    ///
+    ///   mynamspace::Mydata data;
+    ///   json::Object bigone {
+    ///     { "mydata",  data },
+    ///     { "panic",   false },
+    ///     { "nested",  json::Object{ {"one",1}, {"two",2}, {"three",3} } }
+    ///   };
+    ///
+    ///   cout << bigone << endl;
+    ///\endcode
+    /// \see http://www.json.org/
+    ///////////////////////////////////////////////////////////////////
+    struct Value
+    {
+      /** Default ctor (null) */
+      Value() : _data( toJSON() ) {}
+
+      /** Copy ctor */
+      Value( const Value & rhs ) : _data( rhs._data ) {}
+
+      /** Ctor creating a JSON representation of \a T via \ref toJSON(T) */
+      template <class T>
+      Value( const T & val_r ) : _data( toJSON( val_r ) ) {}
+
+      /** JSON representation */
+      const std::string & asJSON() const
+      { return _data; }
+
+      /** String representation */
+      const std::string & asString() const
+      { return asJSON(); }
+
+      /** Stream output */
+      std::ostream & dumpOn( std::ostream & str ) const
+      { return str << _data; }
+
+    private:
+      std::string _data;
+    };
+
+    /** \relates Value Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const Value & obj )
+    { return obj.dumpOn( str ); }
+
+    ///////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    /// \class String
+    /// \brief JSON string
+    /// Force representation as JSON string, mapping e.g. \c null values
+    /// to an empty string. Maninly used in \ref Object as key.
+    ///////////////////////////////////////////////////////////////////
+    struct String : public Value
+    {
+      String()                         : Value( "" ) {}
+      String( std::nullptr_t )         : Value( "" ) {}
+
+      String( const char val_r )       : Value( val_r ) {}
+      String( const char * val_r )     : Value( val_r ? val_r : "" ) {}
+      String( const std::string & val_r ): Value( val_r ) {}
+    };
+
+    ///////////////////////////////////////////////////////////////////
+    /// \class Array
+    /// \brief JSON array
+    ///////////////////////////////////////////////////////////////////
+    struct Array
+    {
+      Array() {}
+
+      /** Construct from container iterator */
+      template <class Iterator>
+      Array( Iterator begin, Iterator end )
+      { for_( it, begin, end ) add( *it ); }
+
+      /** Construct from container initializer list { v1, v2,... } */
+      Array( const std::initializer_list<Value> & contents_r )
+       : Array( contents_r.begin(), contents_r.end() )
+      {}
+
+      /** Push JSON Value to Array */
+      void add( const Value & val_r )
+      { _data.push_back( val_r.asJSON() ); }
+
+      /** \overload from container initializer list { v1, v2,... } */
+      void add( const std::initializer_list<Value> & contents_r )
+      { for_( it, contents_r.begin(), contents_r.end() ) add( *it ); }
+
+      /** JSON representation */
+      std::string asJSON() const
+      { return str::Str() << *this; }
+
+      /** String representation */
+      std::string asString() const
+      { return asJSON(); }
+
+      /** Stream output */
+      std::ostream & dumpOn( std::ostream & str ) const
+      {
+       if ( _data.empty() )
+         return str << "[]";
+       str << '[' << *_data.begin();
+       for_( val, ++_data.begin(), _data.end() )
+         str << ", " << *val;
+       return str << ']';
+      }
+
+    private:
+      std::list<std::string> _data;
+    };
+
+    /** \relates Array Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const Array & obj )
+    { return obj.dumpOn( str ); }
+
+    template <class V>
+    std::string toJSON( const std::vector<V> & cont_r )
+    { return json::Array( cont_r.begin(), cont_r.end() ).asJSON(); }
+
+    template <class V>
+    std::string toJSON( const std::list<V> & cont_r )
+    { return json::Array( cont_r.begin(), cont_r.end() ).asJSON(); }
+
+    template <class V>
+    std::string toJSON( const std::set<V> & cont_r )
+    { return json::Array( cont_r.begin(), cont_r.end() ).asJSON(); }
+
+    ///////////////////////////////////////////////////////////////////
+    /// \class Object
+    /// \brief JSON object
+    ///////////////////////////////////////////////////////////////////
+    struct Object
+    {
+      Object() {}
+
+      /** Construct from map-iterator */
+      template <class Iterator>
+      Object( Iterator begin, Iterator end )
+      { for_( it, begin, end ) add( it->first, it->second ); }
+
+      /** Construct from map-initializer list { {k1,v1}, {k2,v2},... } */
+      Object( const std::initializer_list<std::pair<String, Value>> & 
contents_r )
+       : Object( contents_r.begin(), contents_r.end() )
+      {}
+
+      /** Add key/value pair */
+      void add( const String & key_r, const Value & val_r )
+      { _data[key_r.asJSON()] = val_r.asJSON(); }
+
+      /** \overload from map-initializer list { {k1,v1}, {k2,v2},... } */
+      void add( const std::initializer_list<std::pair<String, Value>> & 
contents_r )
+      { for_( it, contents_r.begin(), contents_r.end() ) add( it->first, 
it->second ); }
+
+      /** JSON representation */
+      std::string asJSON() const
+      { return str::Str() << *this; }
+
+      /** String representation */
+      std::string asString() const
+      { return asJSON(); }
+
+      /** Stream output */
+      std::ostream & dumpOn( std::ostream & str ) const
+      {
+       using std::endl;
+       if ( _data.empty() )
+         return str << "{}";
+       dumpOn( str << '{' << endl, _data.begin() );
+       for_ ( val, ++_data.begin(), _data.end() )
+         dumpOn( str << ',' << endl, val );
+       return str << endl << '}';
+      }
+
+    private:
+      std::ostream & dumpOn( std::ostream & str, 
std::map<std::string,std::string>::const_iterator val_r ) const
+      { return str << val_r->first << ": " << val_r->second; }
+
+      std::map<std::string,std::string> _data;
+    };
+
+    /** \relates Object Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const Object & obj )
+    { return obj.dumpOn( str ); }
+
+    template <class K, class V>
+    std::string toJSON( const std::map<K,V> & cont_r )
+    { return json::Object( cont_r.begin(), cont_r.end() ).asJSON(); }
+
+
+  } // namespace json
+  ///////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_BASE_JSON_H
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/parser/xml/XmlEscape.cc 
new/libzypp-14.2.0/zypp/parser/xml/XmlEscape.cc
--- old/libzypp-14.1.1/zypp/parser/xml/XmlEscape.cc     2013-03-20 
09:29:30.000000000 +0100
+++ new/libzypp-14.2.0/zypp/parser/xml/XmlEscape.cc     2013-11-21 
09:45:42.000000000 +0100
@@ -39,20 +39,30 @@
     {
       std::string escape(const std::string &istr) const
       {
-       size_t i;
-       std::string str = istr;
-       i = str.find_first_of("<>&'\"");
-       while (i != std::string::npos)
+       typedef unsigned char uchar;
+
+       std::string str( istr );
+        for ( size_t i = 0; i < str.size(); ++i )
        {
          switch (str[i])
          {
            case '<': str.replace(i, 1, "&lt;"); i += 3; break;
            case '>': str.replace(i, 1, "&gt;"); i += 3; break;
            case '&': str.replace(i, 1, "&amp;"); i += 4; break;
-           case '\'': str.replace(i, 1, "&apos;"); i += 5; break;
            case '"': str.replace(i, 1, "&quot;"); i += 5; break;
+           case '\'': str.replace(i, 1, "&apos;"); i += 5; break;
+
+           // control chars we allow:
+           case '\n':
+           case '\r':
+           case '\t':
+             break;
+
+           default:
+             if ( uchar(str[i]) < 32u )
+               str[i] = '?'; // filter problematic control chars (XML1.0)
+             break;
          }
-         i = str.find_first_of("<>&'\"", i + 1);
        }
        return str;
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/parser/yum/schema/common-inc.rnc 
new/libzypp-14.2.0/zypp/parser/yum/schema/common-inc.rnc
--- old/libzypp-14.1.1/zypp/parser/yum/schema/common-inc.rnc    2013-03-28 
13:01:31.000000000 +0100
+++ new/libzypp-14.2.0/zypp/parser/yum/schema/common-inc.rnc    2013-11-14 
11:57:43.000000000 +0100
@@ -67,5 +67,6 @@
             | "sh3"
             | "sh4"
             | "sh4a"
+            | "m68k"
             | "src"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/parser/yum/schema/common-inc.rng 
new/libzypp-14.2.0/zypp/parser/yum/schema/common-inc.rng
--- old/libzypp-14.1.1/zypp/parser/yum/schema/common-inc.rng    2013-03-28 
13:01:31.000000000 +0100
+++ new/libzypp-14.2.0/zypp/parser/yum/schema/common-inc.rng    2013-11-14 
11:57:43.000000000 +0100
@@ -130,6 +130,7 @@
       <value>sh3</value>
       <value>sh4</value>
       <value>sh4a</value>
+      <value>m68k</value>
       <value>src</value>
     </choice>
   </define>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/solver/detail/SATResolver.cc 
new/libzypp-14.2.0/zypp/solver/detail/SATResolver.cc
--- old/libzypp-14.1.1/zypp/solver/detail/SATResolver.cc        2013-05-07 
12:19:08.000000000 +0200
+++ new/libzypp-14.2.0/zypp/solver/detail/SATResolver.cc        2013-11-08 
13:29:43.000000000 +0100
@@ -686,8 +686,8 @@
           if ( (*it)->onSystem() ) // (to install) or (not to delete)
           {
             Product::constPtr prodCand( (*it)->candidateAsKind<Product>() );
-            if ( ! prodCand || (*it)->identicalInstalledCandidate() )
-              continue; // product no longer available or unchanged
+            if ( ! prodCand )
+              continue; // product no longer available
 
             CapabilitySet droplist( prodCand->droplist() );
             dumpRangeLine( MIL << "Droplist for " << (*it)->candidateObj() << 
": " << droplist.size() << " ", droplist.begin(), droplist.end() ) << endl;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-14.1.1/zypp/target/TargetImpl.cc 
new/libzypp-14.2.0/zypp/target/TargetImpl.cc
--- old/libzypp-14.1.1/zypp/target/TargetImpl.cc        2013-09-02 
14:29:24.000000000 +0200
+++ new/libzypp-14.2.0/zypp/target/TargetImpl.cc        2013-11-20 
16:37:43.000000000 +0100
@@ -26,6 +26,7 @@
 #include "zypp/base/IOStream.h"
 #include "zypp/base/Functional.h"
 #include "zypp/base/UserRequestException.h"
+#include "zypp/base/Json.h"
 
 #include "zypp/ZConfig.h"
 #include "zypp/ZYppFactory.h"
@@ -64,6 +65,98 @@
 namespace zypp
 { /////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////
+  namespace json
+  {
+    // Lazy via template specialisation / should switch to overloading
+
+    template<>
+    inline std::string toJSON( const ZYppCommitResult::TransactionStepList & 
steps_r )
+    {
+      using sat::Transaction;
+      json::Array ret;
+
+      for ( const Transaction::Step & step : steps_r )
+       // ignore implicit deletes due to obsoletes and non-package actions
+       if ( step.stepType() != Transaction::TRANSACTION_IGNORE )
+         ret.add( step );
+
+      return ret.asJSON();
+    }
+
+    /** See \ref commitbegin on page \ref plugin-commit for the specs. */
+    template<>
+    inline std::string toJSON( const sat::Transaction::Step & step_r )
+    {
+      static const std::string strType( "type" );
+      static const std::string strStage( "stage" );
+      static const std::string strSolvable( "solvable" );
+
+      static const std::string strTypeDel( "-" );
+      static const std::string strTypeIns( "+" );
+      static const std::string strTypeMul( "M" );
+
+      static const std::string strStageDone( "ok" );
+      static const std::string strStageFailed( "err" );
+
+      static const std::string strSolvableN( "n" );
+      static const std::string strSolvableE( "e" );
+      static const std::string strSolvableV( "v" );
+      static const std::string strSolvableR( "r" );
+      static const std::string strSolvableA( "a" );
+
+      using sat::Transaction;
+      json::Object ret;
+
+      switch ( step_r.stepType() )
+      {
+       case Transaction::TRANSACTION_IGNORE:   /*empty*/ break;
+       case Transaction::TRANSACTION_ERASE:    ret.add( strType, strTypeDel ); 
break;
+       case Transaction::TRANSACTION_INSTALL:  ret.add( strType, strTypeIns ); 
break;
+       case Transaction::TRANSACTION_MULTIINSTALL: ret.add( strType, 
strTypeMul ); break;
+      }
+
+      switch ( step_r.stepStage() )
+      {
+       case Transaction::STEP_TODO:            /*empty*/ break;
+       case Transaction::STEP_DONE:            ret.add( strStage, strStageDone 
); break;
+       case Transaction::STEP_ERROR:           ret.add( strStage, 
strStageFailed ); break;
+      }
+
+      {
+       IdString ident;
+       Edition ed;
+       Arch arch;
+       if ( sat::Solvable solv = step_r.satSolvable() )
+       {
+         ident = solv.ident();
+         ed    = solv.edition();
+         arch  = solv.arch();
+       }
+       else
+       {
+         // deleted package; post mortem data stored in Transaction::Step
+         ident = step_r.ident();
+         ed    = step_r.edition();
+         arch  = step_r.arch();
+       }
+
+       json::Object s {
+         { strSolvableN, ident.asString() },
+         { strSolvableV, ed.version() },
+         { strSolvableR, ed.release() },
+         { strSolvableA, arch.asString() }
+       };
+       if ( Edition::epoch_t epoch = ed.epoch() )
+         s.add( strSolvableE, epoch );
+
+       ret.add( strSolvable, s );
+      }
+
+      return ret.asJSON();
+    }
+  } // namespace json
+  ///////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
   namespace target
   { /////////////////////////////////////////////////////////////////
 
@@ -73,8 +166,6 @@
     class CommitPlugins : private base::NonCopyable
     {
       public:
-
-      public:
        /** Default ctor: Empty plugin list */
        CommitPlugins()
        {}
@@ -82,24 +173,31 @@
        /** Dtor: Send PLUGINEND message and close plugins. */
        ~CommitPlugins()
        {
-         for_( it, _scripts.begin(), _scripts.end() )
+         if ( ! _scripts.empty() )
+           send( PluginFrame( "PLUGINEND" ) );
+         // ~PluginScript will disconnect all remaining plugins!
+       }
+
+       /** Whether no plugins are waiting */
+       bool empty() const
+       { return _scripts.empty(); }
+
+
+       /** Send \ref PluginFrame to all open plugins.
+        * Failed plugins are removed from the execution list.
+        */
+       void send( const PluginFrame & frame_r )
+       {
+         DBG << "+++++++++++++++ send " << frame_r << endl;
+         for ( auto it = _scripts.begin(); it != _scripts.end(); )
          {
-           MIL << "Unload plugin: " << *it << endl;
-           try {
-             it->send( PluginFrame( "PLUGINEND" ) );
-             PluginFrame ret( it->receive() );
-             if ( ! ret.isAckCommand() )
-             {
-               WAR << "Failed to unload plugin: Bad plugin response." << endl;
-             }
-             it->close();
-           }
-           catch( const zypp::Exception &  )
-           {
-             WAR << "Failed to unload plugin." << endl;
-           }
+           doSend( *it, frame_r );
+           if ( it->isOpen() )
+             ++it;
+           else
+             it = _scripts.erase( it );
          }
-         // _scripts dtor will disconnect all remaining plugins!
+         DBG << "--------------- send " << frame_r << endl;
        }
 
        /** Find and launch plugins sending PLUGINSTART message.
@@ -111,6 +209,7 @@
        void load( const Pathname & path_r )
        {
          PathInfo pi( path_r );
+         DBG << "+++++++++++++++ load " << pi << endl;
          if ( pi.isDir() )
          {
            std::list<Pathname> entries;
@@ -137,33 +236,55 @@
          {
            WAR << "Plugin path is neither dir nor file: " << pi << endl;
          }
+         DBG << "--------------- load " << pi << endl;
        }
 
       private:
+       /** Send \ref PluginFrame and expect valid answer (ACK|_ENOMETHOD).
+        * Upon invalid answer or error, close the plugin. and remove it from 
the
+        * execution list.
+        * \returns the received \ref PluginFrame (empty Frame upon Exception)
+        */
+       PluginFrame doSend( PluginScript & script_r, const PluginFrame & 
frame_r )
+       {
+         PluginFrame ret;
+
+         try {
+           script_r.send( frame_r );
+           ret = script_r.receive();
+         }
+         catch( const zypp::Exception & e )
+         { ZYPP_CAUGHT(e); }
+
+         if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() ) )
+         {
+           WAR << "Bad plugin response from " << script_r << endl;
+           WAR << dump(ret) << endl;
+           script_r.close();
+         }
+
+         return ret;
+       }
+
+       /** Launch a plugin sending PLUGINSTART message. */
        void doLoad( const PathInfo & pi_r )
        {
          MIL << "Load plugin: " << pi_r << endl;
          try {
+           PluginScript plugin( pi_r.path() );
+           plugin.open();
+
            PluginFrame frame( "PLUGINBEGIN" );
            if ( ZConfig::instance().hasUserData() )
              frame.setHeader( "userdata", ZConfig::instance().userData() );
 
-           PluginScript plugin( pi_r.path() );
-           plugin.open();
-           plugin.send( frame );
-           PluginFrame ret( plugin.receive() );
-           if ( ret.isAckCommand() )
-           {
+           doSend( plugin, frame );    // closes on error
+           if ( plugin.isOpen() )
              _scripts.push_back( plugin );
-           }
-           else
-           {
-             WAR << "Failed to load plugin: Bad plugin response." << endl;
-           }
          }
-         catch( const zypp::Exception &  )
+         catch( const zypp::Exception & e )
          {
-            WAR << "Failed to load plugin." << endl;
+            WAR << "Failed to load plugin " << pi_r << endl;
          }
        }
 
@@ -183,6 +304,16 @@
     }
 
     ///////////////////////////////////////////////////////////////////
+    namespace
+    {
+      inline PluginFrame transactionPluginFrame( const std::string & 
command_r, ZYppCommitResult::TransactionStepList & steps_r )
+      {
+       return PluginFrame( command_r, json::Object {
+         { "TransactionStepList", steps_r }
+       }.asJSON() );
+      }
+    } // namespace
+    ///////////////////////////////////////////////////////////////////
 
     /** \internal Manage writing a new testcase when doing an upgrade. */
     void writeUpgradeTestcase()
@@ -1101,6 +1232,32 @@
       MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
 
       ///////////////////////////////////////////////////////////////////
+      // Compute transaction:
+      ///////////////////////////////////////////////////////////////////
+      ZYppCommitResult result( root() );
+      result.rTransaction() = pool_r.resolver().getTransaction();
+      result.rTransaction().order();
+      // steps: this is our todo-list
+      ZYppCommitResult::TransactionStepList & steps( 
result.rTransactionStepList() );
+      if ( policy_r.restrictToMedia() )
+      {
+       // Collect until the 1st package from an unwanted media occurs.
+        // Further collection could violate install order.
+       MIL << "Restrict to media number " << policy_r.restrictToMedia() << 
endl;
+       for_( it, result.transaction().begin(), result.transaction().end() )
+       {
+         if ( makeResObject( *it )->mediaNr() > 1 )
+           break;
+         steps.push_back( *it );
+       }
+      }
+      else
+      {
+       result.rTransactionStepList().insert( steps.end(), 
result.transaction().begin(), result.transaction().end() );
+      }
+      MIL << "Todo: " << result << endl;
+
+      ///////////////////////////////////////////////////////////////////
       // Prepare execution of commit plugins:
       ///////////////////////////////////////////////////////////////////
       CommitPlugins commitPlugins;
@@ -1109,6 +1266,8 @@
        Pathname plugindir( Pathname::assertprefix( _root, 
ZConfig::instance().pluginsPath()/"commit" ) );
        commitPlugins.load( plugindir );
       }
+      if ( ! commitPlugins.empty() )
+       commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
 
       ///////////////////////////////////////////////////////////////////
       // Write out a testcase if we're in dist upgrade mode.
@@ -1125,7 +1284,7 @@
         }
       }
 
-      ///////////////////////////////////////////////////////////////////
+     ///////////////////////////////////////////////////////////////////
       // Store non-package data:
       ///////////////////////////////////////////////////////////////////
       if ( ! policy_r.dryRun() )
@@ -1153,32 +1312,6 @@
       }
 
       ///////////////////////////////////////////////////////////////////
-      // Compute transaction:
-      ///////////////////////////////////////////////////////////////////
-      ZYppCommitResult result( root() );
-      result.rTransaction() = pool_r.resolver().getTransaction();
-      result.rTransaction().order();
-      // steps: this is our todo-list
-      ZYppCommitResult::TransactionStepList & steps( 
result.rTransactionStepList() );
-      if ( policy_r.restrictToMedia() )
-      {
-       // Collect until the 1st package from an unwanted media occurs.
-        // Further collection could violate install order.
-       MIL << "Restrict to media number " << policy_r.restrictToMedia() << 
endl;
-       for_( it, result.transaction().begin(), result.transaction().end() )
-       {
-         if ( makeResObject( *it )->mediaNr() > 1 )
-           break;
-         steps.push_back( *it );
-       }
-      }
-      else
-      {
-       result.rTransactionStepList().insert( steps.end(), 
result.transaction().begin(), result.transaction().end() );
-      }
-      MIL << "Todo: " << result << endl;
-
-      ///////////////////////////////////////////////////////////////////
       // First collect and display all messages
       // associated with patches to be installed.
       ///////////////////////////////////////////////////////////////////
@@ -1317,6 +1450,12 @@
       }
 
       ///////////////////////////////////////////////////////////////////
+      // Send result to commit plugins:
+      ///////////////////////////////////////////////////////////////////
+      if ( ! commitPlugins.empty() )
+       commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
+
+      ///////////////////////////////////////////////////////////////////
       // Try to rebuild solv file while rpm database is still in cache
       ///////////////////////////////////////////////////////////////////
       if ( ! policy_r.dryRun() )

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to