libzypp  17.14.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"
24 #include "zypp/ZConfig.h"
25 #include "zypp/ZYppCallbacks.h"
26 
27 using std::endl;
28 #undef ZYPP_BASE_LOGGER_LOGGROUP
29 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::posttrans"
30 
32 namespace zypp
33 {
35  namespace target
36  {
37 
43  {
44  friend std::ostream & operator<<( std::ostream & str, const Impl & obj );
45  friend std::ostream & dumpOn( std::ostream & str, const Impl & obj );
46  public:
47  Impl( const Pathname & root_r )
48  : _root( root_r )
49  {}
50 
52  { if ( !_scripts.empty() ) discardScripts(); }
53 
56  {
58  if ( ! pkg )
59  {
60  WAR << "Unexpectedly this is no package: " << rpmPackage_r << endl;
61  return false;
62  }
63 
64  std::string prog( pkg->tag_posttransprog() );
65  if ( prog.empty() || prog == "<lua>" ) // by now leave lua to rpm
66  return false;
67 
68  filesystem::TmpFile script( tmpDir(), rpmPackage_r->basename() );
69  filesystem::addmod( script.path(), 0500 );
70  script.autoCleanup( false ); // no autodelete; within a tmpdir
71  {
72  std::ofstream out( script.path().c_str() );
73  out << "#! " << pkg->tag_posttransprog() << endl
74  << pkg->tag_posttrans() << endl;
75  }
76  _scripts.push_back( script.path().basename() );
77  MIL << "COLLECT posttrans: " << PathInfo( script.path() ) << endl;
78  //DBG << "PROG: " << pkg->tag_posttransprog() << endl;
79  //DBG << "SCRPT: " << pkg->tag_posttrans() << endl;
80  return true;
81  }
82 
85  {
86  if ( _scripts.empty() )
87  return true;
88 
89  HistoryLog historylog;
90 
91  Pathname noRootScriptDir( ZConfig::instance().update_scriptsPath() / tmpDir().basename() );
92 
93  ProgressData scriptProgress( static_cast<ProgressData::value_type>(_scripts.size()) );
95  scriptProgress.sendTo( ProgressReportAdaptor( ProgressData::ReceiverFnc(), report ) );
96 
97  bool firstScript = true;
98  while ( ! _scripts.empty() )
99  {
100  const std::string & script = _scripts.front();
101  const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix
102 
103  scriptProgress.name( str::Format(_("Executing %%posttrans script '%1%'")) % pkgident );
104 
105  bool canContinue = true;
106  if (firstScript) {
107  firstScript = false;
108  canContinue = scriptProgress.toMin();
109  } else {
110  canContinue = scriptProgress.incr();
111  }
112 
113  if (!canContinue) {
114  str::Str msg;
115  msg << "Execution of %posttrans scripts cancelled";
116  WAR << msg << endl;
117  historylog.comment( msg, true /*timestamp*/);
118  JobReport::warning( msg );
119  return false;
120  }
121 
122  MIL << "EXECUTE posttrans: " << script << endl;
123  ExternalProgram prog( (noRootScriptDir/script).asString() + " 0", ExternalProgram::Stderr_To_Stdout, false, -1, true, _root );
124 
125  str::Str collect;
126  for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
127  {
128  DBG << line;
129  collect << " " << line;
130  }
131 
132  //script was executed, remove it from the list
133  _scripts.pop_front();
134 
135  int ret = prog.close();
136  const std::string & scriptmsg( collect );
137 
138  if ( ret != 0 || ! scriptmsg.empty() )
139  {
140  if ( ! scriptmsg.empty() )
141  {
142  str::Str msg;
143  msg << "Output of " << pkgident << " %posttrans script:\n" << scriptmsg;
144  historylog.comment( msg, true /*timestamp*/);
145  JobReport::UserData userData( "cmdout", "%posttrans" );
146  JobReport::info( msg, userData );
147  }
148 
149  if ( ret != 0 )
150  {
151  str::Str msg;
152  msg << pkgident << " %posttrans script failed (returned " << ret << ")";
153  WAR << msg << endl;
154  historylog.comment( msg, true /*timestamp*/);
155  JobReport::warning( msg );
156  }
157  }
158  }
159 
160  //show a final message
161  scriptProgress.name( _("Executing %posttrans scripts") );
162  scriptProgress.toMax();
163  _scripts.clear();
164  return true;
165  }
166 
169  {
170  if ( _scripts.empty() )
171  return;
172 
173  HistoryLog historylog;
174 
175  str::Str msg;
176  msg << "%posttrans scripts skipped while aborting:\n";
177  for ( const auto & script : _scripts )
178  {
179  const std::string & pkgident( script.substr( 0, script.size()-6 ) ); // strip tmp file suffix
180  WAR << "UNEXECUTED posttrans: " << script << endl;
181  msg << " " << pkgident << "\n";
182  }
183 
184  historylog.comment( msg, true /*timestamp*/);
185  JobReport::warning( msg );
186 
187  _scripts.clear();
188  }
189 
190 
191  private:
193  Pathname tmpDir()
194  {
195  if ( !_ptrTmpdir ) _ptrTmpdir.reset( new filesystem::TmpDir( _root / ZConfig::instance().update_scriptsPath(), "posttrans" ) );
196  DBG << _ptrTmpdir->path() << endl;
197  return _ptrTmpdir->path();
198  }
199 
200  private:
201  Pathname _root;
202  std::list<std::string> _scripts;
203  boost::scoped_ptr<filesystem::TmpDir> _ptrTmpdir;
204  };
205 
207  inline std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector::Impl & obj )
208  { return str << "RpmPostTransCollector::Impl"; }
209 
211  inline std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector::Impl & obj )
212  { return str << obj; }
213 
215  //
216  // CLASS NAME : RpmPostTransCollector
217  //
219 
221  : _pimpl( new Impl( root_r ) )
222  {}
223 
225  {}
226 
228  { return _pimpl->collectScriptFromPackage( rpmPackage_r ); }
229 
231  { return _pimpl->executeScripts(); }
232 
234  { return _pimpl->discardScripts(); }
235 
236  std::ostream & operator<<( std::ostream & str, const RpmPostTransCollector & obj )
237  { return str << *obj._pimpl; }
238 
239  std::ostream & dumpOn( std::ostream & str, const RpmPostTransCollector & obj )
240  { return dumpOn( str, *obj._pimpl ); }
241 
242  } // namespace target
244 } // namespace zypp