libzypp 17.31.20
RpmPostTransCollector.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
11#include <iostream>
12#include <fstream>
13#include <zypp/base/LogTools.h>
14#include <zypp/base/NonCopyable.h>
15#include <zypp/base/Gettext.h>
17
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>
25#include <zypp/ZConfig.h>
26#include <zypp/ZYppCallbacks.h>
27
28using std::endl;
29#undef ZYPP_BASE_LOGGER_LOGGROUP
30#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans"
31
33namespace zypp
34{
36 namespace target
37 {
38
44 {
45 friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
46 friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
47 public:
48 Impl( const Pathname & root_r )
49 : _root( root_r )
50 , _myJobReport { "cmdout", "%posttrans" }
51 {}
52
54 { if ( !_scripts.empty() ) discardScripts(); }
55
58 {
60 if ( ! pkg )
61 {
62 WAR << "Unexpectedly this is no package: " << rpmPackage_r << endl;
63 return false;
64 }
65
66 std::string prog( pkg->tag_posttransprog() );
67 if ( prog.empty() || prog == "<lua>" ) // by now leave lua to rpm
68 return false;
69
70 filesystem::TmpFile script( tmpDir(), rpmPackage_r->basename() );
71 filesystem::addmod( script.path(), 0500 );
72 script.autoCleanup( false ); // no autodelete; within a tmpdir
73 {
74 std::ofstream out( script.path().c_str() );
75 out << "#! " << pkg->tag_posttransprog() << endl
76 << pkg->tag_posttrans() << endl;
77 }
78 _scripts.push_back( std::make_pair( script.path().basename(), pkg->tag_name() ) );
79 MIL << "COLLECT posttrans: '" << PathInfo( script.path() ) << "' for package: '" << pkg->tag_name() << "'" << endl;
80 //DBG << "PROG: " << pkg->tag_posttransprog() << endl;
81 //DBG << "SCRPT: " << pkg->tag_posttrans() << endl;
82 return true;
83 }
84
87 {
88 if ( _scripts.empty() )
89 return true;
90
91 HistoryLog historylog;
92
93 Pathname noRootScriptDir( ZConfig::instance().update_scriptsPath() / tmpDir().basename() );
94
96 ProgressData scriptProgress( static_cast<ProgressData::value_type>(_scripts.size()) );
97 scriptProgress.sendTo( ProgressReportAdaptor( ProgressData::ReceiverFnc(), report ) );
98 str::Format fmtScriptProgress { _("Executing %%posttrans script '%1%'") };
99
100 bool firstScript = true;
101 str::Format fmtScriptFailedMsg { "warning: %%posttrans(%1%) scriptlet failed, exit status %2%\n" }; // like rpm would report it (intentionally not translated and NL-terminated)
102 while ( ! _scripts.empty() )
103 {
104 const auto &scriptPair = _scripts.front();
105 const std::string & script = scriptPair.first;
106 const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix
107
108 scriptProgress.name( fmtScriptProgress % pkgident );
109
110 bool canContinue = true;
111 if (firstScript) {
112 firstScript = false;
113 canContinue = scriptProgress.toMin();
114 } else {
115 canContinue = scriptProgress.incr();
116 }
117
118 if (!canContinue) {
119 str::Str msg;
120 msg << "Execution of %posttrans scripts cancelled";
121 WAR << msg << endl;
122 historylog.comment( msg, true /*timestamp*/);
123 _myJobReport.warning( msg );
124 return false;
125 }
126
127 int npkgs = 0;
129 for ( it.findByName( scriptPair.second ); *it; ++it )
130 npkgs++;
131
132 MIL << "EXECUTE posttrans: " << script << " with argument: " << npkgs << endl;
134 "/bin/sh",
135 (noRootScriptDir/script).asString(),
136 str::numstring( npkgs )
137 };
138 ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout, false, -1, true, _root );
139
140 // For now we continue to collect the lines and write the history file at the end.
141 // But JobReport lines are now sent immediately as they occur.
142 str::Str collect;
143 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
144 {
145 DBG << line;
146 collect << line;
147 _myJobReport.info( line );
148 }
149
150 //script was executed, remove it from the list
151 _scripts.pop_front();
152
153 int ret = prog.close();
154 if ( ret != 0 )
155 {
156 const std::string & msg { fmtScriptFailedMsg % pkgident % ret };
157 WAR << msg;
158 collect << msg;
159 _myJobReport.info( msg ); // info!, as rpm would have reported it.
160 }
161
162 const std::string & scriptmsg( collect );
163 if ( ! scriptmsg.empty() )
164 {
165 str::Str msg;
166 msg << "Output of " << pkgident << " %posttrans script:\n" << scriptmsg;
167 historylog.comment( msg, true /*timestamp*/);
168 }
169 }
170
171 //show a final message
172 scriptProgress.name( _("Executing %posttrans scripts") );
173 scriptProgress.toMax();
174 _scripts.clear();
175 return true;
176 }
177
180 {
181 if ( _scripts.empty() )
182 return;
183
184 HistoryLog historylog;
185
186 str::Str msg;
187 msg << "%posttrans scripts skipped while aborting:\n";
188 for ( const auto & script : _scripts )
189 {
190 const std::string & pkgident( script.first.substr( 0, script.first.size()-6 ) ); // strip tmp file suffix
191 WAR << "UNEXECUTED posttrans: " << script.first << endl;
192 msg << " " << pkgident << "\n";
193 }
194
195 historylog.comment( msg, true /*timestamp*/);
196 _myJobReport.warning( msg );
197
198 _scripts.clear();
199 }
200
201
202 private:
205 {
206 if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / ZConfig::instance().update_scriptsPath(), "posttrans" ) );
207 DBG << _ptrTmpdir->path() << endl;
208 return _ptrTmpdir->path();
209 }
210
211 private:
213 std::list< std::pair< std::string, std::string > > _scripts;
214 boost::scoped_ptr<filesystem::TmpDir> _ptrTmpdir;
215
217 };
218
220 inline std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector::Impl & obj )
221 { return str << "RpmPostTransCollector::Impl"; }
222
224 inline std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector::Impl & obj )
225 { return str << obj; }
226
228 //
229 // CLASS NAME : RpmPostTransCollector
230 //
232
234 : _pimpl( new Impl( root_r ) )
235 {}
236
238 {}
239
241 { return _pimpl->collectScriptFromPackage( rpmPackage_r ); }
242
244 { return _pimpl->executeScripts(); }
245
247 { return _pimpl->discardScripts(); }
248
249 std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj )
250 { return str << *obj._pimpl; }
251
252 std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj )
253 { return dumpOn( str, *obj._pimpl ); }
254
255 } // namespace target
257} // namespace zypp
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
std::vector< std::string > Arguments
int close()
Wait for the progamm to complete.
Writing the zypp history file.
Definition: HistoryLog.h:57
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition: HistoryLog.cc:190
Maintain [min,max] and counter (value) for progress counting.
Definition: progressdata.h:132
long long value_type
Definition: progressdata.h:134
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
Definition: progressdata.h:229
bool toMax()
Set counter value to current max value (unless no range).
Definition: progressdata.h:276
void name(const std::string &name_r)
Set counter name.
Definition: progressdata.h:225
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
Definition: progressdata.h:140
bool incr(value_type val_r=1)
Increment counter value (default by 1).
Definition: progressdata.h:264
bool toMin()
Set counter value to current min value.
Definition: progressdata.h:272
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:922
std::string receiveLine()
Read one line from the input stream.
Wrapper class for stat/lstat.
Definition: PathInfo.h:221
const char * c_str() const
String representation.
Definition: Pathname.h:110
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:178
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:128
Pathname path() const
Definition: TmpPath.cc:146
bool autoCleanup() const
Whether path is valid and deleted when the last reference drops.
Definition: TmpPath.cc:163
RpmPostTransCollector implementation.
bool executeScripts()
Execute the remembered scripts.
UserDataJobReport _myJobReport
JobReport with ContentType "cmdout/%posttrans".
void discardScripts()
Discard all remembered scrips.
boost::scoped_ptr< filesystem::TmpDir > _ptrTmpdir
Pathname tmpDir()
Lazy create tmpdir on demand.
std::list< std::pair< std::string, std::string > > _scripts
friend std::ostream & operator<<(std::ostream &str, const Impl &obj)
bool collectScriptFromPackage(ManagedFile rpmPackage_r)
Extract and remember a packages posttrans script for later execution.
std::ostream & dumpOn(std::ostream &str, const RpmPostTransCollector::Impl &obj)
Verbose stream output.
std::ostream & operator<<(std::ostream &str, const RpmPostTransCollector::Impl &obj)
Stream output.
friend std::ostream & dumpOn(std::ostream &str, const Impl &obj)
Extract and remember posttrans scripts for later execution.
RpmPostTransCollector(const Pathname &root_r)
Default ctor.
RW_pointer< Impl > _pimpl
Implementation class.
bool collectScriptFromPackage(ManagedFile rpmPackage_r)
Extract and remember a packages posttrans script for later execution.
bool executeScripts()
Execute the remembered scripts.
void discardScripts()
Discard all remembered scrips.
static RpmHeader::constPtr readPackage(const Pathname &path, VERIFICATION verification=VERIFY)
Get an accessible packages data from disk.
Definition: RpmHeader.cc:210
intrusive_ptr< const RpmHeader > constPtr
Definition: RpmHeader.h:65
Subclass to retrieve database content.
Definition: librpmDb.h:336
bool findByName(const std::string &name_r)
Reset to iterate all packages with a certain name.
Definition: librpmDb.cc:776
String related utilities and Regular expression matching.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1101
std::string numstring(char n, int w=0)
Definition: String.h:289
std::ostream & dumpOn(std::ostream &str, const RpmPostTransCollector &obj)
std::ostream & operator<<(std::ostream &str, const CommitPackageCache &obj)
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
JobReport convenience sending this instance of UserData with each message.
bool info(const std::string &msg_r)
bool warning(const std::string &msg_r)
Convenient building of std::string with boost::format.
Definition: String.h:253
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:212
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define WAR
Definition: Logger.h:97