annotate plugin/PluginScan.cpp @ 1246:75aefcc9f07d piper

Use plugin scan results to inform the list requests issued to Piper servers
author Chris Cannam
date Thu, 03 Nov 2016 14:14:09 +0000
parents 0492e54ccd56
children 8f076d02569a
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@1180 21 #include "checker/knownplugins.h"
Chris@1180 22
Chris@1178 23 #include <QMutex>
Chris@1181 24 #include <QCoreApplication>
Chris@1178 25
Chris@1178 26 using std::string;
Chris@1178 27
cannam@1231 28 //#define DEBUG_PLUGIN_SCAN 1
cannam@1231 29
Chris@1180 30 class PluginScan::Logger : public PluginCandidates::LogCallback
Chris@1180 31 {
Chris@1180 32 protected:
Chris@1180 33 void log(std::string message) {
cannam@1231 34 #ifdef DEBUG_PLUGIN_SCAN
cannam@1231 35 cerr << "PluginScan: " << message;
cannam@1231 36 #endif
Chris@1180 37 SVDEBUG << "PluginScan: " << message;
Chris@1180 38 }
Chris@1180 39 };
Chris@1180 40
Chris@1180 41 PluginScan *PluginScan::getInstance()
Chris@1180 42 {
Chris@1178 43 static QMutex mutex;
Chris@1178 44 static PluginScan *m_instance = 0;
Chris@1178 45 mutex.lock();
Chris@1178 46 if (!m_instance) m_instance = new PluginScan();
Chris@1178 47 mutex.unlock();
Chris@1178 48 return m_instance;
Chris@1178 49 }
Chris@1178 50
Chris@1246 51 PluginScan::PluginScan() : m_succeeded(false), m_logger(new Logger) {
Chris@1178 52 }
Chris@1178 53
Chris@1178 54 PluginScan::~PluginScan() {
Chris@1246 55 QMutexLocker locker(&m_mutex);
Chris@1241 56 clear();
Chris@1180 57 delete m_logger;
Chris@1178 58 }
Chris@1178 59
Chris@1178 60 void
Chris@1241 61 PluginScan::scan()
Chris@1178 62 {
Chris@1246 63 QMutexLocker locker(&m_mutex);
Chris@1246 64
Chris@1246 65 bool inProcess = Preferences::getInstance()->getRunPluginsInProcess();
Chris@1246 66
Chris@1246 67 HelperExecPath hep(inProcess ?
Chris@1246 68 HelperExecPath::NativeArchitectureOnly :
Chris@1246 69 HelperExecPath::AllInstalled);
Chris@1246 70
Chris@1246 71 QString helperName("plugin-checker-helper");
Chris@1246 72 auto helpers = hep.getHelperExecutables(helperName);
Chris@1241 73
Chris@1241 74 clear();
Chris@1241 75
Chris@1246 76 for (auto p: helpers) {
Chris@1246 77 cerr << "NOTE: PluginScan: Found helper: " << p.executable << endl;
Chris@1246 78 }
Chris@1246 79
Chris@1246 80 if (helpers.empty()) {
Chris@1246 81 cerr << "NOTE: No plugin checker helpers found in installation;"
Chris@1246 82 << " found none of the following:" << endl;
Chris@1246 83 for (auto d: hep.getHelperCandidatePaths(helperName)) {
Chris@1246 84 cerr << "NOTE: " << d << endl;
Chris@1246 85 }
Chris@1246 86 }
Chris@1246 87
Chris@1246 88 for (auto p: helpers) {
Chris@1241 89 try {
Chris@1246 90 KnownPlugins *kp = new KnownPlugins
Chris@1246 91 (p.executable.toStdString(), m_logger);
Chris@1246 92 if (m_kp.find(p.tag) != m_kp.end()) {
Chris@1246 93 cerr << "WARNING: PluginScan::scan: Duplicate tag " << p.tag
Chris@1246 94 << " for helpers" << endl;
Chris@1246 95 continue;
Chris@1246 96 }
Chris@1246 97 m_kp[p.tag] = kp;
Chris@1241 98 m_succeeded = true;
Chris@1241 99 } catch (const std::exception &e) {
Chris@1241 100 cerr << "ERROR: PluginScan::scan: " << e.what()
Chris@1246 101 << " (with helper path = " << p.executable << ")" << endl;
Chris@1241 102 }
Chris@1241 103 }
Chris@1241 104 }
Chris@1241 105
Chris@1246 106 bool
Chris@1246 107 PluginScan::scanSucceeded() const
Chris@1246 108 {
Chris@1246 109 QMutexLocker locker(&m_mutex);
Chris@1246 110 return m_succeeded;
Chris@1246 111 }
Chris@1246 112
Chris@1241 113 void
Chris@1241 114 PluginScan::clear()
Chris@1241 115 {
Chris@1246 116 for (auto &p: m_kp) {
Chris@1246 117 delete p.second;
Chris@1246 118 }
Chris@1241 119 m_kp.clear();
Chris@1179 120 m_succeeded = false;
Chris@1179 121 }
Chris@1179 122
Chris@1246 123 QList<PluginScan::Candidate>
Chris@1180 124 PluginScan::getCandidateLibrariesFor(PluginType type) const
Chris@1179 125 {
Chris@1246 126 QMutexLocker locker(&m_mutex);
Chris@1246 127
Chris@1180 128 KnownPlugins::PluginType kpt;
Chris@1180 129 switch (type) {
Chris@1180 130 case VampPlugin: kpt = KnownPlugins::VampPlugin; break;
Chris@1180 131 case LADSPAPlugin: kpt = KnownPlugins::LADSPAPlugin; break;
Chris@1180 132 case DSSIPlugin: kpt = KnownPlugins::DSSIPlugin; break;
Chris@1180 133 default: throw std::logic_error("Inconsistency in plugin type enums");
Chris@1180 134 }
Chris@1180 135
Chris@1246 136 QList<Candidate> candidates;
Chris@1245 137
Chris@1246 138 for (auto rec: m_kp) {
Chris@1245 139
Chris@1246 140 KnownPlugins *kp = rec.second;
Chris@1246 141
Chris@1241 142 auto c = kp->getCandidateLibrariesFor(kpt);
Chris@1245 143
Chris@1245 144 std::cerr << "PluginScan: helper \"" << kp->getHelperExecutableName()
Chris@1245 145 << "\" likes " << c.size() << " libraries of type "
Chris@1245 146 << kp->getTagFor(kpt) << std::endl;
Chris@1245 147
Chris@1246 148 for (auto s: c) {
Chris@1246 149 candidates.push_back({ s.c_str(), rec.first });
Chris@1246 150 }
Chris@1245 151
Chris@1245 152 if (type != VampPlugin) {
Chris@1245 153 // We are only interested in querying multiple helpers
Chris@1245 154 // when dealing with Vamp plugins, for which we can use
Chris@1245 155 // external servers and so in some cases can support
Chris@1245 156 // additional architectures. Other plugin formats are
Chris@1245 157 // loaded directly and so must match the host, which is
Chris@1245 158 // what the first helper is supposed to handle -- so
Chris@1245 159 // break after the first one if not querying Vamp
Chris@1245 160 break;
Chris@1245 161 }
Chris@1241 162 }
Chris@1245 163
Chris@1179 164 return candidates;
Chris@1178 165 }
Chris@1178 166
Chris@1178 167 QString
Chris@1178 168 PluginScan::getStartupFailureReport() const
Chris@1178 169 {
Chris@1246 170 QMutexLocker locker(&m_mutex);
Chris@1246 171
Chris@1179 172 if (!m_succeeded) {
Chris@1179 173 return QObject::tr("<b>Failed to scan for plugins</b>"
Chris@1181 174 "<p>Failed to scan for plugins at startup. Possibly "
Chris@1181 175 "the plugin checker helper program was not correctly "
Chris@1181 176 "installed alongside %1?</p>")
Chris@1181 177 .arg(QCoreApplication::applicationName());
Chris@1179 178 }
Chris@1241 179 if (m_kp.empty()) {
Chris@1179 180 return QObject::tr("<b>Did not scan for plugins</b>"
Chris@1179 181 "<p>Apparently no scan for plugins was attempted "
Chris@1179 182 "(internal error?)</p>");
Chris@1179 183 }
Chris@1179 184
Chris@1241 185 QString report;
Chris@1241 186 for (auto kp: m_kp) {
Chris@1246 187 report += QString::fromStdString(kp.second->getFailureReport());
Chris@1241 188 }
Chris@1179 189 if (report == "") {
Chris@1241 190 return report;
Chris@1179 191 }
Chris@1179 192
Chris@1179 193 return QObject::tr("<b>Failed to load plugins</b>"
Chris@1179 194 "<p>Failed to load one or more plugin libraries:</p>")
Chris@1241 195 + report
Chris@1181 196 + QObject::tr("<p>These plugins may be incompatible with the system, "
Chris@1181 197 "and will be ignored during this run of %1.</p>")
Chris@1181 198 .arg(QCoreApplication::applicationName());
Chris@1178 199 }
Chris@1178 200