Commit helper to collect and execute %posttrans scripts.
authorMichael Andres <ma@suse.de>
Sat, 25 Jan 2014 16:06:43 +0000 (17:06 +0100)
committerMichael Andres <ma@suse.de>
Sat, 25 Jan 2014 16:06:43 +0000 (17:06 +0100)
zypp/CMakeLists.txt
zypp/target/RpmPostTransCollector.cc [new file with mode: 0644]
zypp/target/RpmPostTransCollector.h [new file with mode: 0644]

index 65348f2..74f4912 100644 (file)
@@ -575,6 +575,7 @@ INSTALL(  FILES
 
 
 SET( zypp_target_SRCS
+  target/RpmPostTransCollector.cc
   target/RequestedLocalesFile.cc
   target/SoftLocksFile.cc
   target/HardLocksFile.cc
@@ -585,9 +586,11 @@ SET( zypp_target_SRCS
   target/TargetException.cc
   target/TargetImpl.cc
   target/TargetImpl.commitFindFileConflicts.cc
+
 )
 
 SET( zypp_target_HEADERS
+  target/RpmPostTransCollector.h
   target/RequestedLocalesFile.h
   target/SoftLocksFile.h
   target/HardLocksFile.h
diff --git a/zypp/target/RpmPostTransCollector.cc b/zypp/target/RpmPostTransCollector.cc
new file mode 100644 (file)
index 0000000..6aa35ca
--- /dev/null
@@ -0,0 +1,166 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/target/RpmPostTransCollector.cc
+ */
+#include <iostream>
+#include <fstream>
+#include "zypp/base/LogTools.h"
+#include "zypp/base/NonCopyable.h"
+#include "zypp/target/RpmPostTransCollector.h"
+
+#include "zypp/TmpPath.h"
+#include "zypp/PathInfo.h"
+#include "zypp/ExternalProgram.h"
+#include "zypp/target/rpm/RpmHeader.h"
+
+
+using std::endl;
+#undef ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  namespace target
+  {
+
+    ///////////////////////////////////////////////////////////////////
+    /// \class RpmPostTransCollector::Impl
+    /// \brief RpmPostTransCollector implementation.
+    ///////////////////////////////////////////////////////////////////
+    class RpmPostTransCollector::Impl : private base::NonCopyable
+    {
+      friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
+      friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
+      public:
+       Impl( const Pathname & root_r )
+       : _root( root_r )
+       {}
+
+       ~Impl()
+       { if ( !_scripts.empty() ) discardScripts(); }
+
+       /** Extract and remember a packages %posttrans script for later execution. */
+       bool collectScriptFromPackage( ManagedFile rpmPackage_r )
+       {
+         rpm::RpmHeader::constPtr pkg( rpm::RpmHeader::readPackage( rpmPackage_r, rpm::RpmHeader::NOVERIFY ) );
+
+         std::string prog( pkg->tag_posttransprog() );
+         if ( prog.empty() || prog == "<lua>" )        // by now leave lua to rpm
+           return false;
+
+         filesystem::TmpFile script( tmpDir(), rpmPackage_r->basename() );
+         filesystem::addmod( script.path(), 0500 );
+         script.autoCleanup( false );  // no autodelete; within a tmpdir
+         {
+           std::ofstream out( script.path().c_str() );
+           out << "# " << pkg->tag_posttransprog() << endl
+               << pkg->tag_posttrans() << endl;
+         }
+         _scripts.push_back( script.path().basename() );
+         MIL << "COLLECT posttrans: " << PathInfo( script.path() ) << endl;
+         //DBG << "PROG:  " << pkg->tag_posttransprog() << endl;
+         //DBG << "SCRPT: " << pkg->tag_posttrans() << endl;
+         return true;
+       }
+
+       /** Execute te remembered scripts. */
+       void executeScripts()
+       {
+         if ( _scripts.empty() )
+           return;
+
+         Pathname noRootScriptDir( filesystem::TmpDir::defaultLocation() / tmpDir().basename() );
+
+         for ( auto && script : _scripts )
+         {
+           MIL << "EXECUTE posttrans: " << script << endl;
+            ExternalProgram prog( (noRootScriptDir/script).asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root );
+           for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
+           {
+             DBG << line;
+           }
+           int ret = prog.close();
+           if ( ret != 0 )
+           {
+             ERR << "FAILED posttrans: (" << ret << ") " << script << endl;
+             // HistoryLog()
+             // continue on error?
+           }
+         }
+         _scripts.clear();
+       }
+
+       /** Discard all remembered scrips. */
+       void discardScripts()
+       {
+         if ( _scripts.empty() )
+           return;
+
+         for ( auto && script : _scripts )
+         { WAR << "UNEXECUTED posttrans: " << script << endl; }
+         _scripts.clear();
+       }
+
+      private:
+       /** Lazy create tmpdir on demand. */
+       Pathname tmpDir()
+       {
+         if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / filesystem::TmpDir::defaultLocation(), "posttrans" ) );
+         DBG << _ptrTmpdir->path() << endl;
+         return _ptrTmpdir->path();
+       }
+
+      private:
+       Pathname _root;
+       std::list<std::string> _scripts;
+       boost::scoped_ptr<filesystem::TmpDir> _ptrTmpdir;
+    };
+
+    /** \relates RpmPostTransCollector::Impl Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector::Impl & obj )
+    { return str << "RpmPostTransCollector::Impl"; }
+
+    /** \relates RpmPostTransCollector::Impl Verbose stream output */
+    inline std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector::Impl & obj )
+    { return str << obj; }
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : RpmPostTransCollector
+    //
+    ///////////////////////////////////////////////////////////////////
+
+    RpmPostTransCollector::RpmPostTransCollector( const Pathname & root_r )
+      : _pimpl( new Impl( root_r ) )
+    {}
+
+    RpmPostTransCollector::~RpmPostTransCollector()
+    {}
+
+    bool RpmPostTransCollector::collectScriptFromPackage( ManagedFile rpmPackage_r )
+    { return _pimpl->collectScriptFromPackage( rpmPackage_r ); }
+
+    void RpmPostTransCollector::executeScripts()
+    { return _pimpl->executeScripts(); }
+
+    void RpmPostTransCollector::discardScripts()
+    { return _pimpl->discardScripts(); }
+
+    std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj )
+    { return str << *obj._pimpl; }
+
+    std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj )
+    { return dumpOn( str, *obj._pimpl ); }
+
+  } // namespace target
+  ///////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff --git a/zypp/target/RpmPostTransCollector.h b/zypp/target/RpmPostTransCollector.h
new file mode 100644 (file)
index 0000000..771255c
--- /dev/null
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/target/RpmPostTransCollector.h
+ */
+#ifndef ZYPP_TARGET_RPMPOSTTRANSCOLLECTOR_H
+#define ZYPP_TARGET_RPMPOSTTRANSCOLLECTOR_H
+
+#include <iosfwd>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/ManagedFile.h"
+#include "zypp/Pathname.h"
+
+#undef  ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp:posttrans"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  namespace target
+  {
+    ///////////////////////////////////////////////////////////////////
+    /// \class RpmPostTransCollector
+    /// \brief Extract and remember %posttrans scripts for later execution
+    /// \todo Maybe embedd this into the TransactionSteps.
+    ///////////////////////////////////////////////////////////////////
+    class RpmPostTransCollector
+    {
+      friend std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj );
+      friend std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj );
+
+      public:
+        /** Default ctor */
+        RpmPostTransCollector( const Pathname & root_r );
+
+        /** Dtor */
+        ~RpmPostTransCollector();
+
+      public:
+       /** Extract and remember a packages %posttrans script for later execution.
+        * \return whether a script was collected.
+        */
+       bool collectScriptFromPackage( ManagedFile rpmPackage_r );
+
+       /** Execute te remembered scripts. */
+       void executeScripts();
+
+       /** Discard all remembered scrips. */
+       void discardScripts();
+
+      public:
+        class Impl;              ///< Implementation class.
+      private:
+        RW_pointer<Impl> _pimpl; ///< Pointer to implementation.
+    };
+
+    /** \relates RpmPostTransCollector Stream output */
+    std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj );
+
+    /** \relates RpmPostTransCollector Verbose stream output */
+    std::ostream & dumOn( std::ostream & str, const RpmPostTransCollector & obj );
+
+  } // namespace target
+  ///////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_TARGET_RPMPOSTTRANSCOLLECTOR_H