annotate plugin/PluginScan.cpp @ 1249:d45a16c232bd piper

Align Sonic Annotator with the new Piper-ified subrepos (bearing in mind we want neither Piper nor the plugin load checker in Sonic Annotator itself)
author Chris Cannam
date Fri, 04 Nov 2016 14:16:01 +0000
parents 8f076d02569a
children a99641535e02
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@1180 39 SVDEBUG << "PluginScan: " << message;
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@1246 75 QString helperName("plugin-checker-helper");
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@1180 130 PluginScan::getCandidateLibrariesFor(PluginType type) const
Chris@1179 131 {
Chris@1249 132 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 133
Chris@1246 134 QMutexLocker locker(&m_mutex);
Chris@1246 135
Chris@1180 136 KnownPlugins::PluginType kpt;
Chris@1180 137 switch (type) {
Chris@1180 138 case VampPlugin: kpt = KnownPlugins::VampPlugin; break;
Chris@1180 139 case LADSPAPlugin: kpt = KnownPlugins::LADSPAPlugin; break;
Chris@1180 140 case DSSIPlugin: kpt = KnownPlugins::DSSIPlugin; break;
Chris@1180 141 default: throw std::logic_error("Inconsistency in plugin type enums");
Chris@1180 142 }
Chris@1180 143
Chris@1246 144 QList<Candidate> candidates;
Chris@1245 145
Chris@1246 146 for (auto rec: m_kp) {
Chris@1245 147
Chris@1246 148 KnownPlugins *kp = rec.second;
Chris@1246 149
Chris@1241 150 auto c = kp->getCandidateLibrariesFor(kpt);
Chris@1245 151
Chris@1247 152 SVDEBUG << "PluginScan: helper \"" << kp->getHelperExecutableName()
Chris@1247 153 << "\" likes " << c.size() << " libraries of type "
Chris@1247 154 << kp->getTagFor(kpt) << endl;
Chris@1245 155
Chris@1246 156 for (auto s: c) {
Chris@1246 157 candidates.push_back({ s.c_str(), rec.first });
Chris@1246 158 }
Chris@1245 159
Chris@1245 160 if (type != VampPlugin) {
Chris@1245 161 // We are only interested in querying multiple helpers
Chris@1245 162 // when dealing with Vamp plugins, for which we can use
Chris@1245 163 // external servers and so in some cases can support
Chris@1245 164 // additional architectures. Other plugin formats are
Chris@1245 165 // loaded directly and so must match the host, which is
Chris@1245 166 // what the first helper is supposed to handle -- so
Chris@1245 167 // break after the first one if not querying Vamp
Chris@1245 168 break;
Chris@1245 169 }
Chris@1241 170 }
Chris@1245 171
Chris@1179 172 return candidates;
Chris@1249 173
Chris@1249 174 #else
Chris@1249 175 return {};
Chris@1249 176 #endif
Chris@1178 177 }
Chris@1178 178
Chris@1178 179 QString
Chris@1178 180 PluginScan::getStartupFailureReport() const
Chris@1178 181 {
Chris@1249 182 #ifdef HAVE_PLUGIN_CHECKER_HELPER
Chris@1249 183
Chris@1246 184 QMutexLocker locker(&m_mutex);
Chris@1246 185
Chris@1179 186 if (!m_succeeded) {
Chris@1179 187 return QObject::tr("<b>Failed to scan for plugins</b>"
Chris@1181 188 "<p>Failed to scan for plugins at startup. Possibly "
Chris@1181 189 "the plugin checker helper program was not correctly "
Chris@1181 190 "installed alongside %1?</p>")
Chris@1181 191 .arg(QCoreApplication::applicationName());
Chris@1179 192 }
Chris@1241 193 if (m_kp.empty()) {
Chris@1179 194 return QObject::tr("<b>Did not scan for plugins</b>"
Chris@1179 195 "<p>Apparently no scan for plugins was attempted "
Chris@1179 196 "(internal error?)</p>");
Chris@1179 197 }
Chris@1179 198
Chris@1241 199 QString report;
Chris@1241 200 for (auto kp: m_kp) {
Chris@1246 201 report += QString::fromStdString(kp.second->getFailureReport());
Chris@1241 202 }
Chris@1179 203 if (report == "") {
Chris@1241 204 return report;
Chris@1179 205 }
Chris@1179 206
Chris@1179 207 return QObject::tr("<b>Failed to load plugins</b>"
Chris@1179 208 "<p>Failed to load one or more plugin libraries:</p>")
Chris@1241 209 + report
Chris@1181 210 + QObject::tr("<p>These plugins may be incompatible with the system, "
Chris@1181 211 "and will be ignored during this run of %1.</p>")
Chris@1181 212 .arg(QCoreApplication::applicationName());
Chris@1249 213
Chris@1249 214 #else
Chris@1249 215 return "";
Chris@1249 216 #endif
Chris@1178 217 }
Chris@1178 218