annotate plugin/PluginScan.cpp @ 1372:54366398e636

Handle exceptions raised during plugin processing (as opposed to on init/configure, which were already handled)
author Chris Cannam
date Tue, 31 Jan 2017 11:13:20 +0000
parents f98fde50570b
children 0bbf91b05164
rev   line source
Chris@1178 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1178 2
Chris@1178 3 /*
Chris@1178 4 Sonic Visualiser
Chris@1178 5 An audio file viewer and annotation editor.
Chris@1178 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1178 7
Chris@1178 8 This program is free software; you can redistribute it and/or
Chris@1178 9 modify it under the terms of the GNU General Public License as
Chris@1178 10 published by the Free Software Foundation; either version 2 of the
Chris@1178 11 License, or (at your option) any later version. See the file
Chris@1178 12 COPYING included with this distribution for more information.
Chris@1178 13 */
Chris@1178 14
Chris@1178 15 #include "PluginScan.h"
Chris@1178 16
Chris@1178 17 #include "base/Debug.h"
Chris@1246 18 #include "base/Preferences.h"
Chris@1241 19 #include "base/HelperExecPath.h"
Chris@1178 20
Chris@1249 21 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1180 22 #include "checker/knownplugins.h"
Chris@1249 23 #else
Chris@1249 24 class KnownPlugins {};
Chris@1249 25 #endif
Chris@1180 26
Chris@1178 27 #include <QMutex>
Chris@1181 28 #include <QCoreApplication>
Chris@1178 29
Chris@1178 30 using std::string;
Chris@1178 31
Chris@1249 32 class PluginScan::Logger
Chris@1249 33 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 34 : public PluginCandidates::LogCallback
Chris@1249 35 #endif
Chris@1180 36 {
Chris@1180 37 protected:
Chris@1180 38 void log(std::string message) {
Chris@1264 39 SVDEBUG << "PluginScan: " << message << endl;
Chris@1180 40 }
Chris@1180 41 };
Chris@1180 42
Chris@1180 43 PluginScan *PluginScan::getInstance()
Chris@1180 44 {
Chris@1178 45 static QMutex mutex;
Chris@1178 46 static PluginScan *m_instance = 0;
Chris@1178 47 mutex.lock();
Chris@1178 48 if (!m_instance) m_instance = new PluginScan();
Chris@1178 49 mutex.unlock();
Chris@1178 50 return m_instance;
Chris@1178 51 }
Chris@1178 52
Chris@1246 53 PluginScan::PluginScan() : m_succeeded(false), m_logger(new Logger) {
Chris@1178 54 }
Chris@1178 55
Chris@1178 56 PluginScan::~PluginScan() {
Chris@1246 57 QMutexLocker locker(&m_mutex);
Chris@1241 58 clear();
Chris@1180 59 delete m_logger;
Chris@1178 60 }
Chris@1178 61
Chris@1178 62 void
Chris@1241 63 PluginScan::scan()
Chris@1178 64 {
Chris@1249 65 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 66
Chris@1246 67 QMutexLocker locker(&m_mutex);
Chris@1246 68
Chris@1246 69 bool inProcess = Preferences::getInstance()->getRunPluginsInProcess();
Chris@1246 70
Chris@1246 71 HelperExecPath hep(inProcess ?
Chris@1246 72 HelperExecPath::NativeArchitectureOnly :
Chris@1246 73 HelperExecPath::AllInstalled);
Chris@1246 74
Chris@1352 75 QString helperName("vamp-plugin-load-checker");
Chris@1246 76 auto helpers = hep.getHelperExecutables(helperName);
Chris@1241 77
Chris@1241 78 clear();
Chris@1241 79
Chris@1246 80 for (auto p: helpers) {
Chris@1247 81 SVDEBUG << "NOTE: PluginScan: Found helper: " << p.executable << endl;
Chris@1246 82 }
Chris@1246 83
Chris@1246 84 if (helpers.empty()) {
Chris@1247 85 SVDEBUG << "NOTE: No plugin checker helpers found in installation;"
Chris@1246 86 << " found none of the following:" << endl;
Chris@1246 87 for (auto d: hep.getHelperCandidatePaths(helperName)) {
Chris@1247 88 SVDEBUG << "NOTE: " << d << endl;
Chris@1246 89 }
Chris@1246 90 }
Chris@1246 91
Chris@1246 92 for (auto p: helpers) {
Chris@1241 93 try {
Chris@1246 94 KnownPlugins *kp = new KnownPlugins
Chris@1246 95 (p.executable.toStdString(), m_logger);
Chris@1246 96 if (m_kp.find(p.tag) != m_kp.end()) {
Chris@1247 97 SVDEBUG << "WARNING: PluginScan::scan: Duplicate tag " << p.tag
Chris@1246 98 << " for helpers" << endl;
Chris@1246 99 continue;
Chris@1246 100 }
Chris@1246 101 m_kp[p.tag] = kp;
Chris@1241 102 m_succeeded = true;
Chris@1241 103 } catch (const std::exception &e) {
Chris@1247 104 SVDEBUG << "ERROR: PluginScan::scan: " << e.what()
Chris@1246 105 << " (with helper path = " << p.executable << ")" << endl;
Chris@1241 106 }
Chris@1241 107 }
Chris@1249 108
Chris@1249 109 #endif
Chris@1241 110 }
Chris@1241 111
Chris@1246 112 bool
Chris@1246 113 PluginScan::scanSucceeded() const
Chris@1246 114 {
Chris@1246 115 QMutexLocker locker(&m_mutex);
Chris@1246 116 return m_succeeded;
Chris@1246 117 }
Chris@1246 118
Chris@1241 119 void
Chris@1241 120 PluginScan::clear()
Chris@1241 121 {
Chris@1246 122 for (auto &p: m_kp) {
Chris@1246 123 delete p.second;
Chris@1246 124 }
Chris@1241 125 m_kp.clear();
Chris@1179 126 m_succeeded = false;
Chris@1179 127 }
Chris@1179 128
Chris@1246 129 QList<PluginScan::Candidate>
Chris@1278 130 PluginScan::getCandidateLibrariesFor(PluginType
Chris@1278 131 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1278 132 type
Chris@1278 133 #endif
Chris@1278 134 ) const
Chris@1179 135 {
Chris@1249 136 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 137
Chris@1246 138 QMutexLocker locker(&m_mutex);
Chris@1246 139
Chris@1180 140 KnownPlugins::PluginType kpt;
Chris@1180 141 switch (type) {
Chris@1180 142 case VampPlugin: kpt = KnownPlugins::VampPlugin; break;
Chris@1180 143 case LADSPAPlugin: kpt = KnownPlugins::LADSPAPlugin; break;
Chris@1180 144 case DSSIPlugin: kpt = KnownPlugins::DSSIPlugin; break;
Chris@1180 145 default: throw std::logic_error("Inconsistency in plugin type enums");
Chris@1180 146 }
Chris@1180 147
Chris@1246 148 QList<Candidate> candidates;
Chris@1245 149
Chris@1246 150 for (auto rec: m_kp) {
Chris@1245 151
Chris@1246 152 KnownPlugins *kp = rec.second;
Chris@1246 153
Chris@1241 154 auto c = kp->getCandidateLibrariesFor(kpt);
Chris@1245 155
Chris@1247 156 SVDEBUG << "PluginScan: helper \"" << kp->getHelperExecutableName()
Chris@1247 157 << "\" likes " << c.size() << " libraries of type "
Chris@1247 158 << kp->getTagFor(kpt) << endl;
Chris@1245 159
Chris@1246 160 for (auto s: c) {
Chris@1246 161 candidates.push_back({ s.c_str(), rec.first });
Chris@1246 162 }
Chris@1245 163
Chris@1245 164 if (type != VampPlugin) {
Chris@1245 165 // We are only interested in querying multiple helpers
Chris@1245 166 // when dealing with Vamp plugins, for which we can use
Chris@1245 167 // external servers and so in some cases can support
Chris@1245 168 // additional architectures. Other plugin formats are
Chris@1245 169 // loaded directly and so must match the host, which is
Chris@1245 170 // what the first helper is supposed to handle -- so
Chris@1245 171 // break after the first one if not querying Vamp
Chris@1245 172 break;
Chris@1245 173 }
Chris@1241 174 }
Chris@1245 175
Chris@1179 176 return candidates;
Chris@1249 177
Chris@1249 178 #else
Chris@1249 179 return {};
Chris@1249 180 #endif
Chris@1178 181 }
Chris@1178 182
Chris@1178 183 QString
Chris@1178 184 PluginScan::getStartupFailureReport() const
Chris@1178 185 {
Chris@1249 186 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 187
Chris@1246 188 QMutexLocker locker(&m_mutex);
Chris@1246 189
Chris@1179 190 if (!m_succeeded) {
Chris@1179 191 return QObject::tr("<b>Failed to scan for plugins</b>"
Chris@1181 192 "<p>Failed to scan for plugins at startup. Possibly "
Chris@1352 193 "the plugin checker program was not correctly "
Chris@1181 194 "installed alongside %1?</p>")
Chris@1181 195 .arg(QCoreApplication::applicationName());
Chris@1179 196 }
Chris@1241 197 if (m_kp.empty()) {
Chris@1179 198 return QObject::tr("<b>Did not scan for plugins</b>"
Chris@1179 199 "<p>Apparently no scan for plugins was attempted "
Chris@1179 200 "(internal error?)</p>");
Chris@1179 201 }
Chris@1179 202
Chris@1241 203 QString report;
Chris@1241 204 for (auto kp: m_kp) {
Chris@1246 205 report += QString::fromStdString(kp.second->getFailureReport());
Chris@1241 206 }
Chris@1179 207 if (report == "") {
Chris@1241 208 return report;
Chris@1179 209 }
Chris@1179 210
Chris@1179 211 return QObject::tr("<b>Failed to load plugins</b>"
Chris@1179 212 "<p>Failed to load one or more plugin libraries:</p>")
Chris@1241 213 + report
Chris@1181 214 + QObject::tr("<p>These plugins may be incompatible with the system, "
Chris@1181 215 "and will be ignored during this run of %1.</p>")
Chris@1181 216 .arg(QCoreApplication::applicationName());
Chris@1249 217
Chris@1249 218 #else
Chris@1249 219 return "";
Chris@1249 220 #endif
Chris@1178 221 }
Chris@1178 222