libzypp  17.8.0
PluginExecutor.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
11 #include <iostream>
12 #include "zypp/base/LogTools.h"
13 #include "zypp/base/NonCopyable.h"
14 
15 #include "zypp/ZConfig.h"
16 #include "zypp/PathInfo.h"
17 #include "zypp/PluginExecutor.h"
18 
19 using std::endl;
20 
21 #undef ZYPP_BASE_LOGGER_LOGGROUP
22 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
23 
25 namespace zypp
26 {
32  {
33  public:
34  Impl()
35  {}
36 
38  {
39  if ( ! empty() )
40  send( PluginFrame( "PLUGINEND" ) );
41  // ~PluginScript will disconnect all remaining plugins!
42  }
43 
44  bool empty() const
45  { return _scripts.empty(); }
46 
47  size_t size() const
48  { return _scripts.size(); }
49 
50  void load( const Pathname & path_r )
51  {
52  PathInfo pi( path_r );
53  DBG << "+++++++++++++++ load " << pi << endl;
54  if ( pi.isDir() )
55  {
56  std::list<Pathname> entries;
57  if ( filesystem::readdir( entries, pi.path(), false ) != 0 )
58  {
59  WAR << "Plugin dir is not readable: " << pi << endl;
60  return;
61  }
62  for_( it, entries.begin(), entries.end() )
63  {
64  PathInfo pii( *it );
65  if ( pii.isFile() && pii.userMayRX() )
66  doLoad( pii );
67  }
68  }
69  else if ( pi.isFile() )
70  {
71  if ( pi.userMayRX() )
72  doLoad( pi );
73  else
74  WAR << "Plugin file is not executable: " << pi << endl;
75  }
76  else
77  {
78  WAR << "Plugin path is neither dir nor file: " << pi << endl;
79  }
80  DBG << "--------------- load " << pi << endl;
81  }
82 
83  void send( const PluginFrame & frame_r )
84  {
85  DBG << "+++++++++++++++ send " << frame_r << endl;
86  for ( auto it = _scripts.begin(); it != _scripts.end(); )
87  {
88  doSend( *it, frame_r );
89  if ( it->isOpen() )
90  ++it;
91  else
92  it = _scripts.erase( it );
93  }
94  DBG << "--------------- send " << frame_r << endl;
95  }
96 
97  const std::list<PluginScript> scripts() const
98  { return _scripts; }
99 
100  private:
102  void doLoad( const PathInfo & pi_r )
103  {
104  MIL << "Load plugin: " << pi_r << endl;
105  try {
106  PluginScript plugin( pi_r.path() );
107  plugin.open();
108 
109  PluginFrame frame( "PLUGINBEGIN" );
110  if ( ZConfig::instance().hasUserData() )
111  frame.setHeader( "userdata", ZConfig::instance().userData() );
112 
113  doSend( plugin, frame ); // closes on error
114  if ( plugin.isOpen() )
115  _scripts.push_back( plugin );
116  }
117  catch( const zypp::Exception & e )
118  {
119  WAR << "Failed to load plugin " << pi_r << endl;
120  }
121  }
122 
123  PluginFrame doSend( PluginScript & script_r, const PluginFrame & frame_r )
124  {
125  PluginFrame ret;
126 
127  try {
128  script_r.send( frame_r );
129  ret = script_r.receive();
130  }
131  catch( const zypp::Exception & e )
132  {
133  ZYPP_CAUGHT(e);
134  WAR << e.asUserHistory() << endl;
135  }
136 
137  // Allow using "/bin/cat" as reflector-script for testing
138  if ( ! ( ret.isAckCommand() || ret.isEnomethodCommand() || ( script_r.script() == "/bin/cat" && frame_r.command() != "ERROR" ) ) )
139  {
140  WAR << "Bad plugin response from " << script_r << ": " << ret << endl;
141  WAR << "(Expected " << PluginFrame::ackCommand() << " or " << PluginFrame::enomethodCommand() << ")" << endl;
142  script_r.close();
143  }
144 
145  return ret;
146  }
147  private:
148  std::list<PluginScript> _scripts;
149  };
150 
152  //
153  // CLASS NAME : PluginExecutor
154  //
156 
158  : _pimpl( new Impl() )
159  {}
160 
162  {}
163 
165  { return _pimpl->empty(); }
166 
167  size_t PluginExecutor::size() const
168  { return _pimpl->size(); }
169 
170  void PluginExecutor::load( const Pathname & path_r )
171  { _pimpl->load( path_r ); }
172 
173  void PluginExecutor::send( const PluginFrame & frame_r )
174  { _pimpl->send( frame_r ); }
175 
176  std::ostream & operator<<( std::ostream & str, const PluginExecutor & obj )
177  { return str << obj._pimpl->scripts(); }
178 
179 } // namespace zypp
PluginExecutor()
Default ctor: Empty plugin list.
#define MIL
Definition: Logger.h:79
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:246
size_t size() const
Number of open plugins.
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:130
Command frame for communication with PluginScript.
Definition: PluginFrame.h:40
const std::string & command() const
Return the frame command.
Definition: PluginFrame.cc:286
Parallel execution of stateful PluginScripts.
String related utilities and Regular expression matching.
const Pathname & script() const
Return the script path if set.
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
PluginFrame receive() const
Receive a PluginFrame.
bool empty() const
Whether no plugins are waiting.
PluginFrame doSend(PluginScript &script_r, const PluginFrame &frame_r)
~PluginExecutor()
Dtor: Send PLUGINEND and close all plugins.
bool isEnomethodCommand() const
Convenience to identify an _ENOMETHOD command.
Definition: PluginFrame.h:114
std::list< PluginScript > _scripts
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
std::ostream & operator<<(std::ostream &str, const Exception &obj)
Definition: Exception.cc:147
static const std::string & enomethodCommand()
"_ENOMETHOD" command.
Definition: PluginFrame.cc:253
void send(const PluginFrame &frame_r)
Send PluginFrame to all open plugins.
void send(const PluginFrame &frame_r) const
Send a PluginFrame.
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:91
void load(const Pathname &path_r)
#define WAR
Definition: Logger.h:80
void send(const PluginFrame &frame_r)
static const std::string & ackCommand()
"ACK" command.
Definition: PluginFrame.cc:241
void open()
Setup connection and execute script.
bool isAckCommand() const
Convenience to identify an ACK command.
Definition: PluginFrame.h:106
bool userMayRX() const
Definition: PathInfo.h:350
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:396
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:589
RW_pointer< Impl > _pimpl
Implementation class.
int close()
Close any open connection.
Base class for Exception.
Definition: Exception.h:145
void load(const Pathname &path_r)
Find and launch plugins sending PLUGINBEGIN.
PluginExecutor implementation.
void doLoad(const PathInfo &pi_r)
Launch a plugin sending PLUGINSTART message.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
void setHeader(const std::string &key_r, const std::string &value_r=std::string())
Set header for key_r removing all other occurrences of key_r.
Definition: PluginFrame.cc:319
Interface to plugin scripts using a Stomp inspired communication protocol.
Definition: PluginScript.h:62
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
const std::list< PluginScript > scripts() const
#define DBG
Definition: Logger.h:78