9 #include <boost/filesystem.hpp>
17 #include "plugin_process_handler.h"
21 // implementation of PluginBase in a header to solve issues like
22 // https://bytefreaks.net/programming-2/c/c-undefined-reference-to-templated-class-function
23 namespace linuxdeploy {
26 using namespace linuxdeploy::core::log;
28 template<int API_LEVEL>
29 class PluginBase<API_LEVEL>::PrivateData {
31 const boost::filesystem::path pluginPath;
34 PLUGIN_TYPE pluginType;
37 explicit PrivateData(const boost::filesystem::path& path) : pluginPath(path) {
38 if (!boost::filesystem::exists(path)) {
39 throw PluginError("No such file or directory: " + path.string());
42 apiLevel = getApiLevelFromExecutable();
43 pluginType = getPluginTypeFromExecutable();
46 boost::regex_match(path.filename().c_str(), res, PLUGIN_EXPR);
51 int getApiLevelFromExecutable() {
52 const auto arg = "--plugin-api-version";
54 const subprocess::subprocess proc({pluginPath.string(), arg});
55 const auto stdoutOutput = proc.check_output();
57 if (stdoutOutput.empty()) {
58 ldLog() << LD_WARNING << "received empty response from plugin" << pluginPath << "while trying to fetch data for" << "--plugin-api-version" << std::endl;
63 auto apiLevel = std::stoi(stdoutOutput);
65 } catch (const std::exception&) {
70 PLUGIN_TYPE getPluginTypeFromExecutable() {
72 auto type = INPUT_TYPE;
74 // check whether plugin implements --plugin-type
76 const subprocess::subprocess proc({pluginPath.c_str(), "--plugin-type"});
77 const auto stdoutOutput = proc.check_output();
79 // the specification requires a single line, but we'll silently accept more than that, too
80 if (std::count(stdoutOutput.begin(), stdoutOutput.end(), '\n') >= 1) {
81 auto firstLine = stdoutOutput.substr(0, stdoutOutput.find_first_of('\n'));
83 if (firstLine == "input")
85 else if (firstLine == "output")
88 } catch (const std::logic_error&) {}
94 template<int API_LEVEL>
95 PluginBase<API_LEVEL>::PluginBase(const boost::filesystem::path& path) : IPlugin(path) {
96 d = new PrivateData(path);
98 if (d->apiLevel != API_LEVEL) {
99 std::stringstream msg;
100 msg << "This class only supports API level " << API_LEVEL << ", not " << d->apiLevel;
101 throw WrongApiLevelError(msg.str());
105 template<int API_LEVEL>
106 PluginBase<API_LEVEL>::~PluginBase() {
110 template<int API_LEVEL>
111 boost::filesystem::path PluginBase<API_LEVEL>::path() const {
112 return d->pluginPath;
115 template<int API_LEVEL>
116 PLUGIN_TYPE PluginBase<API_LEVEL>::pluginType() const {
117 return d->pluginType;
120 template<int API_LEVEL>
121 std::string PluginBase<API_LEVEL>::pluginTypeString() const {
122 switch ((int) d->pluginType) {
132 template<int API_LEVEL>
133 int PluginBase<API_LEVEL>::apiLevel() const {
137 template<int API_LEVEL>
138 int PluginBase<API_LEVEL>::run(const boost::filesystem::path& appDirPath) {
139 plugin_process_handler handler(d->name, path());
140 return handler.run(appDirPath);