1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/RpmPostTransCollector.cc
13 #include <zypp/base/LogTools.h>
14 #include <zypp/base/NonCopyable.h>
15 #include <zypp/base/Gettext.h>
16 #include <zypp/target/RpmPostTransCollector.h>
18 #include <zypp/TmpPath.h>
19 #include <zypp/PathInfo.h>
20 #include <zypp/HistoryLog.h>
21 #include <zypp/ZYppCallbacks.h>
22 #include <zypp/ExternalProgram.h>
23 #include <zypp/target/rpm/RpmHeader.h>
24 #include <zypp/target/rpm/librpmDb.h>
25 #include <zypp/ZConfig.h>
26 #include <zypp/ZYppCallbacks.h>
29 #undef ZYPP_BASE_LOGGER_LOGGROUP
30 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans"
32 ///////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////
39 ///////////////////////////////////////////////////////////////////
40 /// \class RpmPostTransCollector::Impl
41 /// \brief RpmPostTransCollector implementation.
42 ///////////////////////////////////////////////////////////////////
43 class RpmPostTransCollector::Impl : private base::NonCopyable
45 friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
46 friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
48 Impl( const Pathname & root_r )
53 { if ( !_scripts.empty() ) discardScripts(); }
55 /** Extract and remember a packages %posttrans script for later execution. */
56 bool collectScriptFromPackage( ManagedFile rpmPackage_r )
58 rpm::RpmHeader::constPtr pkg( rpm::RpmHeader::readPackage( rpmPackage_r, rpm::RpmHeader::NOVERIFY ) );
61 WAR << "Unexpectedly this is no package: " << rpmPackage_r << endl;
65 std::string prog( pkg->tag_posttransprog() );
66 if ( prog.empty() || prog == "<lua>" ) // by now leave lua to rpm
69 filesystem::TmpFile script( tmpDir(), rpmPackage_r->basename() );
70 filesystem::addmod( script.path(), 0500 );
71 script.autoCleanup( false ); // no autodelete; within a tmpdir
73 std::ofstream out( script.path().c_str() );
74 out << "#! " << pkg->tag_posttransprog() << endl
75 << pkg->tag_posttrans() << endl;
77 _scripts.push_back( std::make_pair( script.path().basename(), pkg->tag_name() ) );
78 MIL << "COLLECT posttrans: '" << PathInfo( script.path() ) << "' for package: '" << pkg->tag_name() << "'" << endl;
79 //DBG << "PROG: " << pkg->tag_posttransprog() << endl;
80 //DBG << "SCRPT: " << pkg->tag_posttrans() << endl;
84 /** Execute the remembered scripts. */
87 if ( _scripts.empty() )
90 HistoryLog historylog;
92 Pathname noRootScriptDir( ZConfig::instance().update_scriptsPath() / tmpDir().basename() );
94 ProgressData scriptProgress( static_cast<ProgressData::value_type>(_scripts.size()) );
95 callback::SendReport<ProgressReport> report;
96 scriptProgress.sendTo( ProgressReportAdaptor( ProgressData::ReceiverFnc(), report ) );
98 bool firstScript = true;
99 while ( ! _scripts.empty() )
101 const auto &scriptPair = _scripts.front();
102 const std::string & script = scriptPair.first;
103 const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix
105 scriptProgress.name( str::Format(_("Executing %%posttrans script '%1%'")) % pkgident );
107 bool canContinue = true;
110 canContinue = scriptProgress.toMin();
112 canContinue = scriptProgress.incr();
117 msg << "Execution of %posttrans scripts cancelled";
119 historylog.comment( msg, true /*timestamp*/);
120 JobReport::warning( msg );
125 rpm::librpmDb::db_const_iterator it;
126 for ( it.findByName( scriptPair.second ); *it; ++it )
129 MIL << "EXECUTE posttrans: " << script << " with argument: " << npkgs << endl;
130 ExternalProgram prog( (noRootScriptDir/script).asString() + " " +str::numstring( npkgs ), ExternalProgram::Stderr_To_Stdout, false, -1, true, _root );
133 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
136 collect << " " << line;
139 //script was executed, remove it from the list
140 _scripts.pop_front();
142 int ret = prog.close();
143 const std::string & scriptmsg( collect );
145 if ( ret != 0 || ! scriptmsg.empty() )
147 if ( ! scriptmsg.empty() )
150 msg << "Output of " << pkgident << " %posttrans script:\n" << scriptmsg;
151 historylog.comment( msg, true /*timestamp*/);
152 JobReport::UserData userData( "cmdout", "%posttrans" );
153 JobReport::info( msg, userData );
159 msg << pkgident << " %posttrans script failed (returned " << ret << ")";
161 historylog.comment( msg, true /*timestamp*/);
162 JobReport::warning( msg );
167 //show a final message
168 scriptProgress.name( _("Executing %posttrans scripts") );
169 scriptProgress.toMax();
174 /** Discard all remembered scrips. */
175 void discardScripts()
177 if ( _scripts.empty() )
180 HistoryLog historylog;
183 msg << "%posttrans scripts skipped while aborting:\n";
184 for ( const auto & script : _scripts )
186 const std::string & pkgident( script.first.substr( 0, script.first.size()-6 ) ); // strip tmp file suffix
187 WAR << "UNEXECUTED posttrans: " << script.first << endl;
188 msg << " " << pkgident << "\n";
191 historylog.comment( msg, true /*timestamp*/);
192 JobReport::warning( msg );
199 /** Lazy create tmpdir on demand. */
202 if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / ZConfig::instance().update_scriptsPath(), "posttrans" ) );
203 DBG << _ptrTmpdir->path() << endl;
204 return _ptrTmpdir->path();
209 std::list< std::pair< std::string, std::string > > _scripts;
210 boost::scoped_ptr<filesystem::TmpDir> _ptrTmpdir;
213 /** \relates RpmPostTransCollector::Impl Stream output */
214 inline std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector::Impl & obj )
215 { return str << "RpmPostTransCollector::Impl"; }
217 /** \relates RpmPostTransCollector::Impl Verbose stream output */
218 inline std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector::Impl & obj )
219 { return str << obj; }
221 ///////////////////////////////////////////////////////////////////
223 // CLASS NAME : RpmPostTransCollector
225 ///////////////////////////////////////////////////////////////////
227 RpmPostTransCollector::RpmPostTransCollector( const Pathname & root_r )
228 : _pimpl( new Impl( root_r ) )
231 RpmPostTransCollector::~RpmPostTransCollector()
234 bool RpmPostTransCollector::collectScriptFromPackage( ManagedFile rpmPackage_r )
235 { return _pimpl->collectScriptFromPackage( rpmPackage_r ); }
237 bool RpmPostTransCollector::executeScripts()
238 { return _pimpl->executeScripts(); }
240 void RpmPostTransCollector::discardScripts()
241 { return _pimpl->discardScripts(); }
243 std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj )
244 { return str << *obj._pimpl; }
246 std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj )
247 { return dumpOn( str, *obj._pimpl ); }
249 } // namespace target
250 ///////////////////////////////////////////////////////////////////
252 ///////////////////////////////////////////////////////////////////