MatN work for versatile appimage creation for all types of os
[goodguy/cinelerra.git] / cinelerra-5.1 / tools / makeappimagetool / includes / base_impl.h
1 // system headers
2 #include <set>
3 #include <string>
4 #include <vector>
5 #include <fcntl.h>
6 #include <poll.h>
7
8 // library headers
9 #include <boost/filesystem.hpp>
10 #include <fnmatch.h>
11 #include <thread>
12
13 // local headers
14 #include "log.h"
15 #include "util.h"
16 #include "process.h"
17 #include "plugin_process_handler.h"
18
19 #pragma once
20
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 {
24     namespace plugin {
25         namespace base {
26             using namespace linuxdeploy::core::log;
27
28             template<int API_LEVEL>
29             class PluginBase<API_LEVEL>::PrivateData {
30                 public:
31                     const boost::filesystem::path pluginPath;
32                     std::string name;
33                     int apiLevel;
34                     PLUGIN_TYPE pluginType;
35
36                 public:
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());
40                         }
41
42                         apiLevel = getApiLevelFromExecutable();
43                         pluginType = getPluginTypeFromExecutable();
44
45                         boost::cmatch res;
46                         boost::regex_match(path.filename().c_str(), res, PLUGIN_EXPR);
47                         name = res[1].str();
48                     };
49
50                 private:
51                     int getApiLevelFromExecutable() {
52                         const auto arg =  "--plugin-api-version";
53
54                         const subprocess::subprocess proc({pluginPath.string(), arg});
55                         const auto stdoutOutput = proc.check_output();
56
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;
59                             return -1;
60                         }
61
62                         try {
63                             auto apiLevel = std::stoi(stdoutOutput);
64                             return apiLevel;
65                         } catch (const std::exception&) {
66                             return -1;
67                         }
68                     }
69
70                     PLUGIN_TYPE getPluginTypeFromExecutable() {
71                         // assume input type
72                         auto type = INPUT_TYPE;
73
74                         // check whether plugin implements --plugin-type
75                         try {
76                             const subprocess::subprocess proc({pluginPath.c_str(), "--plugin-type"});
77                             const auto stdoutOutput = proc.check_output();
78
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'));
82
83                                 if (firstLine == "input")
84                                     type = INPUT_TYPE;
85                                 else if (firstLine == "output")
86                                     type = OUTPUT_TYPE;
87                             }
88                         } catch (const std::logic_error&) {}
89
90                         return type;
91                     }
92             };
93
94             template<int API_LEVEL>
95             PluginBase<API_LEVEL>::PluginBase(const boost::filesystem::path& path) : IPlugin(path) {
96                 d = new PrivateData(path);
97
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());
102                 }
103             }
104
105             template<int API_LEVEL>
106             PluginBase<API_LEVEL>::~PluginBase() {
107                 delete d;
108             }
109
110             template<int API_LEVEL>
111             boost::filesystem::path PluginBase<API_LEVEL>::path() const {
112                 return d->pluginPath;
113             }
114
115             template<int API_LEVEL>
116             PLUGIN_TYPE PluginBase<API_LEVEL>::pluginType() const {
117                 return d->pluginType;
118             }
119
120             template<int API_LEVEL>
121             std::string PluginBase<API_LEVEL>::pluginTypeString() const {
122                 switch ((int) d->pluginType) {
123                     case INPUT_TYPE:
124                         return "input";
125                     case OUTPUT_TYPE:
126                         return "output";
127                     default:
128                         return "<unknown>";
129                 }
130             }
131
132             template<int API_LEVEL>
133             int PluginBase<API_LEVEL>::apiLevel() const {
134                 return d->apiLevel;
135             }
136
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);
141             }
142         }
143     }
144 }