libzypp  17.31.0
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 
28 using std::endl;
29 #undef ZYPP_BASE_LOGGER_LOGGROUP
30 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans"
31 
33 namespace 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
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:122
#define MIL
Definition: Logger.h:96
intrusive_ptr< const RpmHeader > constPtr
Definition: RpmHeader.h:65
JobReport convenience sending this instance of UserData with each message.
#define _(MSG)
Definition: Gettext.h:37
std::list< std::pair< std::string, std::string > > _scripts
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
Definition: progressdata.h:226
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:823
bool warning(const std::string &msg_r)
void discardScripts()
Discard all remembered scrips.
friend std::ostream & dumpOn(std::ostream &str, const Impl &obj)
String related utilities and Regular expression matching.
bool toMax()
Set counter value to current max value (unless no range).
Definition: progressdata.h:273
std::string receiveLine()
Read one line from the input stream.
std::ostream & dumpOn(std::ostream &str, const RpmPostTransCollector::Impl &obj)
Convenient building of std::string with boost::format.
Definition: String.h:252
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:127
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
Definition: progressdata.h:139
RW_pointer< Impl > _pimpl
Implementation class.
std::vector< std::string > Arguments
RpmPostTransCollector(const Pathname &root_r)
Default ctor.
Extract and remember posttrans scripts for later execution.
Subclass to retrieve database content.
Definition: librpmDb.h:335
bool info(const std::string &msg_r)
Pathname tmpDir()
Lazy create tmpdir on demand.
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1101
bool toMin()
Set counter value to current min value.
Definition: progressdata.h:269
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:177
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
bool collectScriptFromPackage(ManagedFile rpmPackage_r)
Extract and remember a packages posttrans script for later execution.
bool executeScripts()
Execute the remembered scripts.
bool findByName(const std::string &name_r)
Reset to iterate all packages with a certain name.
Definition: librpmDb.cc:776
#define WAR
Definition: Logger.h:97
RpmPostTransCollector implementation.
Maintain [min,max] and counter (value) for progress counting.
Definition: progressdata.h:130
std::ostream & operator<<(std::ostream &str, const CommitPackageCache &obj)
boost::scoped_ptr< filesystem::TmpDir > _ptrTmpdir
Writing the zypp history fileReference counted signleton for writhing the zypp history file...
Definition: HistoryLog.h:56
bool incr(value_type val_r=1)
Increment counter value (default by 1).
Definition: progressdata.h:261
static RpmHeader::constPtr readPackage(const Pathname &path, VERIFICATION verification=VERIFY)
Get an accessible packages data from disk.
Definition: RpmHeader.cc:210
std::string numstring(char n, int w=0)
Definition: String.h:289
std::ostream & dumpOn(std::ostream &str, const RpmPostTransCollector &obj)
int close()
Wait for the progamm to complete.
bool collectScriptFromPackage(ManagedFile rpmPackage_r)
Extract and remember a packages posttrans script for later execution.
void discardScripts()
Discard all remembered scrips.
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
void comment(const std::string &comment, bool timestamp=false)
Log a comment (even multiline).
Definition: HistoryLog.cc:188
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
bool executeScripts()
Execute the remembered scripts.
void name(const std::string &name_r)
Set counter name.
Definition: progressdata.h:222
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
friend std::ostream & operator<<(std::ostream &str, const Impl &obj)
UserDataJobReport _myJobReport
JobReport with ContentType "cmdout/%posttrans".
#define DBG
Definition: Logger.h:95
std::ostream & operator<<(std::ostream &str, const RpmPostTransCollector::Impl &obj)