3014af95a0eaab06f82469f966785b9ca244a98d
[platform/upstream/libzypp.git] / zypp / target / RpmPostTransCollector.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/target/RpmPostTransCollector.cc
10  */
11 #include <iostream>
12 #include <fstream>
13 #include "zypp/base/LogTools.h"
14 #include "zypp/base/NonCopyable.h"
15 #include "zypp/target/RpmPostTransCollector.h"
16
17 #include "zypp/TmpPath.h"
18 #include "zypp/PathInfo.h"
19 #include "zypp/HistoryLog.h"
20 #include "zypp/ZYppCallbacks.h"
21 #include "zypp/ExternalProgram.h"
22 #include "zypp/target/rpm/RpmHeader.h"
23 #include "zypp/ZConfig.h"
24
25 using std::endl;
26 #undef ZYPP_BASE_LOGGER_LOGGROUP
27 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans"
28
29 ///////////////////////////////////////////////////////////////////
30 namespace zypp
31 {
32   ///////////////////////////////////////////////////////////////////
33   namespace target
34   {
35
36     ///////////////////////////////////////////////////////////////////
37     /// \class RpmPostTransCollector::Impl
38     /// \brief RpmPostTransCollector implementation.
39     ///////////////////////////////////////////////////////////////////
40     class RpmPostTransCollector::Impl : private base::NonCopyable
41     {
42       friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
43       friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
44       public:
45         Impl( const Pathname & root_r )
46         : _root( root_r )
47         {}
48
49         ~Impl()
50         { if ( !_scripts.empty() ) discardScripts(); }
51
52         /** Extract and remember a packages %posttrans script for later execution. */
53         bool collectScriptFromPackage( ManagedFile rpmPackage_r )
54         {
55           rpm::RpmHeader::constPtr pkg( rpm::RpmHeader::readPackage( rpmPackage_r, rpm::RpmHeader::NOVERIFY ) );
56
57           std::string prog( pkg->tag_posttransprog() );
58           if ( prog.empty() || prog == "<lua>" )        // by now leave lua to rpm
59             return false;
60
61           filesystem::TmpFile script( tmpDir(), rpmPackage_r->basename() );
62           filesystem::addmod( script.path(), 0500 );
63           script.autoCleanup( false );  // no autodelete; within a tmpdir
64           {
65             std::ofstream out( script.path().c_str() );
66             out << "#! " << pkg->tag_posttransprog() << endl
67                 << pkg->tag_posttrans() << endl;
68           }
69           _scripts.push_back( script.path().basename() );
70           MIL << "COLLECT posttrans: " << PathInfo( script.path() ) << endl;
71           //DBG << "PROG:  " << pkg->tag_posttransprog() << endl;
72           //DBG << "SCRPT: " << pkg->tag_posttrans() << endl;
73           return true;
74         }
75
76         /** Execute te remembered scripts. */
77         void executeScripts()
78         {
79           if ( _scripts.empty() )
80             return;
81
82           HistoryLog historylog;
83
84           Pathname noRootScriptDir( ZConfig::instance().update_scriptsPath() / tmpDir().basename() );
85
86           for ( auto && script : _scripts )
87           {
88             MIL << "EXECUTE posttrans: " << script << endl;
89             ExternalProgram prog( (noRootScriptDir/script).asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root );
90
91             str::Str collect;
92             for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
93             {
94               DBG << line;
95               collect << "    " << line;
96             }
97             int ret = prog.close();
98             const std::string & scriptmsg( collect );
99
100             if ( ret != 0 || ! scriptmsg.empty() )
101             {
102               const std::string & pkgident( script.substr( 0, script.size()-6 ) );      // strip tmp file suffix
103
104               if ( ! scriptmsg.empty() )
105               {
106                 str::Str msg;
107                 msg << "Output of " << pkgident << " %posttrans script:\n" << scriptmsg;
108                 historylog.comment( msg, true /*timestamp*/);
109                 JobReport::info( msg );
110               }
111
112               if ( ret != 0 )
113               {
114                 str::Str msg;
115                 msg << pkgident << " %posttrans script failed (returned " << ret << ")";
116                 WAR << msg << endl;
117                 historylog.comment( msg, true /*timestamp*/);
118                 JobReport::warning( msg );
119               }
120             }
121           }
122           _scripts.clear();
123         }
124
125         /** Discard all remembered scrips. */
126         void discardScripts()
127         {
128           if ( _scripts.empty() )
129             return;
130
131           HistoryLog historylog;
132
133           str::Str msg;
134           msg << "%posttrans scripts skipped while aborting:\n";
135           for ( auto && script : _scripts )
136           {
137             const std::string & pkgident( script.substr( 0, script.size()-6 ) );        // strip tmp file suffix
138             WAR << "UNEXECUTED posttrans: " << script << endl;
139             msg << "    " << pkgident << "\n";
140           }
141
142           historylog.comment( msg, true /*timestamp*/);
143           JobReport::warning( msg );
144
145           _scripts.clear();
146         }
147
148       private:
149         /** Lazy create tmpdir on demand. */
150         Pathname tmpDir()
151         {
152           if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / ZConfig::instance().update_scriptsPath(), "posttrans" ) );
153           DBG << _ptrTmpdir->path() << endl;
154           return _ptrTmpdir->path();
155         }
156
157       private:
158         Pathname _root;
159         std::list<std::string> _scripts;
160         boost::scoped_ptr<filesystem::TmpDir> _ptrTmpdir;
161     };
162
163     /** \relates RpmPostTransCollector::Impl Stream output */
164     inline std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector::Impl & obj )
165     { return str << "RpmPostTransCollector::Impl"; }
166
167     /** \relates RpmPostTransCollector::Impl Verbose stream output */
168     inline std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector::Impl & obj )
169     { return str << obj; }
170
171     ///////////////////////////////////////////////////////////////////
172     //
173     //  CLASS NAME : RpmPostTransCollector
174     //
175     ///////////////////////////////////////////////////////////////////
176
177     RpmPostTransCollector::RpmPostTransCollector( const Pathname & root_r )
178       : _pimpl( new Impl( root_r ) )
179     {}
180
181     RpmPostTransCollector::~RpmPostTransCollector()
182     {}
183
184     bool RpmPostTransCollector::collectScriptFromPackage( ManagedFile rpmPackage_r )
185     { return _pimpl->collectScriptFromPackage( rpmPackage_r ); }
186
187     void RpmPostTransCollector::executeScripts()
188     { return _pimpl->executeScripts(); }
189
190     void RpmPostTransCollector::discardScripts()
191     { return _pimpl->discardScripts(); }
192
193     std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj )
194     { return str << *obj._pimpl; }
195
196     std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj )
197     { return dumpOn( str, *obj._pimpl ); }
198
199   } // namespace target
200   ///////////////////////////////////////////////////////////////////
201 } // namespace zypp
202 ///////////////////////////////////////////////////////////////////