Hello community,

here is the log from the commit of package libzypp for openSUSE:Factory checked 
in at 2016-03-26 15:11:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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  2016-03-07 
13:36:55.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.libzypp.new/libzypp.changes     2016-03-26 
15:11:12.000000000 +0100
@@ -1,0 +2,17 @@
+Fri Mar 18 13:37:22 CET 2016 - [email protected]
+
+- Use PluginExecutor for commit- and system-hooks (bnc#971637)
+- BuildRequires:  libsolv-devel >= 0.6.19 (bnc#971018)
+- version 15.21.5 (19)
+
+-------------------------------------------------------------------
+Sun Mar 13 01:13:08 CET 2016 - [email protected]
+
+- Update zypp-po.tar.bz2
+
+-------------------------------------------------------------------
+Thu Mar 10 01:13:24 CET 2016 - [email protected]
+
+- Update zypp-po.tar.bz2
+
+-------------------------------------------------------------------

Old:
----
  libzypp-15.21.4.tar.bz2

New:
----
  libzypp-15.21.5.tar.bz2

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

Other differences:
------------------
++++++ libzypp.spec ++++++
--- /var/tmp/diff_new_pack.i1prVY/_old  2016-03-26 15:11:13.000000000 +0100
+++ /var/tmp/diff_new_pack.i1prVY/_new  2016-03-26 15:11:13.000000000 +0100
@@ -19,7 +19,7 @@
 %define force_gcc_46 0
 
 Name:           libzypp
-Version:        15.21.4
+Version:        15.21.5
 Release:        0
 Url:            git://gitorious.org/opensuse/libzypp.git
 Summary:        Package, Patch, Pattern, and Product Management
@@ -36,7 +36,7 @@
 Provides:       libzypp(plugin:appdata) = 0
 Provides:       libzypp(plugin:commit) = 1
 Provides:       libzypp(plugin:services) = 0
-Provides:       libzypp(plugin:system) = 0
+Provides:       libzypp(plugin:system) = 1
 Provides:       libzypp(plugin:urlresolver) = 0
 Provides:       libzypp(repovarexpand) = 0
 
@@ -75,7 +75,7 @@
 BuildRequires:  pkg-config
 %endif
 
-BuildRequires:  libsolv-devel >= 0.6.7
+BuildRequires:  libsolv-devel >= 0.6.19
 %if 0%{?suse_version} >= 1100
 BuildRequires:  libsolv-tools
 %requires_eq    libsolv-tools

++++++ libzypp-15.21.4.tar.bz2 -> libzypp-15.21.5.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/VERSION.cmake 
new/libzypp-15.21.5/VERSION.cmake
--- old/libzypp-15.21.4/VERSION.cmake   2016-03-01 12:36:44.000000000 +0100
+++ new/libzypp-15.21.5/VERSION.cmake   2016-03-18 13:40:46.000000000 +0100
@@ -61,8 +61,8 @@
 SET(LIBZYPP_MAJOR "15")
 SET(LIBZYPP_COMPATMINOR "19")
 SET(LIBZYPP_MINOR "21")
-SET(LIBZYPP_PATCH "4")
+SET(LIBZYPP_PATCH "5")
 #
-# LAST RELEASED: 15.21.4 (19)
+# LAST RELEASED: 15.21.5 (19)
 # (The number in parenthesis is LIBZYPP_COMPATMINOR)
 #=======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/doc/autoinclude/FeatureTest.doc 
new/libzypp-15.21.5/doc/autoinclude/FeatureTest.doc
--- old/libzypp-15.21.4/doc/autoinclude/FeatureTest.doc 2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.21.5/doc/autoinclude/FeatureTest.doc 2016-03-18 
13:28:44.000000000 +0100
@@ -29,32 +29,41 @@
 
   <DT>plugin:commit</DT>
   <DD><DL>
+    <DT>\ref plugin-commit </DT>
     <DT>version 0</DT>
-    <DD>\see \ref plugin-commit </DD>
+    <DD>Basic plugin indicating start and end of commit.</DD>
+    <DT>version 1</DT>
+    <DD>Added COMMITBEGIN/COMMITEND.</DD>
   </DL></DD>
 
   <DT>plugin:services</DT>
   <DD><DL>
+    <DT>\ref plugin-services </DT>
     <DT>version 0</DT>
-    <DD>\see \ref plugin-services </DD>
+    <DD>Provide a client a list of repositories.</DD>
   </DL></DD>
 
   <DT>plugin:system</DT>
   <DD><DL>
+    <DT>\ref plugin-system </DT>
     <DT>version 0</DT>
     <DD>Plugin executed when system content change is detected (by now SUSE 
Manager/spacewalk only).</DD>
+    <DT>version 1</DT>
+    <DD>Plugin executed when system content change is detected (all installed 
plugins).</DD>
   </DL></DD>
 
   <DT>plugin:urlresolver</DT>
   <DD><DL>
+    <DT>\ref plugin-url-resolver </DT>
     <DT>version 0</DT>
-    <DD>\see \ref plugin-url-resolver </DD>
+    <DD>Convert urls of scheme "plugin" into a supported scheme. </DD>
   </DL></DD>
 
   <DT>repovarexpand</DT>
   <DD><DL>
+    <DT>\ref zypp-repovars </DT>
     <DT>version 0</DT>
-    <DD>Also support braced variables, shell like default and alternate 
values. \see \ref zypp-repovars</DD>
+    <DD>Also support braced variables, shell like default and alternate 
values.</DD>
   </DL></DD>
 </DL>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/doc/autoinclude/Plugin-System.doc 
new/libzypp-15.21.5/doc/autoinclude/Plugin-System.doc
--- old/libzypp-15.21.4/doc/autoinclude/Plugin-System.doc       1970-01-01 
01:00:00.000000000 +0100
+++ new/libzypp-15.21.5/doc/autoinclude/Plugin-System.doc       2016-03-18 
13:28:44.000000000 +0100
@@ -0,0 +1,75 @@
+/**
+
+\page plugin-system System plugin
+
+\author Michael Andres <[email protected]>
+
+<HR><!-- 
====================================================================== -->
+\section intro Introduction
+
+This is a statefull plugin executed at the end of \ref zypp::ZYpp::commit, if 
the system content has change, i.e. if packages have actually been installed or 
deleted.
+
+All plugins found in \c /usr/lib/zypp/plugins/system are launched. Unless 
otherwise specified, messages received need to be confirmed by sending an \c 
ACC message. Sending back an unexpected or \c ERROR message, the execution of 
the plugin will be canceled.
+
+If you have e.g. \c zypp-plugin-python installed a basic system plugin could 
look like this:
+
+\verbatim
+#!/usr/bin/env python
+#
+# zypp system plugin
+#
+import os
+import sys
+from zypp_plugin import Plugin
+
+class MyPlugin(Plugin):
+
+  def PACKAGESETCHANGED(self, headers, body):
+
+    // Installation has ended. The set of installed packages has changed.
+    // ....
+
+    self.ack()
+  def
+
+plugin = MyPlugin()
+plugin.main()
+\endverbatim
+
+\see \ref plugin-writing
+
+<HR><!-- 
====================================================================== -->
+\section pluginbegin PLUGINBEGIN
+\verbatim
+PLUGINBEGIN
+userdata:TIDfoo42
+
+^@
+\endverbatim
+Sent as 1st message after the plugin was launched. Prepare your plugin and 
send an \c ACC message when you are done.
+
+\li \c userdata:stringval Optional header sent if the application has provided 
a user data string. \see \ref zypp-userdata
+
+
+<HR><!-- 
====================================================================== -->
+\section packagesetchanged PACKAGESETCHANGED
+\verbatim
+PACKAGESETCHANGED
+
+^@
+\endverbatim
+Installation has ended. The set of installed packages has changed.
+
+\see \ref zypp::sat::Transaction::Step
+
+<HR><!-- 
====================================================================== -->
+\section pluginend PLUGINEND
+\verbatim
+PLUGINEND
+
+^@
+\endverbatim
+This message is sent at the end before the plugin is closed. You should 
receive this message even if the action was aborted by some unexpected 
exception.
+
+
+*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/doc/autoinclude/Plugins.doc 
new/libzypp-15.21.5/doc/autoinclude/Plugins.doc
--- old/libzypp-15.21.4/doc/autoinclude/Plugins.doc     2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.21.5/doc/autoinclude/Plugins.doc     2016-03-18 
13:28:44.000000000 +0100
@@ -100,6 +100,8 @@
 
 \subpage plugin-commit Escort installation of packages
 
+\subpage plugin-system Receive notification if system content has changed
+
 \ref plugin-services
 
 \ref plugin-url-resolver
@@ -155,7 +157,7 @@
 plugin:foo?param1=val1&param2=val2
 \endverbatim
 
-ZYpp tries to executa a plugin named foo (in 
/usr/lib/zypp/plugins/urlresolver) and call it with the following protocol:
+ZYpp tries to execute a plugin named foo (in 
/usr/lib/zypp/plugins/urlresolver) and call it with the following protocol:
 
 \verbatim
    RESOLVEURL
@@ -214,4 +216,4 @@
 \note REPO_METADATA_PATH can be empty or a not existing directory, indicating 
valid metadata for the repo are not yet available.
 
 Scripts are executed 'fire and forget' whenever a RepoManager instance that 
performed changes goes out of scope. So it's up to the script to protect 
against concurrency.
-*/
\ No newline at end of file
+*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/libzypp.spec.cmake 
new/libzypp-15.21.5/libzypp.spec.cmake
--- old/libzypp-15.21.4/libzypp.spec.cmake      2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.21.5/libzypp.spec.cmake      2016-03-18 13:28:44.000000000 
+0100
@@ -36,7 +36,7 @@
 Provides:       libzypp(plugin:appdata) = 0
 Provides:       libzypp(plugin:commit) = 1
 Provides:       libzypp(plugin:services) = 0
-Provides:       libzypp(plugin:system) = 0
+Provides:       libzypp(plugin:system) = 1
 Provides:       libzypp(plugin:urlresolver) = 0
 Provides:       libzypp(repovarexpand) = 0
 
@@ -75,7 +75,7 @@
 BuildRequires:  pkg-config
 %endif
 
-BuildRequires:  libsolv-devel >= 0.6.7
+BuildRequires:  libsolv-devel >= 0.6.19
 %if 0%{?suse_version} >= 1100
 BuildRequires:  libsolv-tools
 %requires_eq    libsolv-tools
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/package/libzypp.changes 
new/libzypp-15.21.5/package/libzypp.changes
--- old/libzypp-15.21.4/package/libzypp.changes 2016-03-01 12:36:44.000000000 
+0100
+++ new/libzypp-15.21.5/package/libzypp.changes 2016-03-18 13:40:46.000000000 
+0100
@@ -1,4 +1,21 @@
 -------------------------------------------------------------------
+Fri Mar 18 13:37:22 CET 2016 - [email protected]
+
+- Use PluginExecutor for commit- and system-hooks (bnc#971637)
+- BuildRequires:  libsolv-devel >= 0.6.19 (bnc#971018)
+- version 15.21.5 (19)
+
+-------------------------------------------------------------------
+Sun Mar 13 01:13:08 CET 2016 - [email protected]
+
+- Update zypp-po.tar.bz2
+
+-------------------------------------------------------------------
+Thu Mar 10 01:13:24 CET 2016 - [email protected]
+
+- Update zypp-po.tar.bz2
+
+-------------------------------------------------------------------
 Tue Mar  1 12:34:53 CET 2016 - [email protected]
 
 - media: Send stats header to download.opensuse.org only (bsc#955801)
Files old/libzypp-15.21.4/po/zypp-po.tar.bz2 and 
new/libzypp-15.21.5/po/zypp-po.tar.bz2 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/tests/zypp/PluginFrame_test.cc 
new/libzypp-15.21.5/tests/zypp/PluginFrame_test.cc
--- old/libzypp-15.21.4/tests/zypp/PluginFrame_test.cc  2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.21.5/tests/zypp/PluginFrame_test.cc  2016-03-18 
15:28:44.000000000 +0100
@@ -5,7 +5,7 @@
 #include <sstream>
 
 #include "TestSetup.h"
-#include "zypp/PluginScript.h"
+#include "zypp/PluginExecutor.h"
 
 BOOST_AUTO_TEST_CASE(InitialSettings)
 {
@@ -15,8 +15,8 @@
 BOOST_AUTO_TEST_CASE(PluginFrameDefaultCtor)
 {
   PluginFrame f;
+  BOOST_CHECK_EQUAL( bool(f), !f.empty() );
   BOOST_CHECK_EQUAL( f.empty(), true );
-  BOOST_CHECK_EQUAL( bool(f), f.empty() );
   BOOST_CHECK_EQUAL( f.command().empty(), true );
   BOOST_CHECK_EQUAL( f.body().empty(), true );
   BOOST_CHECK_EQUAL( f.headerEmpty(), true );
@@ -27,8 +27,8 @@
 BOOST_AUTO_TEST_CASE(PluginFrameCtorAssign)
 {
   PluginFrame f( "command" );
+  BOOST_CHECK_EQUAL( bool(f), !f.empty() );
   BOOST_CHECK_EQUAL( f.empty(), false );
-  BOOST_CHECK_EQUAL( bool(f), f.empty() );
   BOOST_CHECK_EQUAL( f.command(), "command" );
   BOOST_CHECK_EQUAL( f.body().empty(), true );
   BOOST_CHECK_EQUAL( f.headerEmpty(), true );
@@ -36,8 +36,8 @@
   BOOST_CHECK_EQUAL( (f != f), false );
 
   PluginFrame g( "command", "body" );
+  BOOST_CHECK_EQUAL( bool(g), !g.empty() );
   BOOST_CHECK_EQUAL( g.empty(), false );
-  BOOST_CHECK_EQUAL( bool(g), g.empty() );
   BOOST_CHECK_EQUAL( g.command(), "command" );
   BOOST_CHECK_EQUAL( g.body(), "body");
   BOOST_CHECK_EQUAL( g.headerEmpty(), true );
@@ -168,3 +168,25 @@
   ::kill( scr.getPid(), SIGKILL);
   BOOST_CHECK_THROW(  scr.receive(), PluginScriptDiedUnexpectedly );
 }
+
+BOOST_AUTO_TEST_CASE(PluginExecutorTest)
+{
+  PluginExecutor exec;
+  BOOST_CHECK_EQUAL( (bool)exec, !exec.empty() );
+  BOOST_CHECK_EQUAL( exec.empty(), true );
+  BOOST_CHECK_EQUAL( exec.size(), 0 );
+
+  exec.load( "/bin/cat" );
+  BOOST_CHECK_EQUAL( (bool)exec, !exec.empty() );
+  BOOST_CHECK_EQUAL( exec.empty(), false );
+  BOOST_CHECK_EQUAL( exec.size(), 1 );
+
+  exec.load( "/bin/cat" );
+  BOOST_CHECK_EQUAL( exec.size(), 2 );
+
+  exec.send( PluginFrame( "ACK" ) );
+  BOOST_CHECK_EQUAL( exec.size(), 2 );
+
+  exec.send( PluginFrame( "ERROR" ) );
+  BOOST_CHECK_EQUAL( exec.size(), 0 ); // deleted failing scripts
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/CMakeLists.txt 
new/libzypp-15.21.5/zypp/CMakeLists.txt
--- old/libzypp-15.21.4/zypp/CMakeLists.txt     2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.21.5/zypp/CMakeLists.txt     2016-03-18 13:28:44.000000000 
+0100
@@ -27,6 +27,7 @@
   PluginFrameException.cc
   PluginScript.cc
   PluginScriptException.cc
+  PluginExecutor.cc
   Fetcher.cc
   FileChecker.cc
   Glob.cc
@@ -116,6 +117,7 @@
   PluginFrameException.h
   PluginScript.h
   PluginScriptException.h
+  PluginExecutor.h
   Fetcher.h
   FileChecker.h
   Glob.h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/Patch.cc 
new/libzypp-15.21.5/zypp/Patch.cc
--- old/libzypp-15.21.4/zypp/Patch.cc   2016-02-11 17:22:14.000000000 +0100
+++ new/libzypp-15.21.5/zypp/Patch.cc   2016-03-14 16:28:44.000000000 +0100
@@ -44,7 +44,7 @@
   ///////////////////////////////////////////////////////////////////
 
   std::string Patch::category() const
-  { return lookupStrAttribute( sat::SolvAttr::patchcategory ); }
+  { return str::toLower(lookupStrAttribute( sat::SolvAttr::patchcategory )); }
 
   Patch::Category Patch::categoryEnum() const
   { return categoryEnum( category() ); }
@@ -132,7 +132,7 @@
   ///////////////////////////////////////////////////////////////////
 
   std::string Patch::severity() const
-  { return lookupStrAttribute( sat::SolvAttr::severity ); }
+  { return str::toLower(lookupStrAttribute( sat::SolvAttr::severity )); }
 
   Patch::SeverityFlag Patch::severityFlag() const
   { return severityFlag( severity() ); }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/PluginExecutor.cc 
new/libzypp-15.21.5/zypp/PluginExecutor.cc
--- old/libzypp-15.21.4/zypp/PluginExecutor.cc  1970-01-01 01:00:00.000000000 
+0100
+++ new/libzypp-15.21.5/zypp/PluginExecutor.cc  2016-03-18 15:28:44.000000000 
+0100
@@ -0,0 +1,180 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/PluginExecutor.cc
+ */
+#include <iostream>
+#include "zypp/base/LogTools.h"
+#include "zypp/base/NonCopyable.h"
+
+#include "zypp/ZConfig.h"
+#include "zypp/PathInfo.h"
+#include "zypp/PluginExecutor.h"
+
+using std::endl;
+
+#undef  ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  /// \class PluginExecutor::Impl
+  /// \brief PluginExecutor implementation.
+  ///////////////////////////////////////////////////////////////////
+  class PluginExecutor::Impl : private base::NonCopyable
+  {
+  public:
+    Impl()
+    {}
+
+    ~Impl()
+    {
+      if ( ! empty() )
+       send( PluginFrame( "PLUGINEND" ) );
+      // ~PluginScript will disconnect all remaining plugins!
+    }
+
+    bool empty() const
+    { return _scripts.empty(); }
+
+    size_t size() const
+    { return _scripts.size(); }
+
+    void load( const Pathname & path_r )
+    {
+      PathInfo pi( path_r );
+      DBG << "+++++++++++++++ load " << pi << endl;
+      if ( pi.isDir() )
+      {
+       std::list<Pathname> entries;
+       if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
+       {
+         WAR << "Plugin dir is not readable: " << pi << endl;
+         return;
+       }
+       for_( it, entries.begin(), entries.end() )
+       {
+         PathInfo pii( *it );
+         if ( pii.isFile() && pii.userMayRX() )
+           doLoad( pii );
+       }
+      }
+      else if ( pi.isFile() )
+      {
+       if ( pi.userMayRX() )
+         doLoad( pi );
+       else
+         WAR << "Plugin file is not executable: " << pi << endl;
+      }
+      else
+      {
+       WAR << "Plugin path is neither dir nor file: " << pi << endl;
+      }
+      DBG << "--------------- load " << pi << endl;
+    }
+
+    void send( const PluginFrame & frame_r )
+    {
+      DBG << "+++++++++++++++ send " << frame_r << endl;
+      for ( auto it = _scripts.begin(); it != _scripts.end(); )
+      {
+       doSend( *it, frame_r );
+       if ( it->isOpen() )
+         ++it;
+       else
+         it = _scripts.erase( it );
+      }
+      DBG << "--------------- send " << frame_r << endl;
+    }
+
+    const std::list<PluginScript> scripts() const
+    { return _scripts; }
+
+  private:
+    /** 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() );
+
+       doSend( plugin, frame );        // closes on error
+       if ( plugin.isOpen() )
+         _scripts.push_back( plugin );
+      }
+      catch( const zypp::Exception & e )
+      {
+       WAR << "Failed to load plugin " << pi_r << endl;
+      }
+    }
+
+    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);
+       WAR << e.asUserHistory() << endl;
+      }
+
+      // Allow using "/bin/cat" as reflector-script for testing
+      if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() || ( 
script_r.script() == "/bin/cat" && frame_r.command() != "ERROR" ) ) )
+      {
+       WAR << "Bad plugin response from " << script_r << ": " << ret << endl;
+       WAR << "(Expected " << PluginFrame::ackCommand() << " or " << 
PluginFrame::enomethodCommand() << ")" << endl;
+       script_r.close();
+      }
+
+      return ret;
+    }
+  private:
+    std::list<PluginScript> _scripts;
+  };
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //   CLASS NAME : PluginExecutor
+  //
+  ///////////////////////////////////////////////////////////////////
+
+  PluginExecutor::PluginExecutor()
+    : _pimpl( new Impl() )
+  {}
+
+  PluginExecutor::~PluginExecutor()
+  {}
+
+  bool PluginExecutor::empty() const
+  { return _pimpl->empty(); }
+
+  size_t PluginExecutor::size() const
+  { return _pimpl->size(); }
+
+  void PluginExecutor::load( const Pathname & path_r )
+  { _pimpl->load( path_r ); }
+
+  void PluginExecutor::send( const PluginFrame & frame_r )
+  { _pimpl->send( frame_r ); }
+
+  std::ostream & operator<<( std::ostream & str, const PluginExecutor & obj )
+  { return str << obj._pimpl->scripts(); }
+
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/PluginExecutor.h 
new/libzypp-15.21.5/zypp/PluginExecutor.h
--- old/libzypp-15.21.4/zypp/PluginExecutor.h   1970-01-01 01:00:00.000000000 
+0100
+++ new/libzypp-15.21.5/zypp/PluginExecutor.h   2016-03-18 15:28:44.000000000 
+0100
@@ -0,0 +1,97 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/PluginExecutor.h
+ */
+#ifndef ZYPP_PLUGINEXECUTOR_H
+#define ZYPP_PLUGINEXECUTOR_H
+
+#include <iosfwd>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/PluginScript.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  /// \class PluginExecutor
+  /// \brief Parallel execution of stateful PluginScripts
+  ///
+  /// Sent PluginFrames are distributed to all open PluginScripts and
+  /// need to be receipted by sending back either \c ACK or \c _ENOMETHOD
+  /// command.
+  ///
+  /// All PluginScripts receive an initial \c PLUGINBEGIN frame, containing
+  /// a \c userdata header if \ref ZConfig::userData are defined.
+  /// \see also zypper '--userdata' option
+  ///
+  /// A final \c PLUGINEND frame is sent and open scripts are closed, when the
+  /// executors last reference goes out of scope. Failing PluginScripts are
+  /// closed immediately.
+  ///
+  /// \see PluginScript
+  /// \ingroup g_RAII
+  ///////////////////////////////////////////////////////////////////
+  class PluginExecutor
+  {
+    friend std::ostream & operator<<( std::ostream & str, const PluginExecutor 
& obj );
+    friend bool operator==( const PluginExecutor & lhs, const PluginExecutor & 
rhs );
+
+    public:
+      /** Default ctor: Empty plugin list */
+      PluginExecutor();
+
+      /** Dtor: Send \c PLUGINEND and close all plugins */
+      ~PluginExecutor();
+
+    public:
+      /**  Validate object in a boolean context: There are plugins waiting for 
input */
+      explicit operator bool() const
+      { return !empty(); }
+
+      /** Whether no plugins are waiting */
+      bool empty() const;
+
+      /** Number of open plugins */
+      size_t size() const;
+
+    public:
+      /** Find and launch plugins sending \c PLUGINBEGIN.
+       *
+       * If \a path_r is a directory all executable files within are
+       * expected to be plugins. Otherwise \a path_r must point to an
+       * executable plugin.
+       */
+      void load( const Pathname & path_r );
+
+      /** Send \ref PluginFrame to all open plugins.
+       * Failed plugins are removed from the execution list.
+       */
+      void send( const PluginFrame & frame_r );
+
+    public:
+      class Impl;              ///< Implementation class.
+    private:
+      RW_pointer<Impl> _pimpl; ///< Pointer to implementation.
+  };
+
+  /** \relates PluginExecutor Stream output */
+  std::ostream & operator<<( std::ostream & str, const PluginExecutor & obj );
+
+  /** \relates PluginExecutor Comparison based on reference. */
+  inline bool operator==( const PluginExecutor & lhs, const PluginExecutor & 
rhs )
+  { return ( lhs._pimpl == rhs._pimpl ); }
+
+  /** \relates PluginExecutor Comparison based on reference. */
+  inline bool operator!=( const PluginExecutor & lhs, const PluginExecutor & 
rhs )
+  { return( ! operator==( lhs, rhs ) ); }
+
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_PLUGINEXECUTOR_H
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/PluginFrame.h 
new/libzypp-15.21.5/zypp/PluginFrame.h
--- old/libzypp-15.21.4/zypp/PluginFrame.h      2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.21.5/zypp/PluginFrame.h      2016-03-18 15:28:44.000000000 
+0100
@@ -89,9 +89,9 @@
       /** Whether this is an empty frame. */
       bool empty() const;
 
-      /** Evaluate in a boolean context (empty frame) */
+      /** Evaluate in a boolean context (not an empty frame) */
       explicit operator bool() const
-      { return empty(); }
+      { return !empty(); }
 
     public:
       /** Return the frame command. */
@@ -174,7 +174,7 @@
       bool keyEmpty( const std::string & key_r ) const
       { return headerList().find( key_r ) == headerEnd(); }
 
-      /** Return number of header entires for \c key_r. */
+      /** Return number of header entries for \c key_r. */
       bool keySize( const std::string & key_r ) const
       { return headerList().count( key_r ); }
 
@@ -201,7 +201,7 @@
       /** Not throwing version returing one of the matching header values or 
\c default_r string. */
       const std::string & getHeaderNT( const std::string & key_r, const 
std::string & default_r = std::string() ) const;
 
-      /** Set header for \c key_r removing all other occurences of \c key_r.
+      /** Set header for \c key_r removing all other occurrences of \c key_r.
        * \throw PluginFrameException If key contains illegal chars (\c NL or 
\c :)
        * \throw PluginFrameException If value contains illegal chars (\c NL)
        */
@@ -256,9 +256,9 @@
   /** \relates PluginFrame Stream output for logging */
   std::ostream & operator<<( std::ostream & str, const PluginFrame & obj );
 
-  /** \relates PluginFrame Stream output sending all data */
+  /** \relates PluginFrame Stream output writing all data for logging (no 
throw) */
   inline std::ostream & dumpOn( std::ostream & str, const PluginFrame & obj )
-  { return PluginFrame::writeTo( str, obj ); }
+  { if ( str ) try { PluginFrame::writeTo( str, obj ); } catch(...){}; return 
str; }
 
   /** \relates PluginFrame Construct from stream. */
   inline std::istream & operator>>( std::istream & str, PluginFrame & obj )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/PluginScript.h 
new/libzypp-15.21.5/zypp/PluginScript.h
--- old/libzypp-15.21.4/zypp/PluginScript.h     2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.21.5/zypp/PluginScript.h     2016-03-18 13:28:44.000000000 
+0100
@@ -27,7 +27,7 @@
 { /////////////////////////////////////////////////////////////////
 
   /**
-   * \brief Interface to pluigin scripts using a \c Stomp inspired 
communication protocol.
+   * \brief Interface to plugin scripts using a \c Stomp inspired 
communication protocol.
    *
    * \note \ref PluginScript is copyable and assignable, but the connection is 
shared
    * among multiple copies. It gets automatically closed if the last copy goes 
out of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/base/Iterable.h 
new/libzypp-15.21.5/zypp/base/Iterable.h
--- old/libzypp-15.21.4/zypp/base/Iterable.h    2016-02-11 17:22:14.000000000 
+0100
+++ new/libzypp-15.21.5/zypp/base/Iterable.h    2016-03-14 16:28:44.000000000 
+0100
@@ -54,6 +54,12 @@
     , _end( std::move(end_r) )
     {}
 
+    /** Ctor taking the iterator pair */
+    Iterable( std::pair<iterator_type,iterator_type> range_r )
+    : _begin( std::move(range_r.first) )
+    , _end( std::move(range_r.second) )
+    {}
+
     iterator_type begin() const
     { return _begin; }
 
@@ -82,6 +88,10 @@
   Iterable<TIterator> makeIterable( TIterator && begin_r, TIterator && end_r )
   { return Iterable<TIterator>( std::forward<TIterator>(begin_r), 
std::forward<TIterator>(end_r) ); }
 
+  /** \relates Iterable convenient construction. */
+  template <class TIterator>
+  Iterable<TIterator> makeIterable( std::pair<TIterator,TIterator> && range_r )
+  { return Iterable<TIterator>( 
std::forward<std::pair<TIterator,TIterator>>(range_r) ); }
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////
 #endif // ZYPP_BASE_ITERABLE_H
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libzypp-15.21.4/zypp/target/TargetImpl.cc 
new/libzypp-15.21.5/zypp/target/TargetImpl.cc
--- old/libzypp-15.21.4/zypp/target/TargetImpl.cc       2016-02-11 
17:22:14.000000000 +0100
+++ new/libzypp-15.21.5/zypp/target/TargetImpl.cc       2016-03-18 
13:28:44.000000000 +0100
@@ -54,7 +54,7 @@
 #include "zypp/sat/detail/PoolImpl.h"
 #include "zypp/sat/Transaction.h"
 
-#include "zypp/PluginScript.h"
+#include "zypp/PluginExecutor.h"
 
 using namespace std;
 
@@ -231,149 +231,6 @@
     } // namespace
     ///////////////////////////////////////////////////////////////////
 
-    /** Helper for commit plugin execution.
-     * \ingroup g_RAII
-     */
-    class CommitPlugins : private base::NonCopyable
-    {
-      public:
-       /** Default ctor: Empty plugin list */
-       CommitPlugins()
-       {}
-
-       /** Dtor: Send PLUGINEND message and close plugins. */
-       ~CommitPlugins()
-       {
-         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(); )
-         {
-           doSend( *it, frame_r );
-           if ( it->isOpen() )
-             ++it;
-           else
-             it = _scripts.erase( it );
-         }
-         DBG << "--------------- send " << frame_r << endl;
-       }
-
-       /** Find and launch plugins sending PLUGINSTART message.
-        *
-        * If \a path_r is a directory all executable files whithin are
-        * expected to be plugins. Otherwise \a path_r must point to an
-        * executable plugin.
-        */
-       void load( const Pathname & path_r )
-       {
-         PathInfo pi( path_r );
-         DBG << "+++++++++++++++ load " << pi << endl;
-         if ( pi.isDir() )
-         {
-           std::list<Pathname> entries;
-           if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
-           {
-             WAR << "Plugin dir is not readable: " << pi << endl;
-             return;
-           }
-           for_( it, entries.begin(), entries.end() )
-           {
-             PathInfo pii( *it );
-             if ( pii.isFile() && pii.userMayRX() )
-               doLoad( pii );
-           }
-         }
-         else if ( pi.isFile() )
-         {
-           if ( pi.userMayRX() )
-             doLoad( pi );
-           else
-             WAR << "Plugin file is not executable: " << pi << endl;
-         }
-         else
-         {
-           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() );
-
-           doSend( plugin, frame );    // closes on error
-           if ( plugin.isOpen() )
-             _scripts.push_back( plugin );
-         }
-         catch( const zypp::Exception & e )
-         {
-            WAR << "Failed to load plugin " << pi_r << endl;
-         }
-       }
-
-      private:
-       std::list<PluginScript> _scripts;
-    };
-
-    void testCommitPlugins( const Pathname & path_r ) // for testing only
-    {
-      USR << "+++++" << endl;
-      {
-       CommitPlugins pl;
-       pl.load( path_r );
-       USR << "=====" << endl;
-      }
-      USR << "-----" << endl;
-    }
-
     ///////////////////////////////////////////////////////////////////
     namespace
     {
@@ -1097,27 +954,13 @@
         guard.resetDispose();
        sat::updateSolvFileIndex( rpmsolv );    // content digest for zypper 
bash completion
 
-       // Finally send notification to plugins
-       // NOTE: quick hack looking for spacewalk plugin only
+       // system-hook: Finally send notification to plugins
+       if ( root() == "/" )
        {
-         Pathname script( Pathname::assertprefix( _root, 
ZConfig::instance().pluginsPath()/"system/spacewalk" ) );
-         if ( PathInfo( script ).isX() )
-           try {
-             PluginScript spacewalk( script );
-             spacewalk.open();
-
-             PluginFrame notify( "PACKAGESETCHANGED" );
-             spacewalk.send( notify );
-
-             PluginFrame ret( spacewalk.receive() );
-             MIL << ret << endl;
-             if ( ret.command() == "ERROR" )
-               ret.writeTo( WAR ) << endl;
-           }
-           catch ( const Exception & excpt )
-           {
-             WAR << excpt.asUserHistory() << endl;
-           }
+         PluginExecutor plugins;
+         plugins.load( ZConfig::instance().pluginsPath()/"system" );
+         if ( plugins )
+           plugins.send( PluginFrame( "PACKAGESETCHANGED" ) );
        }
       }
       else
@@ -1298,13 +1141,12 @@
       ///////////////////////////////////////////////////////////////////
       // Prepare execution of commit plugins:
       ///////////////////////////////////////////////////////////////////
-      CommitPlugins commitPlugins;
+      PluginExecutor commitPlugins;
       if ( root() == "/" && ! policy_r.dryRun() )
       {
-       Pathname plugindir( Pathname::assertprefix( _root, 
ZConfig::instance().pluginsPath()/"commit" ) );
-       commitPlugins.load( plugindir );
+       commitPlugins.load( ZConfig::instance().pluginsPath()/"commit" );
       }
-      if ( ! commitPlugins.empty() )
+      if ( commitPlugins )
        commitPlugins.send( transactionPluginFrame( "COMMITBEGIN", steps ) );
 
       ///////////////////////////////////////////////////////////////////
@@ -1495,7 +1337,7 @@
       ///////////////////////////////////////////////////////////////////
       // Send result to commit plugins:
       ///////////////////////////////////////////////////////////////////
-      if ( ! commitPlugins.empty() )
+      if ( commitPlugins )
        commitPlugins.send( transactionPluginFrame( "COMMITEND", steps ) );
 
       ///////////////////////////////////////////////////////////////////


Reply via email to