Mercurial > hg > vamp-plugin-load-checker
comparison plugincandidates.cpp @ 4:6f891a9c6434
Make checker with hard-coded knowledge about various plugin types and paths; fix some process management problems
author | Chris Cannam |
---|---|
date | Wed, 13 Apr 2016 12:00:07 +0100 |
parents | 3bae396cf8e0 |
children | 74064d6f5e07 |
comparison
equal
deleted
inserted
replaced
3:3bae396cf8e0 | 4:6f891a9c6434 |
---|---|
7 #include <iostream> | 7 #include <iostream> |
8 | 8 |
9 #include <QProcess> | 9 #include <QProcess> |
10 #include <QDir> | 10 #include <QDir> |
11 | 11 |
12 #ifdef _WIN32 | 12 #if defined(_WIN32) |
13 #define PLUGIN_GLOB "*.dll" | 13 #define PLUGIN_GLOB "*.dll" |
14 #define PATH_SEPARATOR ';' | 14 #elif defined(__APPLE__) |
15 #else | |
16 #define PATH_SEPARATOR ':' | |
17 #ifdef __APPLE__ | |
18 #define PLUGIN_GLOB "*.dylib *.so" | 15 #define PLUGIN_GLOB "*.dylib *.so" |
19 #else | 16 #else |
20 #define PLUGIN_GLOB "*.so" | 17 #define PLUGIN_GLOB "*.so" |
21 #endif | |
22 #endif | 18 #endif |
23 | 19 |
24 using namespace std; | 20 using namespace std; |
25 | 21 |
26 PluginCandidates::PluginCandidates(string helperExecutableName) : | 22 PluginCandidates::PluginCandidates(string helperExecutableName) : |
27 m_helper(helperExecutableName) | 23 m_helper(helperExecutableName) |
28 { | 24 { |
29 } | 25 } |
30 | 26 |
31 vector<string> | 27 vector<string> |
32 PluginCandidates::getCandidateLibrariesFor(string tag) | 28 PluginCandidates::getCandidateLibrariesFor(string tag) const |
33 { | 29 { |
34 return m_candidates[tag]; | 30 if (m_candidates.find(tag) == m_candidates.end()) return {}; |
31 else return m_candidates.at(tag); | |
35 } | 32 } |
36 | 33 |
37 vector<PluginCandidates::FailureRec> | 34 vector<PluginCandidates::FailureRec> |
38 PluginCandidates::getFailedLibrariesFor(string tag) | 35 PluginCandidates::getFailedLibrariesFor(string tag) const |
39 { | 36 { |
40 return m_failures[tag]; | 37 if (m_failures.find(tag) == m_failures.end()) return {}; |
38 else return m_failures.at(tag); | |
41 } | 39 } |
42 | 40 |
43 vector<string> | 41 vector<string> |
44 PluginCandidates::getLibrariesInPath(vector<string> path) | 42 PluginCandidates::getLibrariesInPath(vector<string> path) |
45 { | 43 { |
65 } | 63 } |
66 | 64 |
67 void | 65 void |
68 PluginCandidates::scan(string tag, | 66 PluginCandidates::scan(string tag, |
69 vector<string> pluginPath, | 67 vector<string> pluginPath, |
70 string descriptorFunctionName) | 68 string descriptorSymbolName) |
71 { | 69 { |
72 vector<string> libraries = getLibrariesInPath(pluginPath); | 70 vector<string> libraries = getLibrariesInPath(pluginPath); |
73 vector<string> remaining = libraries; | 71 vector<string> remaining = libraries; |
74 | 72 |
75 int runlimit = 20; | 73 int runlimit = 20; |
76 int runcount = 0; | 74 int runcount = 0; |
77 | 75 |
78 vector<string> result; | 76 vector<string> result; |
79 | 77 |
80 while (result.size() < libraries.size() && runcount < runlimit) { | 78 while (result.size() < libraries.size() && runcount < runlimit) { |
81 vector<string> output = runHelper(remaining, descriptorFunctionName); | 79 vector<string> output = runHelper(remaining, descriptorSymbolName); |
82 result.insert(result.end(), output.begin(), output.end()); | 80 result.insert(result.end(), output.begin(), output.end()); |
83 int shortfall = int(remaining.size()) - int(output.size()); | 81 int shortfall = int(remaining.size()) - int(output.size()); |
84 if (shortfall > 0) { | 82 if (shortfall > 0) { |
85 // Helper bailed out for some reason presumably associated | 83 // Helper bailed out for some reason presumably associated |
86 // with the plugin following the last one it reported | 84 // with the plugin following the last one it reported |
87 // on. Add a null entry for that one and continue with the | 85 // on. Add a failure entry for that one and continue with |
88 // following ones. | 86 // the following ones. |
89 result.push_back(""); | 87 cerr << "shortfall = " << shortfall << " (of " << remaining.size() << ")" << endl; |
90 if (shortfall == 1) { | 88 result.push_back("FAILURE|" + |
91 remaining = vector<string>(); | 89 *(remaining.rbegin() + shortfall - 1) + |
92 } else { | 90 "|Plugin load check failed"); |
93 remaining = vector<string> | 91 remaining = vector<string> |
94 (remaining.rbegin(), remaining.rbegin() + shortfall - 1); | 92 (remaining.rbegin(), remaining.rbegin() + shortfall - 1); |
95 } | |
96 } | 93 } |
97 ++runcount; | 94 ++runcount; |
98 } | 95 } |
99 | 96 |
100 recordResult(tag, result); | 97 recordResult(tag, result); |
102 | 99 |
103 vector<string> | 100 vector<string> |
104 PluginCandidates::runHelper(vector<string> libraries, string descriptor) | 101 PluginCandidates::runHelper(vector<string> libraries, string descriptor) |
105 { | 102 { |
106 vector<string> output; | 103 vector<string> output; |
107 cerr << "running helper with following library list:" << endl; | 104 // cerr << "running helper with following library list:" << endl; |
108 for (auto &lib: libraries) cerr << lib << endl; | 105 // for (auto &lib: libraries) cerr << lib << endl; |
109 | 106 |
110 QProcess process; | 107 QProcess process; |
111 process.setReadChannel(QProcess::StandardOutput); | 108 process.setReadChannel(QProcess::StandardOutput); |
109 process.setProcessChannelMode(QProcess::ForwardedErrorChannel); | |
112 process.start(m_helper.c_str(), { descriptor.c_str() }); | 110 process.start(m_helper.c_str(), { descriptor.c_str() }); |
113 if (!process.waitForStarted()) { | 111 if (!process.waitForStarted()) { |
114 cerr << "helper failed to start" << endl; | 112 cerr << "helper failed to start" << endl; |
115 throw runtime_error("plugin load helper failed to start"); | 113 throw runtime_error("plugin load helper failed to start"); |
116 } | 114 } |
118 process.write(lib.c_str(), lib.size()); | 116 process.write(lib.c_str(), lib.size()); |
119 process.write("\n", 1); | 117 process.write("\n", 1); |
120 } | 118 } |
121 | 119 |
122 int buflen = 4096; | 120 int buflen = 4096; |
123 while (process.waitForReadyRead()) { | 121 bool done = false; |
122 | |
123 while (!done) { | |
124 char buf[buflen]; | 124 char buf[buflen]; |
125 qint64 linelen = process.readLine(buf, buflen); | 125 qint64 linelen = process.readLine(buf, buflen); |
126 // cerr << "read line: " << buf; | 126 if (linelen > 0) { |
127 if (linelen < 0) { | 127 output.push_back(buf); |
128 cerr << "read failed from plugin load helper" << endl; | 128 done = (output.size() == libraries.size()); |
129 return output; | 129 } else if (linelen < 0) { |
130 } | 130 // error case |
131 output.push_back(buf); | 131 done = true; |
132 if (output.size() == libraries.size()) { | 132 } else { |
133 process.close(); | 133 // no error, but no line read (could just be between |
134 process.waitForFinished(); | 134 // lines, or could be eof) |
135 break; | 135 done = (process.state() == QProcess::NotRunning); |
136 if (!done) process.waitForReadyRead(100); | |
136 } | 137 } |
137 } | 138 } |
139 | |
140 if (process.state() != QProcess::NotRunning) { | |
141 process.close(); | |
142 process.waitForFinished(); | |
143 } | |
138 | 144 |
139 return output; | 145 return output; |
140 } | 146 } |
141 | 147 |
142 void | 148 void |
143 PluginCandidates::recordResult(string tag, vector<string> result) | 149 PluginCandidates::recordResult(string tag, vector<string> result) |
144 { | 150 { |
145 cerr << "recordResult: not yet implemented, but result was:" << endl; | 151 for (auto &r: result) { |
146 for (auto &r: result) cerr << r; | 152 |
147 cerr << "(ends)" << endl; | 153 QString s(r.c_str()); |
154 QStringList bits = s.split("|"); | |
155 if (bits.size() < 2 || bits.size() > 3) { | |
156 cerr << "Invalid helper output line: \"" << r << "\"" << endl; | |
157 continue; | |
158 } | |
159 | |
160 string status = bits[0].toStdString(); | |
161 | |
162 string library = bits[1].toStdString(); | |
163 if (bits.size() == 2) library = bits[1].trimmed().toStdString(); | |
164 | |
165 string message = ""; | |
166 if (bits.size() > 2) message = bits[2].trimmed().toStdString(); | |
167 | |
168 if (status == "SUCCESS") { | |
169 m_candidates[tag].push_back(library); | |
170 | |
171 } else if (status == "FAILURE") { | |
172 m_failures[tag].push_back({ library, message }); | |
173 | |
174 } else { | |
175 cerr << "Unexpected status " << status | |
176 << " in helper output line: \"" << r << "\"" << endl; | |
177 } | |
178 } | |
148 } | 179 } |
149 | 180 |