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