Mercurial > hg > vamp-plugin-load-checker
comparison src/plugincandidates.cpp @ 55:81ce3ba92b16
Try to forward stderr from the checker to the log callback
author | Chris Cannam |
---|---|
date | Wed, 16 Jan 2019 14:25:28 +0000 |
parents | 0d2d3c89fdf6 |
children | 38ad8cba87a6 |
comparison
equal
deleted
inserted
replaced
54:bb3d59462052 | 55:81ce3ba92b16 |
---|---|
90 { | 90 { |
91 vector<string> candidates; | 91 vector<string> candidates; |
92 | 92 |
93 for (string dirname: path) { | 93 for (string dirname: path) { |
94 | 94 |
95 log("scanning directory " + dirname); | 95 log("Scanning directory " + dirname); |
96 | 96 |
97 QDir dir(dirname.c_str(), PLUGIN_GLOB, | 97 QDir dir(dirname.c_str(), PLUGIN_GLOB, |
98 QDir::Name | QDir::IgnoreCase, | 98 QDir::Name | QDir::IgnoreCase, |
99 QDir::Files | QDir::Readable); | 99 QDir::Files | QDir::Readable); |
100 | 100 |
114 vector<string> pluginPath, | 114 vector<string> pluginPath, |
115 string descriptorSymbolName) | 115 string descriptorSymbolName) |
116 { | 116 { |
117 string helperVersion = getHelperCompatibilityVersion(); | 117 string helperVersion = getHelperCompatibilityVersion(); |
118 if (helperVersion != CHECKER_COMPATIBILITY_VERSION) { | 118 if (helperVersion != CHECKER_COMPATIBILITY_VERSION) { |
119 log("wrong plugin checker helper version found: expected v" + | 119 log("Wrong plugin checker helper version found: expected v" + |
120 string(CHECKER_COMPATIBILITY_VERSION) + ", found v" + | 120 string(CHECKER_COMPATIBILITY_VERSION) + ", found v" + |
121 helperVersion); | 121 helperVersion); |
122 throw runtime_error("wrong version of plugin load helper found"); | 122 throw runtime_error("wrong version of plugin load helper found"); |
123 } | 123 } |
124 | 124 |
138 // Helper bailed out for some reason presumably associated | 138 // Helper bailed out for some reason presumably associated |
139 // with the plugin following the last one it reported | 139 // with the plugin following the last one it reported |
140 // on. Add a failure entry for that one and continue with | 140 // on. Add a failure entry for that one and continue with |
141 // the following ones. | 141 // the following ones. |
142 string failed = *(remaining.rbegin() + shortfall - 1); | 142 string failed = *(remaining.rbegin() + shortfall - 1); |
143 log("helper output ended before result for plugin " + failed); | 143 log("Helper output ended before result for plugin " + failed); |
144 result.push_back("FAILURE|" + failed + "|Plugin load check failed or timed out"); | 144 result.push_back("FAILURE|" + failed + "|Plugin load check failed or timed out"); |
145 remaining = vector<string> | 145 remaining = vector<string> |
146 (remaining.rbegin(), remaining.rbegin() + shortfall - 1); | 146 (remaining.rbegin(), remaining.rbegin() + shortfall - 1); |
147 } | 147 } |
148 ++runcount; | 148 ++runcount; |
180 while (output.endsWith('\n') || output.endsWith('\r')) { | 180 while (output.endsWith('\n') || output.endsWith('\r')) { |
181 output.chop(1); | 181 output.chop(1); |
182 } | 182 } |
183 | 183 |
184 string versionString = QString(output).toStdString(); | 184 string versionString = QString(output).toStdString(); |
185 log("read version string from helper: " + versionString); | 185 log("Read version string from helper: " + versionString); |
186 return versionString; | 186 return versionString; |
187 } | 187 } |
188 | 188 |
189 vector<string> | 189 vector<string> |
190 PluginCandidates::runHelper(vector<string> libraries, string descriptor) | 190 PluginCandidates::runHelper(vector<string> libraries, string descriptor) |
191 { | 191 { |
192 vector<string> output; | 192 vector<string> output; |
193 | 193 |
194 log("running helper " + m_helper + " with following library list:"); | 194 log("Running helper " + m_helper + " with following library list:"); |
195 for (auto &lib: libraries) log(lib); | 195 for (auto &lib: libraries) log(lib); |
196 | 196 |
197 QProcess process; | 197 QProcess process; |
198 process.setReadChannel(QProcess::StandardOutput); | 198 process.setReadChannel(QProcess::StandardOutput); |
199 process.setProcessChannelMode(QProcess::ForwardedErrorChannel); | 199 |
200 if (m_logCallback) { | |
201 log("Log callback is set: using separate-channels mode to gather stderr"); | |
202 process.setProcessChannelMode(QProcess::SeparateChannels); | |
203 } else { | |
204 process.setProcessChannelMode(QProcess::ForwardedErrorChannel); | |
205 } | |
206 | |
200 process.start(m_helper.c_str(), { descriptor.c_str() }); | 207 process.start(m_helper.c_str(), { descriptor.c_str() }); |
201 | 208 |
202 if (!process.waitForStarted()) { | 209 if (!process.waitForStarted()) { |
203 QProcess::ProcessError err = process.error(); | 210 QProcess::ProcessError err = process.error(); |
204 if (err == QProcess::FailedToStart) { | 211 if (err == QProcess::FailedToStart) { |
210 } else { | 217 } else { |
211 std::cerr << "Helper process " << m_helper | 218 std::cerr << "Helper process " << m_helper |
212 << " failed on startup with error code " | 219 << " failed on startup with error code " |
213 << err << std::endl; | 220 << err << std::endl; |
214 } | 221 } |
222 logErrors(&process); | |
215 throw runtime_error("plugin load helper failed to start"); | 223 throw runtime_error("plugin load helper failed to start"); |
216 } | 224 } |
225 | |
226 log("Helper " + m_helper + " started OK"); | |
227 logErrors(&process); | |
217 | 228 |
218 for (auto &lib: libraries) { | 229 for (auto &lib: libraries) { |
219 process.write(lib.c_str(), lib.size()); | 230 process.write(lib.c_str(), lib.size()); |
220 process.write("\n", 1); | 231 process.write("\n", 1); |
221 } | 232 } |
233 if (linelen > 0) { | 244 if (linelen > 0) { |
234 output.push_back(buf); | 245 output.push_back(buf); |
235 done = (output.size() == libraries.size()); | 246 done = (output.size() == libraries.size()); |
236 } else if (linelen < 0) { | 247 } else if (linelen < 0) { |
237 // error case | 248 // error case |
238 log("received error code while reading from helper"); | 249 log("Received error code while reading from helper"); |
239 done = true; | 250 done = true; |
240 } else { | 251 } else { |
241 // no error, but no line read (could just be between | 252 // no error, but no line read (could just be between |
242 // lines, or could be eof) | 253 // lines, or could be eof) |
243 done = (process.state() == QProcess::NotRunning); | 254 done = (process.state() == QProcess::NotRunning); |
244 if (!done) { | 255 if (!done) { |
245 if (t.elapsed() > timeout) { | 256 if (t.elapsed() > timeout) { |
246 // this is purely an emergency measure | 257 // this is purely an emergency measure |
247 log("timeout: helper took too long, killing it"); | 258 log("Timeout: helper took too long, killing it"); |
248 process.kill(); | 259 process.kill(); |
249 done = true; | 260 done = true; |
250 } else { | 261 } else { |
251 process.waitForReadyRead(200); | 262 process.waitForReadyRead(200); |
252 } | 263 } |
253 } | 264 } |
254 } | 265 } |
266 logErrors(&process); | |
255 } | 267 } |
256 | 268 |
257 if (process.state() != QProcess::NotRunning) { | 269 if (process.state() != QProcess::NotRunning) { |
258 process.close(); | 270 process.close(); |
259 process.waitForFinished(); | 271 process.waitForFinished(); |
260 } | 272 logErrors(&process); |
261 | 273 } |
262 log("helper completed"); | 274 |
275 log("Helper completed"); | |
263 | 276 |
264 return output; | 277 return output; |
278 } | |
279 | |
280 void | |
281 PluginCandidates::logErrors(QProcess *p) | |
282 { | |
283 p->setReadChannel(QProcess::StandardError); | |
284 | |
285 qint64 byteCount = p->bytesAvailable(); | |
286 if (byteCount == 0) { | |
287 log("Helper emitted no stderr output"); | |
288 p->setReadChannel(QProcess::StandardOutput); | |
289 return; | |
290 } | |
291 | |
292 QByteArray buffer = p->read(byteCount); | |
293 while (buffer.endsWith('\n') || buffer.endsWith('\r')) { | |
294 buffer.chop(1); | |
295 } | |
296 std::string str(buffer.constData(), buffer.size()); | |
297 log("Helper stderr output follows:\n" + str); | |
298 log("Helper stderr output ends"); | |
299 | |
300 p->setReadChannel(QProcess::StandardOutput); | |
265 } | 301 } |
266 | 302 |
267 void | 303 void |
268 PluginCandidates::recordResult(string tag, vector<string> result) | 304 PluginCandidates::recordResult(string tag, vector<string> result) |
269 { | 305 { |
270 for (auto &r: result) { | 306 for (auto &r: result) { |
271 | 307 |
272 QString s(r.c_str()); | 308 QString s(r.c_str()); |
273 QStringList bits = s.split("|"); | 309 QStringList bits = s.split("|"); |
274 | 310 |
275 log(("read output line from helper: " + s.trimmed()).toStdString()); | 311 log(("Read output line from helper: " + s.trimmed()).toStdString()); |
276 | 312 |
277 if (bits.size() < 2 || bits.size() > 3) { | 313 if (bits.size() < 2 || bits.size() > 3) { |
278 log("invalid output line (wrong number of |-separated fields)"); | 314 log("Invalid output line (wrong number of |-separated fields)"); |
279 continue; | 315 continue; |
280 } | 316 } |
281 | 317 |
282 string status = bits[0].toStdString(); | 318 string status = bits[0].toStdString(); |
283 | 319 |
303 if (codeRE.exactMatch(messageAndCode)) { | 339 if (codeRE.exactMatch(messageAndCode)) { |
304 QStringList caps(codeRE.capturedTexts()); | 340 QStringList caps(codeRE.capturedTexts()); |
305 if (caps.length() == 3) { | 341 if (caps.length() == 3) { |
306 message = caps[1].toStdString(); | 342 message = caps[1].toStdString(); |
307 code = PluginCheckCode(caps[2].toInt()); | 343 code = PluginCheckCode(caps[2].toInt()); |
308 log("split failure report into message and failure code " | 344 log("Split failure report into message and failure code " |
309 + caps[2].toStdString()); | 345 + caps[2].toStdString()); |
310 } else { | 346 } else { |
311 log("unable to split out failure code from report"); | 347 log("Unable to split out failure code from report"); |
312 } | 348 } |
313 } else { | 349 } else { |
314 log("failure message does not give a failure code"); | 350 log("Failure message does not give a failure code"); |
315 } | 351 } |
316 | 352 |
317 if (message == "") { | 353 if (message == "") { |
318 message = messageAndCode.toStdString(); | 354 message = messageAndCode.toStdString(); |
319 } | 355 } |
320 | 356 |
321 m_failures[tag].push_back({ library, code, message }); | 357 m_failures[tag].push_back({ library, code, message }); |
322 | 358 |
323 } else { | 359 } else { |
324 log("unexpected status \"" + status + "\" in output line"); | 360 log("Unexpected status \"" + status + "\" in output line"); |
325 } | 361 } |
326 } | 362 } |
327 } | 363 } |
328 | 364 |