forked from qt-creator/qt-creator
ExtensionSystem: Refactor PluginSpec
Splits the functionality between plugin type specific and general. Allows Plugins to be loaded after the first pass, e.g. for Lua scripted plugins. Change-Id: If2712817a672c49d554fdc308250cb06ca7eb3f8 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -11,7 +11,7 @@ add_qtc_library(ExtensionSystem
|
|||||||
pluginerroroverview.cpp pluginerroroverview.h
|
pluginerroroverview.cpp pluginerroroverview.h
|
||||||
pluginerrorview.cpp pluginerrorview.h
|
pluginerrorview.cpp pluginerrorview.h
|
||||||
pluginmanager.cpp pluginmanager.h pluginmanager_p.h
|
pluginmanager.cpp pluginmanager.h pluginmanager_p.h
|
||||||
pluginspec.cpp pluginspec.h pluginspec_p.h
|
pluginspec.cpp pluginspec.h
|
||||||
pluginview.cpp pluginview.h
|
pluginview.cpp pluginview.h
|
||||||
EXPLICIT_MOC
|
EXPLICIT_MOC
|
||||||
pluginmanager.h
|
pluginmanager.h
|
||||||
|
@@ -29,7 +29,6 @@ QtcLibrary {
|
|||||||
"pluginmanager_p.h",
|
"pluginmanager_p.h",
|
||||||
"pluginspec.cpp",
|
"pluginspec.cpp",
|
||||||
"pluginspec.h",
|
"pluginspec.h",
|
||||||
"pluginspec_p.h",
|
|
||||||
"pluginview.cpp",
|
"pluginview.cpp",
|
||||||
"pluginview.h",
|
"pluginview.h",
|
||||||
]
|
]
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
#include "extensionsystemtr.h"
|
#include "extensionsystemtr.h"
|
||||||
#include "pluginmanager.h"
|
#include "pluginmanager.h"
|
||||||
#include "pluginmanager_p.h"
|
#include "pluginmanager_p.h"
|
||||||
#include "pluginspec_p.h"
|
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
@@ -177,7 +176,7 @@ bool OptionsParser::checkForLoadOption()
|
|||||||
if (nextToken(RequiredToken)) {
|
if (nextToken(RequiredToken)) {
|
||||||
if (m_currentArg == QLatin1String("all")) {
|
if (m_currentArg == QLatin1String("all")) {
|
||||||
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs))
|
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs))
|
||||||
spec->d->setForceEnabled(true);
|
spec->setForceEnabled(true);
|
||||||
m_isDependencyRefreshNeeded = true;
|
m_isDependencyRefreshNeeded = true;
|
||||||
} else {
|
} else {
|
||||||
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
|
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
|
||||||
@@ -186,7 +185,7 @@ bool OptionsParser::checkForLoadOption()
|
|||||||
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(m_currentArg);
|
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(m_currentArg);
|
||||||
m_hasError = true;
|
m_hasError = true;
|
||||||
} else {
|
} else {
|
||||||
spec->d->setForceEnabled(true);
|
spec->setForceEnabled(true);
|
||||||
m_isDependencyRefreshNeeded = true;
|
m_isDependencyRefreshNeeded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +201,7 @@ bool OptionsParser::checkForNoLoadOption()
|
|||||||
if (nextToken(RequiredToken)) {
|
if (nextToken(RequiredToken)) {
|
||||||
if (m_currentArg == QLatin1String("all")) {
|
if (m_currentArg == QLatin1String("all")) {
|
||||||
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs))
|
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs))
|
||||||
spec->d->setForceDisabled(true);
|
spec->setForceDisabled(true);
|
||||||
m_isDependencyRefreshNeeded = true;
|
m_isDependencyRefreshNeeded = true;
|
||||||
} else {
|
} else {
|
||||||
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
|
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
|
||||||
@@ -211,10 +210,10 @@ bool OptionsParser::checkForNoLoadOption()
|
|||||||
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(m_currentArg);
|
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(m_currentArg);
|
||||||
m_hasError = true;
|
m_hasError = true;
|
||||||
} else {
|
} else {
|
||||||
spec->d->setForceDisabled(true);
|
spec->setForceDisabled(true);
|
||||||
// recursively disable all plugins that require this plugin
|
// recursively disable all plugins that require this plugin
|
||||||
for (PluginSpec *dependantSpec : PluginManager::pluginsRequiringPlugin(spec))
|
for (PluginSpec *dependantSpec : PluginManager::pluginsRequiringPlugin(spec))
|
||||||
dependantSpec->d->setForceDisabled(true);
|
dependantSpec->setForceDisabled(true);
|
||||||
m_isDependencyRefreshNeeded = true;
|
m_isDependencyRefreshNeeded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,10 +291,10 @@ bool OptionsParser::checkForUnknownOption()
|
|||||||
void OptionsParser::forceDisableAllPluginsExceptTestedAndForceEnabled()
|
void OptionsParser::forceDisableAllPluginsExceptTestedAndForceEnabled()
|
||||||
{
|
{
|
||||||
for (const PluginManagerPrivate::TestSpec &testSpec : m_pmPrivate->testSpecs)
|
for (const PluginManagerPrivate::TestSpec &testSpec : m_pmPrivate->testSpecs)
|
||||||
testSpec.pluginSpec->d->setForceEnabled(true);
|
testSpec.pluginSpec->setForceEnabled(true);
|
||||||
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs)) {
|
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs)) {
|
||||||
if (!spec->isForceEnabled() && !spec->isRequired())
|
if (!spec->isForceEnabled() && !spec->isRequired())
|
||||||
spec->d->setForceDisabled(true);
|
spec->setForceDisabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
#include "optionsparser.h"
|
#include "optionsparser.h"
|
||||||
#include "pluginmanager_p.h"
|
#include "pluginmanager_p.h"
|
||||||
#include "pluginspec.h"
|
#include "pluginspec.h"
|
||||||
#include "pluginspec_p.h"
|
|
||||||
|
|
||||||
#include <nanotrace/nanotrace.h>
|
#include <nanotrace/nanotrace.h>
|
||||||
|
|
||||||
@@ -35,6 +34,7 @@
|
|||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMetaProperty>
|
#include <QMetaProperty>
|
||||||
|
#include <QPluginLoader>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QScopeGuard>
|
#include <QScopeGuard>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
@@ -327,6 +327,11 @@ void PluginManager::loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins)
|
|||||||
d->loadPluginsAtRuntime(plugins);
|
d->loadPluginsAtRuntime(plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PluginManager::addPlugins(const QVector<PluginSpec *> &specs)
|
||||||
|
{
|
||||||
|
d->addPlugins(specs);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns \c true if any plugin has errors even though it is enabled.
|
Returns \c true if any plugin has errors even though it is enabled.
|
||||||
Most useful to call after loadPlugins().
|
Most useful to call after loadPlugins().
|
||||||
@@ -903,14 +908,6 @@ QVector<PluginSpec *> PluginManager::loadQueue()
|
|||||||
|
|
||||||
//============PluginManagerPrivate===========
|
//============PluginManagerPrivate===========
|
||||||
|
|
||||||
/*!
|
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
PluginSpec *PluginManagerPrivate::createSpec()
|
|
||||||
{
|
|
||||||
return new PluginSpec();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@@ -935,14 +932,6 @@ void PluginManagerPrivate::setGlobalSettings(QtcSettings *s)
|
|||||||
globalSettings->setParent(this);
|
globalSettings->setParent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec)
|
|
||||||
{
|
|
||||||
return spec->d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginManagerPrivate::startDelayedInitialize()
|
void PluginManagerPrivate::startDelayedInitialize()
|
||||||
{
|
{
|
||||||
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
|
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
|
||||||
@@ -954,8 +943,8 @@ void PluginManagerPrivate::startDelayedInitialize()
|
|||||||
delayedInitializeQueue.pop();
|
delayedInitializeQueue.pop();
|
||||||
NANOTRACE_SCOPE(specName, specName + "::delayedInitialized");
|
NANOTRACE_SCOPE(specName, specName + "::delayedInitialized");
|
||||||
profilingReport(">delayedInitialize", spec);
|
profilingReport(">delayedInitialize", spec);
|
||||||
bool delay = spec->d->delayedInitialize();
|
bool delay = spec->delayedInitialize();
|
||||||
profilingReport("<delayedInitialize", spec, &spec->d->performanceData.delayedInitialize);
|
profilingReport("<delayedInitialize", spec, &spec->performanceData().delayedInitialize);
|
||||||
if (delay) // give UI a bit of breathing space, but prevent user interaction
|
if (delay) // give UI a bit of breathing space, but prevent user interaction
|
||||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
}
|
}
|
||||||
@@ -1068,10 +1057,8 @@ void PluginManagerPrivate::checkForDuplicatePlugins()
|
|||||||
if (spec->isEffectivelyEnabled() && other->isEffectivelyEnabled()) {
|
if (spec->isEffectivelyEnabled() && other->isEffectivelyEnabled()) {
|
||||||
const QString error = Tr::tr(
|
const QString error = Tr::tr(
|
||||||
"Multiple versions of the same plugin have been found.");
|
"Multiple versions of the same plugin have been found.");
|
||||||
spec->d->hasError = true;
|
spec->setError(error);
|
||||||
spec->d->errorString = error;
|
other->setError(error);
|
||||||
other->d->hasError = true;
|
|
||||||
other->d->errorString = error;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
seen.insert(spec->name(), spec);
|
seen.insert(spec->name(), spec);
|
||||||
@@ -1403,7 +1390,7 @@ void PluginManagerPrivate::loadPlugins()
|
|||||||
delayedInitializeQueue.push(spec);
|
delayedInitializeQueue.push(spec);
|
||||||
} else {
|
} else {
|
||||||
// Plugin initialization failed, so cleanup after it
|
// Plugin initialization failed, so cleanup after it
|
||||||
spec->d->kill();
|
spec->kill();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1421,10 +1408,23 @@ void PluginManagerPrivate::loadPlugins()
|
|||||||
void PluginManagerPrivate::loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins)
|
void PluginManagerPrivate::loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins)
|
||||||
{
|
{
|
||||||
QTC_CHECK(allOf(plugins, [](PluginSpec *spec) { return spec->isSoftLoadable(); }));
|
QTC_CHECK(allOf(plugins, [](PluginSpec *spec) { return spec->isSoftLoadable(); }));
|
||||||
// load the plugins ordered by dependency
|
|
||||||
|
// load the plugins and their dependencies (if possible) ordered by dependency
|
||||||
const QList<PluginSpec *> queue = filtered(loadQueue(), [&plugins](PluginSpec *spec) {
|
const QList<PluginSpec *> queue = filtered(loadQueue(), [&plugins](PluginSpec *spec) {
|
||||||
return plugins.contains(spec);
|
// Is the current plugin already running, or not soft loadable?
|
||||||
|
if (spec->state() == PluginSpec::State::Running || !spec->isSoftLoadable())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Is the current plugin in the list of plugins to load?
|
||||||
|
if (plugins.contains(spec))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Is the current plugin a dependency of any of the plugins we want to load?
|
||||||
|
return plugins.contains(spec) || Utils::anyOf(plugins, [spec](PluginSpec *other) {
|
||||||
|
return other->requiresAny({spec});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
std::queue<PluginSpec *> localDelayedInitializeQueue;
|
std::queue<PluginSpec *> localDelayedInitializeQueue;
|
||||||
for (PluginSpec *spec : queue)
|
for (PluginSpec *spec : queue)
|
||||||
loadPlugin(spec, PluginSpec::Loaded);
|
loadPlugin(spec, PluginSpec::Loaded);
|
||||||
@@ -1434,12 +1434,12 @@ void PluginManagerPrivate::loadPluginsAtRuntime(const QSet<PluginSpec *> &plugin
|
|||||||
[this](PluginSpec *spec) { loadPlugin(spec, PluginSpec::Running); });
|
[this](PluginSpec *spec) { loadPlugin(spec, PluginSpec::Running); });
|
||||||
Utils::reverseForeach(queue, [](PluginSpec *spec) {
|
Utils::reverseForeach(queue, [](PluginSpec *spec) {
|
||||||
if (spec->state() == PluginSpec::Running) {
|
if (spec->state() == PluginSpec::Running) {
|
||||||
const bool delay = spec->d->delayedInitialize();
|
const bool delay = spec->delayedInitialize();
|
||||||
if (delay)
|
if (delay)
|
||||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
} else {
|
} else {
|
||||||
// Plugin initialization failed, so cleanup after it
|
// Plugin initialization failed, so cleanup after it
|
||||||
spec->d->kill();
|
spec->kill();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
emit q->pluginsChanged();
|
emit q->pluginsChanged();
|
||||||
@@ -1494,17 +1494,17 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec,
|
|||||||
return true;
|
return true;
|
||||||
// check for circular dependencies
|
// check for circular dependencies
|
||||||
if (circularityCheckQueue.contains(spec)) {
|
if (circularityCheckQueue.contains(spec)) {
|
||||||
spec->d->hasError = true;
|
QString errorString = Tr::tr("Circular dependency detected:");
|
||||||
spec->d->errorString = Tr::tr("Circular dependency detected:");
|
errorString += QLatin1Char('\n');
|
||||||
spec->d->errorString += QLatin1Char('\n');
|
|
||||||
int index = circularityCheckQueue.indexOf(spec);
|
int index = circularityCheckQueue.indexOf(spec);
|
||||||
for (int i = index; i < circularityCheckQueue.size(); ++i) {
|
for (int i = index; i < circularityCheckQueue.size(); ++i) {
|
||||||
const PluginSpec *depSpec = circularityCheckQueue.at(i);
|
const PluginSpec *depSpec = circularityCheckQueue.at(i);
|
||||||
spec->d->errorString.append(Tr::tr("%1 (%2) depends on")
|
errorString.append(
|
||||||
.arg(depSpec->name(), depSpec->version()));
|
Tr::tr("%1 (%2) depends on").arg(depSpec->name(), depSpec->version()));
|
||||||
spec->d->errorString += QLatin1Char('\n');
|
errorString += QLatin1Char('\n');
|
||||||
}
|
}
|
||||||
spec->d->errorString.append(Tr::tr("%1 (%2)").arg(spec->name(), spec->version()));
|
errorString.append(Tr::tr("%1 (%2)").arg(spec->name(), spec->version()));
|
||||||
|
spec->setError(errorString);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
circularityCheckQueue.append(spec);
|
circularityCheckQueue.append(spec);
|
||||||
@@ -1523,10 +1523,9 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec,
|
|||||||
continue;
|
continue;
|
||||||
PluginSpec *depSpec = it.value();
|
PluginSpec *depSpec = it.value();
|
||||||
if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
|
if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
|
||||||
spec->d->hasError = true;
|
spec->setError(
|
||||||
spec->d->errorString =
|
|
||||||
Tr::tr("Cannot load plugin because dependency failed to load: %1 (%2)\nReason: %3")
|
Tr::tr("Cannot load plugin because dependency failed to load: %1 (%2)\nReason: %3")
|
||||||
.arg(depSpec->name(), depSpec->version(), depSpec->errorString());
|
.arg(depSpec->name(), depSpec->version(), depSpec->errorString()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1619,9 +1618,9 @@ void PluginManagerPrivate::checkForProblematicPlugins()
|
|||||||
dialog.addButton(Tr::tr("Continue"), QMessageBox::RejectRole);
|
dialog.addButton(Tr::tr("Continue"), QMessageBox::RejectRole);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
if (dialog.clickedButton() == disableButton) {
|
if (dialog.clickedButton() == disableButton) {
|
||||||
spec->d->setForceDisabled(true);
|
spec->setForceDisabled(true);
|
||||||
for (PluginSpec *other : dependents)
|
for (PluginSpec *other : dependents)
|
||||||
other->d->setForceDisabled(true);
|
other->setForceDisabled(true);
|
||||||
enableDependenciesIndirectly();
|
enableDependenciesIndirectly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1664,15 +1663,15 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
|||||||
case PluginSpec::Running: {
|
case PluginSpec::Running: {
|
||||||
NANOTRACE_SCOPE(specName, specName + "::extensionsInitialized");
|
NANOTRACE_SCOPE(specName, specName + "::extensionsInitialized");
|
||||||
profilingReport(">initializeExtensions", spec);
|
profilingReport(">initializeExtensions", spec);
|
||||||
spec->d->initializeExtensions();
|
spec->initializeExtensions();
|
||||||
profilingReport("<initializeExtensions",
|
profilingReport("<initializeExtensions",
|
||||||
spec,
|
spec,
|
||||||
&spec->d->performanceData.extensionsInitialized);
|
&spec->performanceData().extensionsInitialized);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case PluginSpec::Deleted:
|
case PluginSpec::Deleted:
|
||||||
profilingReport(">delete", spec);
|
profilingReport(">delete", spec);
|
||||||
spec->d->kill();
|
spec->kill();
|
||||||
profilingReport("<delete", spec);
|
profilingReport("<delete", spec);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
@@ -1686,10 +1685,10 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
|||||||
continue;
|
continue;
|
||||||
PluginSpec *depSpec = it.value();
|
PluginSpec *depSpec = it.value();
|
||||||
if (depSpec->state() != destState) {
|
if (depSpec->state() != destState) {
|
||||||
spec->d->hasError = true;
|
spec->setError(
|
||||||
spec->d->errorString =
|
Tr::tr(
|
||||||
Tr::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
|
"Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
|
||||||
.arg(depSpec->name(), depSpec->version(), depSpec->errorString());
|
.arg(depSpec->name(), depSpec->version(), depSpec->errorString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1698,20 +1697,20 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
|||||||
case PluginSpec::Loaded: {
|
case PluginSpec::Loaded: {
|
||||||
NANOTRACE_SCOPE(specName, specName + "::load");
|
NANOTRACE_SCOPE(specName, specName + "::load");
|
||||||
profilingReport(">loadLibrary", spec);
|
profilingReport(">loadLibrary", spec);
|
||||||
spec->d->loadLibrary();
|
spec->loadLibrary();
|
||||||
profilingReport("<loadLibrary", spec, &spec->d->performanceData.load);
|
profilingReport("<loadLibrary", spec, &spec->performanceData().load);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PluginSpec::Initialized: {
|
case PluginSpec::Initialized: {
|
||||||
NANOTRACE_SCOPE(specName, specName + "::initialize");
|
NANOTRACE_SCOPE(specName, specName + "::initialize");
|
||||||
profilingReport(">initializePlugin", spec);
|
profilingReport(">initializePlugin", spec);
|
||||||
spec->d->initializePlugin();
|
spec->initializePlugin();
|
||||||
profilingReport("<initializePlugin", spec, &spec->d->performanceData.initialize);
|
profilingReport("<initializePlugin", spec, &spec->performanceData().initialize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PluginSpec::Stopped:
|
case PluginSpec::Stopped:
|
||||||
profilingReport(">stop", spec);
|
profilingReport(">stop", spec);
|
||||||
if (spec->d->stop() == IPlugin::AsynchronousShutdown) {
|
if (spec->stop() == IPlugin::AsynchronousShutdown) {
|
||||||
asynchronousPlugins << spec;
|
asynchronousPlugins << spec;
|
||||||
connect(spec->plugin(), &IPlugin::asynchronousShutdownFinished, this, [this, spec] {
|
connect(spec->plugin(), &IPlugin::asynchronousShutdownFinished, this, [this, spec] {
|
||||||
asynchronousPlugins.remove(spec);
|
asynchronousPlugins.remove(spec);
|
||||||
@@ -1753,45 +1752,24 @@ static const QStringList pluginFiles(const QStringList &pluginPaths)
|
|||||||
return pluginFiles;
|
return pluginFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
void PluginManagerPrivate::addPlugins(const QVector<PluginSpec *> &specs)
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
void PluginManagerPrivate::readPluginPaths()
|
|
||||||
{
|
{
|
||||||
qDeleteAll(pluginSpecs);
|
pluginSpecs += specs;
|
||||||
pluginSpecs.clear();
|
|
||||||
pluginCategories.clear();
|
|
||||||
|
|
||||||
// default
|
for (PluginSpec *spec : specs) {
|
||||||
pluginCategories.insert(QString(), QVector<PluginSpec *>());
|
|
||||||
|
|
||||||
// from the file system
|
|
||||||
for (const QString &pluginFile : pluginFiles(pluginPaths)) {
|
|
||||||
PluginSpec *spec = PluginSpec::read(pluginFile);
|
|
||||||
if (spec) // Qt Creator plugin
|
|
||||||
pluginSpecs.append(spec);
|
|
||||||
}
|
|
||||||
// static
|
|
||||||
for (const QStaticPlugin &plugin : QPluginLoader::staticPlugins()) {
|
|
||||||
PluginSpec *spec = PluginSpec::read(plugin);
|
|
||||||
if (spec) // Qt Creator plugin
|
|
||||||
pluginSpecs.append(spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PluginSpec *spec : pluginSpecs) {
|
|
||||||
// defaultDisabledPlugins and defaultEnabledPlugins from install settings
|
// defaultDisabledPlugins and defaultEnabledPlugins from install settings
|
||||||
// is used to override the defaults read from the plugin spec
|
// is used to override the defaults read from the plugin spec
|
||||||
if (spec->isEnabledByDefault() && defaultDisabledPlugins.contains(spec->name())) {
|
if (spec->isEnabledByDefault() && defaultDisabledPlugins.contains(spec->name())) {
|
||||||
spec->d->setEnabledByDefault(false);
|
spec->setEnabledByDefault(false);
|
||||||
spec->d->setEnabledBySettings(false);
|
spec->setEnabledBySettings(false);
|
||||||
} else if (!spec->isEnabledByDefault() && defaultEnabledPlugins.contains(spec->name())) {
|
} else if (!spec->isEnabledByDefault() && defaultEnabledPlugins.contains(spec->name())) {
|
||||||
spec->d->setEnabledByDefault(true);
|
spec->setEnabledByDefault(true);
|
||||||
spec->d->setEnabledBySettings(true);
|
spec->setEnabledBySettings(true);
|
||||||
}
|
}
|
||||||
if (!spec->isEnabledByDefault() && forceEnabledPlugins.contains(spec->name()))
|
if (!spec->isEnabledByDefault() && forceEnabledPlugins.contains(spec->name()))
|
||||||
spec->d->setEnabledBySettings(true);
|
spec->setEnabledBySettings(true);
|
||||||
if (spec->isEnabledByDefault() && disabledPlugins.contains(spec->name()))
|
if (spec->isEnabledByDefault() && disabledPlugins.contains(spec->name()))
|
||||||
spec->d->setEnabledBySettings(false);
|
spec->setEnabledBySettings(false);
|
||||||
|
|
||||||
pluginCategories[spec->category()].append(spec);
|
pluginCategories[spec->category()].append(spec);
|
||||||
}
|
}
|
||||||
@@ -1803,21 +1781,49 @@ void PluginManagerPrivate::readPluginPaths()
|
|||||||
emit q->pluginsChanged();
|
emit q->pluginsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
void PluginManagerPrivate::readPluginPaths()
|
||||||
|
{
|
||||||
|
QVector<PluginSpec *> newSpecs;
|
||||||
|
|
||||||
|
// from the file system
|
||||||
|
for (const QString &pluginFile : pluginFiles(pluginPaths)) {
|
||||||
|
expected_str<PluginSpec *> spec = PluginSpecImpl::read(pluginFile);
|
||||||
|
if (!spec) {
|
||||||
|
qCWarning(pluginLog).noquote()
|
||||||
|
<< QString("Ignoring plugin \"%1\" because: %2").arg(pluginFile).arg(spec.error());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
newSpecs.append(*spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
for (const QStaticPlugin &plugin : QPluginLoader::staticPlugins()) {
|
||||||
|
expected_str<PluginSpec *> spec = PluginSpecImpl::read(plugin);
|
||||||
|
QTC_ASSERT_EXPECTED(spec, continue);
|
||||||
|
newSpecs.append(*spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPlugins(newSpecs);
|
||||||
|
}
|
||||||
|
|
||||||
void PluginManagerPrivate::resolveDependencies()
|
void PluginManagerPrivate::resolveDependencies()
|
||||||
{
|
{
|
||||||
for (PluginSpec *spec : std::as_const(pluginSpecs))
|
for (PluginSpec *spec : std::as_const(pluginSpecs))
|
||||||
spec->d->resolveDependencies(pluginSpecs);
|
spec->resolveDependencies(pluginSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginManagerPrivate::enableDependenciesIndirectly()
|
void PluginManagerPrivate::enableDependenciesIndirectly()
|
||||||
{
|
{
|
||||||
for (PluginSpec *spec : std::as_const(pluginSpecs))
|
for (PluginSpec *spec : std::as_const(pluginSpecs))
|
||||||
spec->d->enabledIndirectly = false;
|
spec->setEnabledIndirectly(false);
|
||||||
// cannot use reverse loadQueue here, because test dependencies can introduce circles
|
// cannot use reverse loadQueue here, because test dependencies can introduce circles
|
||||||
QVector<PluginSpec *> queue = Utils::filtered(pluginSpecs, &PluginSpec::isEffectivelyEnabled);
|
QVector<PluginSpec *> queue = Utils::filtered(pluginSpecs, &PluginSpec::isEffectivelyEnabled);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
PluginSpec *spec = queue.takeFirst();
|
PluginSpec *spec = queue.takeFirst();
|
||||||
queue += spec->d->enableDependenciesIndirectly(containsTestSpec(spec));
|
queue += spec->enableDependenciesIndirectly(containsTestSpec(spec));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -82,6 +82,8 @@ public:
|
|||||||
static void checkForProblematicPlugins();
|
static void checkForProblematicPlugins();
|
||||||
static PluginSpec *specForPlugin(IPlugin *plugin);
|
static PluginSpec *specForPlugin(IPlugin *plugin);
|
||||||
|
|
||||||
|
static void addPlugins(const QVector<PluginSpec *> &specs);
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
static void setSettings(Utils::QtcSettings *settings);
|
static void setSettings(Utils::QtcSettings *settings);
|
||||||
static Utils::QtcSettings *settings();
|
static Utils::QtcSettings *settings();
|
||||||
|
@@ -36,8 +36,6 @@ class PluginManager;
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class PluginSpecPrivate;
|
|
||||||
|
|
||||||
class EXTENSIONSYSTEM_TEST_EXPORT PluginManagerPrivate : public QObject
|
class EXTENSIONSYSTEM_TEST_EXPORT PluginManagerPrivate : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -52,6 +50,8 @@ public:
|
|||||||
void checkForProblematicPlugins();
|
void checkForProblematicPlugins();
|
||||||
void loadPlugins();
|
void loadPlugins();
|
||||||
void loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins);
|
void loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins);
|
||||||
|
void addPlugins(const QVector<PluginSpec *> &specs);
|
||||||
|
|
||||||
void shutdown();
|
void shutdown();
|
||||||
void setPluginPaths(const QStringList &paths);
|
void setPluginPaths(const QStringList &paths);
|
||||||
const QVector<ExtensionSystem::PluginSpec *> loadQueue();
|
const QVector<ExtensionSystem::PluginSpec *> loadQueue();
|
||||||
@@ -119,10 +119,6 @@ public:
|
|||||||
PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
|
PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
|
||||||
PluginSpec *pluginByName(const QString &name) const;
|
PluginSpec *pluginByName(const QString &name) const;
|
||||||
|
|
||||||
// used by tests
|
|
||||||
static PluginSpec *createSpec();
|
|
||||||
static PluginSpecPrivate *privateSpec(PluginSpec *spec);
|
|
||||||
|
|
||||||
static void addTestCreator(IPlugin *plugin, const std::function<QObject *()> &testCreator);
|
static void addTestCreator(IPlugin *plugin, const std::function<QObject *()> &testCreator);
|
||||||
|
|
||||||
mutable QReadWriteLock m_lock;
|
mutable QReadWriteLock m_lock;
|
||||||
|
@@ -6,7 +6,6 @@
|
|||||||
#include "extensionsystemtr.h"
|
#include "extensionsystemtr.h"
|
||||||
#include "iplugin.h"
|
#include "iplugin.h"
|
||||||
#include "pluginmanager.h"
|
#include "pluginmanager.h"
|
||||||
#include "pluginspec_p.h"
|
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
@@ -25,6 +24,7 @@
|
|||||||
#include <QPluginLoader>
|
#include <QPluginLoader>
|
||||||
|
|
||||||
using namespace ExtensionSystem::Internal;
|
using namespace ExtensionSystem::Internal;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ExtensionSystem {
|
namespace ExtensionSystem {
|
||||||
|
|
||||||
@@ -168,22 +168,78 @@ QString PluginDependency::toString() const
|
|||||||
return name + " (" + version + typeString(type) + ")";
|
return name + " (" + version + typeString(type) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
namespace Internal {
|
||||||
\internal
|
class PluginSpecImplPrivate
|
||||||
*/
|
|
||||||
PluginSpec::PluginSpec()
|
|
||||||
: d(new PluginSpecPrivate(this))
|
|
||||||
{
|
{
|
||||||
}
|
public:
|
||||||
|
std::optional<QPluginLoader> loader;
|
||||||
|
std::optional<QStaticPlugin> staticPlugin;
|
||||||
|
|
||||||
|
IPlugin *plugin;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PluginSpecPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExtensionSystem::PerformanceData performanceData;
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
QString version;
|
||||||
|
QString compatVersion;
|
||||||
|
QString vendor;
|
||||||
|
QString category;
|
||||||
|
QString description;
|
||||||
|
QString longDescription;
|
||||||
|
QString url;
|
||||||
|
QString license;
|
||||||
|
QString revision;
|
||||||
|
QString copyright;
|
||||||
|
QStringList arguments;
|
||||||
|
QRegularExpression platformSpecification;
|
||||||
|
QVector<ExtensionSystem::PluginDependency> dependencies;
|
||||||
|
|
||||||
|
PluginSpecImpl::PluginArgumentDescriptions argumentDescriptions;
|
||||||
|
QString location;
|
||||||
|
QString filePath;
|
||||||
|
|
||||||
|
bool experimental{false};
|
||||||
|
bool deprecated{false};
|
||||||
|
bool required{false};
|
||||||
|
|
||||||
|
bool enabledByDefault{false};
|
||||||
|
bool enabledBySettings{true};
|
||||||
|
bool enabledIndirectly{false};
|
||||||
|
bool forceEnabled{false};
|
||||||
|
bool forceDisabled{false};
|
||||||
|
bool softLoadable{false};
|
||||||
|
|
||||||
|
std::optional<QString> errorString;
|
||||||
|
|
||||||
|
PluginSpec::State state;
|
||||||
|
QHash<PluginDependency, PluginSpec *> dependencySpecs;
|
||||||
|
|
||||||
|
QJsonObject metaData;
|
||||||
|
|
||||||
|
Utils::expected_str<void> readMetaData(const QJsonObject &metaData);
|
||||||
|
Utils::expected_str<void> reportError(const QString &error)
|
||||||
|
{
|
||||||
|
errorString = error;
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
PluginSpec::~PluginSpec()
|
PluginSpecImpl::PluginSpecImpl()
|
||||||
{
|
: d(new PluginSpecImplPrivate)
|
||||||
delete d;
|
{}
|
||||||
d = nullptr;
|
|
||||||
}
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
PluginSpecImpl::~PluginSpecImpl() = default;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the plugin name. This is valid after the PluginSpec::Read state is
|
Returns the plugin name. This is valid after the PluginSpec::Read state is
|
||||||
@@ -278,10 +334,7 @@ QString PluginSpec::category() const
|
|||||||
|
|
||||||
QString PluginSpec::revision() const
|
QString PluginSpec::revision() const
|
||||||
{
|
{
|
||||||
const QJsonValue revision = metaData().value("Revision");
|
return d->revision;
|
||||||
if (revision.isString())
|
|
||||||
return revision.toString();
|
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -419,7 +472,7 @@ QJsonObject PluginSpec::metaData() const
|
|||||||
return d->metaData;
|
return d->metaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PerformanceData &PluginSpec::performanceData() const
|
PerformanceData &PluginSpec::performanceData() const
|
||||||
{
|
{
|
||||||
return d->performanceData;
|
return d->performanceData;
|
||||||
}
|
}
|
||||||
@@ -491,7 +544,7 @@ PluginSpec::State PluginSpec::state() const
|
|||||||
*/
|
*/
|
||||||
bool PluginSpec::hasError() const
|
bool PluginSpec::hasError() const
|
||||||
{
|
{
|
||||||
return d->hasError;
|
return d->errorString.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -500,7 +553,7 @@ bool PluginSpec::hasError() const
|
|||||||
*/
|
*/
|
||||||
QString PluginSpec::errorString() const
|
QString PluginSpec::errorString() const
|
||||||
{
|
{
|
||||||
return d->errorString;
|
return d->errorString.value_or(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -509,9 +562,13 @@ QString PluginSpec::errorString() const
|
|||||||
|
|
||||||
\sa PluginSpec::dependencies()
|
\sa PluginSpec::dependencies()
|
||||||
*/
|
*/
|
||||||
bool PluginSpec::provides(const QString &pluginName, const QString &version) const
|
bool PluginSpec::provides(const QString &pluginName, const QString &pluginVersion) const
|
||||||
{
|
{
|
||||||
return d->provides(pluginName, version);
|
if (QString::compare(pluginName, name(), Qt::CaseInsensitive) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (versionCompare(version(), pluginVersion) >= 0)
|
||||||
|
&& (versionCompare(compatVersion(), pluginVersion) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -519,7 +576,7 @@ bool PluginSpec::provides(const QString &pluginName, const QString &version) con
|
|||||||
already been successfully loaded. That is, the PluginSpec::Loaded state
|
already been successfully loaded. That is, the PluginSpec::Loaded state
|
||||||
is reached.
|
is reached.
|
||||||
*/
|
*/
|
||||||
IPlugin *PluginSpec::plugin() const
|
IPlugin *PluginSpecImpl::plugin() const
|
||||||
{
|
{
|
||||||
return d->plugin;
|
return d->plugin;
|
||||||
}
|
}
|
||||||
@@ -548,6 +605,11 @@ bool PluginSpec::requiresAny(const QSet<PluginSpec *> &plugins) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PluginSpec::setEnabledByDefault(bool value)
|
||||||
|
{
|
||||||
|
d->enabledByDefault = value;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the plugin should be loaded at startup to \a value.
|
Sets whether the plugin should be loaded at startup to \a value.
|
||||||
|
|
||||||
@@ -555,27 +617,40 @@ bool PluginSpec::requiresAny(const QSet<PluginSpec *> &plugins) const
|
|||||||
*/
|
*/
|
||||||
void PluginSpec::setEnabledBySettings(bool value)
|
void PluginSpec::setEnabledBySettings(bool value)
|
||||||
{
|
{
|
||||||
d->setEnabledBySettings(value);
|
d->enabledBySettings = value;
|
||||||
|
}
|
||||||
|
void PluginSpec::setEnabledIndirectly(bool value)
|
||||||
|
{
|
||||||
|
d->enabledIndirectly = value;
|
||||||
|
}
|
||||||
|
void PluginSpec::setForceDisabled(bool value)
|
||||||
|
{
|
||||||
|
d->forceDisabled = value;
|
||||||
|
}
|
||||||
|
void PluginSpec::setForceEnabled(bool value)
|
||||||
|
{
|
||||||
|
d->forceEnabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginSpec *PluginSpec::read(const QString &filePath)
|
// returns the plugins that it actually indirectly enabled
|
||||||
|
QVector<PluginSpec *> PluginSpec::enableDependenciesIndirectly(bool enableTestDependencies)
|
||||||
{
|
{
|
||||||
auto spec = new PluginSpec;
|
if (!isEffectivelyEnabled()) // plugin not enabled, nothing to do
|
||||||
if (!spec->d->read(filePath)) { // not a Qt Creator plugin
|
return {};
|
||||||
delete spec;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return spec;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginSpec *PluginSpec::read(const QStaticPlugin &plugin)
|
QVector<PluginSpec *> enabled;
|
||||||
{
|
for (auto it = d->dependencySpecs.cbegin(), end = d->dependencySpecs.cend(); it != end; ++it) {
|
||||||
auto spec = new PluginSpec;
|
if (it.key().type != PluginDependency::Required
|
||||||
if (!spec->d->read(plugin)) { // not a Qt Creator plugin
|
&& (!enableTestDependencies || it.key().type != PluginDependency::Test))
|
||||||
delete spec;
|
continue;
|
||||||
return nullptr;
|
|
||||||
|
PluginSpec *dependencySpec = it.value();
|
||||||
|
if (!dependencySpec->isEffectivelyEnabled()) {
|
||||||
|
dependencySpec->setEnabledIndirectly(true);
|
||||||
|
enabled << dependencySpec;
|
||||||
}
|
}
|
||||||
return spec;
|
}
|
||||||
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========PluginSpecPrivate==================
|
//==========PluginSpecPrivate==================
|
||||||
@@ -610,112 +685,45 @@ namespace {
|
|||||||
const char ARGUMENT_PARAMETER[] = "Parameter";
|
const char ARGUMENT_PARAMETER[] = "Parameter";
|
||||||
const char ARGUMENT_DESCRIPTION[] = "Description";
|
const char ARGUMENT_DESCRIPTION[] = "Description";
|
||||||
}
|
}
|
||||||
/*!
|
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
|
|
||||||
: q(spec)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void PluginSpecPrivate::reset()
|
|
||||||
{
|
|
||||||
name.clear();
|
|
||||||
version.clear();
|
|
||||||
compatVersion.clear();
|
|
||||||
vendor.clear();
|
|
||||||
copyright.clear();
|
|
||||||
license.clear();
|
|
||||||
description.clear();
|
|
||||||
longDescription.clear();
|
|
||||||
url.clear();
|
|
||||||
category.clear();
|
|
||||||
location.clear();
|
|
||||||
filePath.clear();
|
|
||||||
state = PluginSpec::Invalid;
|
|
||||||
hasError = false;
|
|
||||||
errorString.clear();
|
|
||||||
dependencies.clear();
|
|
||||||
metaData = QJsonObject();
|
|
||||||
loader.reset();
|
|
||||||
staticPlugin.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
Returns false if the file does not represent a Qt Creator plugin.
|
Returns false if the file does not represent a Qt Creator plugin.
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::read(const QString &fileName)
|
expected_str<PluginSpec *> PluginSpecImpl::read(const QString &fileName)
|
||||||
{
|
{
|
||||||
qCDebug(pluginLog) << "\nReading meta data of" << fileName;
|
auto spec = new PluginSpecImpl;
|
||||||
reset();
|
|
||||||
QFileInfo fileInfo(fileName);
|
QFileInfo fileInfo(fileName);
|
||||||
location = fileInfo.absolutePath();
|
spec->setLocation(fileInfo.absolutePath());
|
||||||
filePath = fileInfo.absoluteFilePath();
|
spec->setFilePath(fileInfo.absoluteFilePath());
|
||||||
loader.emplace();
|
spec->d->loader.emplace();
|
||||||
|
|
||||||
if (Utils::HostOsInfo::isMacHost())
|
if (Utils::HostOsInfo::isMacHost())
|
||||||
loader->setLoadHints(QLibrary::ExportExternalSymbolsHint);
|
spec->d->loader->setLoadHints(QLibrary::ExportExternalSymbolsHint);
|
||||||
loader->setFileName(filePath);
|
|
||||||
if (loader->fileName().isEmpty()) {
|
|
||||||
qCDebug(pluginLog) << "Cannot open file";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!readMetaData(loader->metaData()))
|
spec->d->loader->setFileName(fileInfo.absoluteFilePath());
|
||||||
return false;
|
if (spec->d->loader->fileName().isEmpty())
|
||||||
|
return make_unexpected(::ExtensionSystem::Tr::tr("Cannot open file"));
|
||||||
|
|
||||||
state = PluginSpec::Read;
|
expected_str<void> r = spec->readMetaData(spec->d->loader->metaData());
|
||||||
return true;
|
if (!r)
|
||||||
|
return make_unexpected(r.error());
|
||||||
|
|
||||||
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PluginSpecPrivate::read(const QStaticPlugin &plugin)
|
expected_str<PluginSpec *> PluginSpecImpl::read(const QStaticPlugin &plugin)
|
||||||
{
|
{
|
||||||
|
auto spec = new PluginSpecImpl;
|
||||||
|
|
||||||
qCDebug(pluginLog) << "\nReading meta data of static plugin";
|
qCDebug(pluginLog) << "\nReading meta data of static plugin";
|
||||||
reset();
|
spec->d->staticPlugin = plugin;
|
||||||
staticPlugin = plugin;
|
expected_str<void> r = spec->readMetaData(plugin.metaData());
|
||||||
if (!readMetaData(plugin.metaData()))
|
if (!r)
|
||||||
return false;
|
return make_unexpected(r.error());
|
||||||
|
|
||||||
state = PluginSpec::Read;
|
return spec;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginSpecPrivate::setEnabledBySettings(bool value)
|
|
||||||
{
|
|
||||||
enabledBySettings = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginSpecPrivate::setEnabledByDefault(bool value)
|
|
||||||
{
|
|
||||||
enabledByDefault = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginSpecPrivate::setForceEnabled(bool value)
|
|
||||||
{
|
|
||||||
forceEnabled = value;
|
|
||||||
if (value)
|
|
||||||
forceDisabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginSpecPrivate::setForceDisabled(bool value)
|
|
||||||
{
|
|
||||||
if (value)
|
|
||||||
forceEnabled = false;
|
|
||||||
forceDisabled = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginSpecPrivate::setSoftLoadable(bool value)
|
|
||||||
{
|
|
||||||
softLoadable = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
bool PluginSpecPrivate::reportError(const QString &err)
|
|
||||||
{
|
|
||||||
errorString = err;
|
|
||||||
hasError = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString msgValueMissing(const char *key)
|
static inline QString msgValueMissing(const char *key)
|
||||||
@@ -725,20 +733,17 @@ static inline QString msgValueMissing(const char *key)
|
|||||||
|
|
||||||
static inline QString msgValueIsNotAString(const char *key)
|
static inline QString msgValueIsNotAString(const char *key)
|
||||||
{
|
{
|
||||||
return Tr::tr("Value for key \"%1\" is not a string")
|
return Tr::tr("Value for key \"%1\" is not a string").arg(QLatin1String(key));
|
||||||
.arg(QLatin1String(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString msgValueIsNotABool(const char *key)
|
static inline QString msgValueIsNotABool(const char *key)
|
||||||
{
|
{
|
||||||
return Tr::tr("Value for key \"%1\" is not a bool")
|
return Tr::tr("Value for key \"%1\" is not a bool").arg(QLatin1String(key));
|
||||||
.arg(QLatin1String(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString msgValueIsNotAObjectArray(const char *key)
|
static inline QString msgValueIsNotAObjectArray(const char *key)
|
||||||
{
|
{
|
||||||
return Tr::tr("Value for key \"%1\" is not an array of objects")
|
return Tr::tr("Value for key \"%1\" is not an array of objects").arg(QLatin1String(key));
|
||||||
.arg(QLatin1String(key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QString msgValueIsNotAMultilineString(const char *key)
|
static inline QString msgValueIsNotAMultilineString(const char *key)
|
||||||
@@ -749,34 +754,46 @@ static inline QString msgValueIsNotAMultilineString(const char *key)
|
|||||||
|
|
||||||
static inline QString msgInvalidFormat(const char *key, const QString &content)
|
static inline QString msgInvalidFormat(const char *key, const QString &content)
|
||||||
{
|
{
|
||||||
return Tr::tr("Value \"%2\" for key \"%1\" has invalid format")
|
return Tr::tr("Value \"%2\" for key \"%1\" has invalid format").arg(QLatin1String(key), content);
|
||||||
.arg(QLatin1String(key), content);
|
}
|
||||||
|
|
||||||
|
Utils::expected_str<void> PluginSpec::readMetaData(const QJsonObject &metaData)
|
||||||
|
{
|
||||||
|
return d->readMetaData(metaData);
|
||||||
|
}
|
||||||
|
Utils::expected_str<void> PluginSpec::reportError(const QString &error)
|
||||||
|
{
|
||||||
|
return d->reportError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
|
expected_str<void> PluginSpecImpl::readMetaData(const QJsonObject &pluginMetaData)
|
||||||
{
|
{
|
||||||
qCDebug(pluginLog) << "MetaData:" << QJsonDocument(pluginMetaData).toJson();
|
qCDebug(pluginLog).noquote() << "MetaData:" << QJsonDocument(pluginMetaData).toJson();
|
||||||
QJsonValue value;
|
QJsonValue value;
|
||||||
value = pluginMetaData.value(QLatin1String("IID"));
|
value = pluginMetaData.value(QLatin1String("IID"));
|
||||||
if (!value.isString()) {
|
if (!value.isString())
|
||||||
qCDebug(pluginLog) << "Not a plugin (no string IID found)";
|
return make_unexpected(::ExtensionSystem::Tr::tr("No IID found"));
|
||||||
return false;
|
|
||||||
}
|
if (value.toString() != PluginManager::pluginIID())
|
||||||
if (value.toString() != PluginManager::pluginIID()) {
|
return make_unexpected(::ExtensionSystem::Tr::tr("Expected IID \"%1\", but found \"%2\"")
|
||||||
qCDebug(pluginLog) << "Plugin ignored (IID does not match)";
|
.arg(PluginManager::pluginIID())
|
||||||
return false;
|
.arg(value.toString()));
|
||||||
}
|
|
||||||
|
|
||||||
value = pluginMetaData.value(QLatin1String(PLUGIN_METADATA));
|
value = pluginMetaData.value(QLatin1String(PLUGIN_METADATA));
|
||||||
if (!value.isObject()) {
|
if (!value.isObject())
|
||||||
return reportError(::ExtensionSystem::Tr::tr("Plugin meta data not found"));
|
return reportError(::ExtensionSystem::Tr::tr("Plugin meta data not found"));
|
||||||
}
|
|
||||||
metaData = value.toObject();
|
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(PLUGIN_NAME));
|
return PluginSpec::readMetaData(value.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::expected_str<void> PluginSpecPrivate::readMetaData(const QJsonObject &data)
|
||||||
|
{
|
||||||
|
metaData = data;
|
||||||
|
|
||||||
|
QJsonValue value = metaData.value(QLatin1String(PLUGIN_NAME));
|
||||||
if (value.isUndefined())
|
if (value.isUndefined())
|
||||||
return reportError(msgValueMissing(PLUGIN_NAME));
|
return reportError(msgValueMissing(PLUGIN_NAME));
|
||||||
if (!value.isString())
|
if (!value.isString())
|
||||||
@@ -789,14 +806,14 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
|
|||||||
if (!value.isString())
|
if (!value.isString())
|
||||||
return reportError(msgValueIsNotAString(PLUGIN_VERSION));
|
return reportError(msgValueIsNotAString(PLUGIN_VERSION));
|
||||||
version = value.toString();
|
version = value.toString();
|
||||||
if (!isValidVersion(version))
|
if (!PluginSpec::isValidVersion(version))
|
||||||
return reportError(msgInvalidFormat(PLUGIN_VERSION, version));
|
return reportError(msgInvalidFormat(PLUGIN_VERSION, version));
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(PLUGIN_COMPATVERSION));
|
value = metaData.value(QLatin1String(PLUGIN_COMPATVERSION));
|
||||||
if (!value.isUndefined() && !value.isString())
|
if (!value.isUndefined() && !value.isString())
|
||||||
return reportError(msgValueIsNotAString(PLUGIN_COMPATVERSION));
|
return reportError(msgValueIsNotAString(PLUGIN_COMPATVERSION));
|
||||||
compatVersion = value.toString(version);
|
compatVersion = value.toString(version);
|
||||||
if (!value.isUndefined() && !isValidVersion(compatVersion))
|
if (!value.isUndefined() && !PluginSpec::isValidVersion(compatVersion))
|
||||||
return reportError(msgInvalidFormat(PLUGIN_COMPATVERSION, compatVersion));
|
return reportError(msgInvalidFormat(PLUGIN_COMPATVERSION, compatVersion));
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(PLUGIN_REQUIRED));
|
value = metaData.value(QLatin1String(PLUGIN_REQUIRED));
|
||||||
@@ -844,11 +861,11 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
|
|||||||
copyright = value.toString();
|
copyright = value.toString();
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(DESCRIPTION));
|
value = metaData.value(QLatin1String(DESCRIPTION));
|
||||||
if (!value.isUndefined() && !Utils::readMultiLineString(value, &description))
|
if (!value.isUndefined() && !readMultiLineString(value, &description))
|
||||||
return reportError(msgValueIsNotAString(DESCRIPTION));
|
return reportError(msgValueIsNotAString(DESCRIPTION));
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(LONGDESCRIPTION));
|
value = metaData.value(QLatin1String(LONGDESCRIPTION));
|
||||||
if (!value.isUndefined() && !Utils::readMultiLineString(value, &longDescription))
|
if (!value.isUndefined() && !readMultiLineString(value, &longDescription))
|
||||||
return reportError(msgValueIsNotAString(LONGDESCRIPTION));
|
return reportError(msgValueIsNotAString(LONGDESCRIPTION));
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(URL));
|
value = metaData.value(QLatin1String(URL));
|
||||||
@@ -862,9 +879,14 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
|
|||||||
category = value.toString();
|
category = value.toString();
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(LICENSE));
|
value = metaData.value(QLatin1String(LICENSE));
|
||||||
if (!value.isUndefined() && !Utils::readMultiLineString(value, &license))
|
if (!value.isUndefined() && !readMultiLineString(value, &license))
|
||||||
return reportError(msgValueIsNotAMultilineString(LICENSE));
|
return reportError(msgValueIsNotAMultilineString(LICENSE));
|
||||||
|
|
||||||
|
value = metaData.value("Revision");
|
||||||
|
if (!value.isUndefined() && !value.isString())
|
||||||
|
return reportError(msgValueIsNotAString("Revision"));
|
||||||
|
revision = value.toString();
|
||||||
|
|
||||||
value = metaData.value(QLatin1String(PLATFORM));
|
value = metaData.value(QLatin1String(PLATFORM));
|
||||||
if (!value.isUndefined() && !value.isString())
|
if (!value.isUndefined() && !value.isString())
|
||||||
return reportError(msgValueIsNotAString(PLATFORM));
|
return reportError(msgValueIsNotAString(PLATFORM));
|
||||||
@@ -906,7 +928,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
|
|||||||
.arg(msgValueIsNotAString(DEPENDENCY_VERSION)));
|
.arg(msgValueIsNotAString(DEPENDENCY_VERSION)));
|
||||||
}
|
}
|
||||||
dep.version = value.toString();
|
dep.version = value.toString();
|
||||||
if (!isValidVersion(dep.version)) {
|
if (!PluginSpec::isValidVersion(dep.version)) {
|
||||||
return reportError(
|
return reportError(
|
||||||
::ExtensionSystem::Tr::tr("Dependency: %1")
|
::ExtensionSystem::Tr::tr("Dependency: %1")
|
||||||
.arg(msgInvalidFormat(DEPENDENCY_VERSION, dep.version)));
|
.arg(msgInvalidFormat(DEPENDENCY_VERSION, dep.version)));
|
||||||
@@ -987,23 +1009,15 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
state = PluginSpecImpl::Read;
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
|
static const QRegularExpression &versionRegExp()
|
||||||
{
|
|
||||||
if (QString::compare(pluginName, name, Qt::CaseInsensitive) != 0)
|
|
||||||
return false;
|
|
||||||
return (versionCompare(version, pluginVersion) >= 0) && (versionCompare(compatVersion, pluginVersion) <= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
const QRegularExpression &PluginSpecPrivate::versionRegExp()
|
|
||||||
{
|
{
|
||||||
static const QRegularExpression reg("^([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?$");
|
static const QRegularExpression reg("^([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?$");
|
||||||
return reg;
|
return reg;
|
||||||
@@ -1011,7 +1025,7 @@ const QRegularExpression &PluginSpecPrivate::versionRegExp()
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::isValidVersion(const QString &version)
|
bool PluginSpec::isValidVersion(const QString &version)
|
||||||
{
|
{
|
||||||
return versionRegExp().match(version).hasMatch();
|
return versionRegExp().match(version).hasMatch();
|
||||||
}
|
}
|
||||||
@@ -1019,7 +1033,7 @@ bool PluginSpecPrivate::isValidVersion(const QString &version)
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
|
int PluginSpec::versionCompare(const QString &version1, const QString &version2)
|
||||||
{
|
{
|
||||||
const QRegularExpressionMatch match1 = versionRegExp().match(version1);
|
const QRegularExpressionMatch match1 = versionRegExp().match(version1);
|
||||||
const QRegularExpressionMatch match2 = versionRegExp().match(version2);
|
const QRegularExpressionMatch match2 = versionRegExp().match(version2);
|
||||||
@@ -1041,196 +1055,205 @@ int PluginSpecPrivate::versionCompare(const QString &version1, const QString &ve
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::resolveDependencies(const QVector<PluginSpec *> &specs)
|
bool PluginSpec::resolveDependencies(const QVector<PluginSpec *> &specs)
|
||||||
{
|
{
|
||||||
if (hasError)
|
if (hasError())
|
||||||
return false;
|
return false;
|
||||||
if (state == PluginSpec::Resolved)
|
if (state() > PluginSpecImpl::Resolved)
|
||||||
state = PluginSpec::Read; // Go back, so we just re-resolve the dependencies.
|
return true; // We are resolved already.
|
||||||
if (state != PluginSpec::Read) {
|
if (state() == PluginSpecImpl::Resolved)
|
||||||
errorString = ::ExtensionSystem::Tr::tr("Resolving dependencies failed because state != Read");
|
setState(PluginSpecImpl::Read); // Go back, so we just re-resolve the dependencies.
|
||||||
hasError = true;
|
if (state() != PluginSpecImpl::Read) {
|
||||||
|
setError(::ExtensionSystem::Tr::tr("Resolving dependencies failed because state != Read"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<PluginDependency, PluginSpec *> resolvedDependencies;
|
QHash<PluginDependency, PluginSpec *> resolvedDependencies;
|
||||||
for (const PluginDependency &dependency : std::as_const(dependencies)) {
|
for (const PluginDependency &dependency : d->dependencies) {
|
||||||
PluginSpec * const found = Utils::findOrDefault(specs, [&dependency](PluginSpec *spec) {
|
PluginSpec *const found = findOrDefault(specs, [&dependency](PluginSpec *spec) {
|
||||||
return spec->provides(dependency.name, dependency.version);
|
return spec->provides(dependency.name, dependency.version);
|
||||||
});
|
});
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (dependency.type == PluginDependency::Required) {
|
if (dependency.type == PluginDependency::Required) {
|
||||||
hasError = true;
|
const QString error = ::ExtensionSystem::Tr::tr(
|
||||||
if (!errorString.isEmpty())
|
"Could not resolve dependency '%1(%2)'")
|
||||||
errorString.append(QLatin1Char('\n'));
|
.arg(dependency.name, dependency.version);
|
||||||
errorString.append(::ExtensionSystem::Tr::tr("Could not resolve dependency '%1(%2)'")
|
if (hasError())
|
||||||
.arg(dependency.name, dependency.version));
|
setError(errorString() + '\n' + error);
|
||||||
|
else
|
||||||
|
setError(error);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
resolvedDependencies.insert(dependency, found);
|
resolvedDependencies.insert(dependency, found);
|
||||||
}
|
}
|
||||||
if (hasError)
|
if (hasError())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dependencySpecs = resolvedDependencies;
|
d->dependencySpecs = resolvedDependencies;
|
||||||
|
|
||||||
state = PluginSpec::Resolved;
|
d->state = PluginSpecImpl::Resolved;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the plugins that it actually indirectly enabled
|
PluginSpec::PluginSpec()
|
||||||
QVector<PluginSpec *> PluginSpecPrivate::enableDependenciesIndirectly(bool enableTestDependencies)
|
: d(new PluginSpecPrivate())
|
||||||
|
{}
|
||||||
|
|
||||||
|
PluginSpec::~PluginSpec() = default;
|
||||||
|
|
||||||
|
void PluginSpec::setState(State state)
|
||||||
{
|
{
|
||||||
if (!q->isEffectivelyEnabled()) // plugin not enabled, nothing to do
|
d->state = state;
|
||||||
return {};
|
}
|
||||||
QVector<PluginSpec *> enabled;
|
|
||||||
for (auto it = dependencySpecs.cbegin(), end = dependencySpecs.cend(); it != end; ++it) {
|
void PluginSpec::setLocation(const QString &location)
|
||||||
if (it.key().type != PluginDependency::Required
|
{
|
||||||
&& (!enableTestDependencies || it.key().type != PluginDependency::Test))
|
d->location = location;
|
||||||
continue;
|
}
|
||||||
PluginSpec *dependencySpec = it.value();
|
|
||||||
if (!dependencySpec->isEffectivelyEnabled()) {
|
void PluginSpec::setFilePath(const QString &filePath)
|
||||||
dependencySpec->d->enabledIndirectly = true;
|
{
|
||||||
enabled << dependencySpec;
|
d->filePath = filePath;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return enabled;
|
void PluginSpec::setError(const QString &errorString)
|
||||||
|
{
|
||||||
|
d->errorString = errorString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::loadLibrary()
|
bool PluginSpecImpl::loadLibrary()
|
||||||
{
|
{
|
||||||
if (hasError)
|
if (hasError())
|
||||||
return false;
|
return false;
|
||||||
if (state != PluginSpec::Resolved) {
|
|
||||||
if (state == PluginSpec::Loaded)
|
if (state() != PluginSpecImpl::Resolved) {
|
||||||
|
if (state() == PluginSpecImpl::Loaded)
|
||||||
return true;
|
return true;
|
||||||
errorString =
|
setError(::ExtensionSystem::Tr::tr("Loading the library failed because state != Resolved"));
|
||||||
::ExtensionSystem::Tr::tr("Loading the library failed because state != Resolved");
|
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (loader && !loader->load()) {
|
if (d->loader && !d->loader->load()) {
|
||||||
hasError = true;
|
setError(QDir::toNativeSeparators(filePath()) + QString::fromLatin1(": ")
|
||||||
errorString = QDir::toNativeSeparators(filePath) + QString::fromLatin1(": ")
|
+ d->loader->errorString());
|
||||||
+ loader->errorString();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto *pluginObject = loader ? qobject_cast<IPlugin *>(loader->instance())
|
auto *pluginObject = d->loader ? qobject_cast<IPlugin *>(d->loader->instance())
|
||||||
: qobject_cast<IPlugin *>(staticPlugin->instance());
|
: qobject_cast<IPlugin *>(d->staticPlugin->instance());
|
||||||
if (!pluginObject) {
|
if (!pluginObject) {
|
||||||
hasError = true;
|
setError(::ExtensionSystem::Tr::tr("Plugin is not valid (does not derive from IPlugin)"));
|
||||||
errorString =
|
if (d->loader)
|
||||||
::ExtensionSystem::Tr::tr("Plugin is not valid (does not derive from IPlugin)");
|
d->loader->unload();
|
||||||
if (loader)
|
|
||||||
loader->unload();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
state = PluginSpec::Loaded;
|
setState(PluginSpecImpl::Loaded);
|
||||||
plugin = pluginObject;
|
d->plugin = pluginObject;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::initializePlugin()
|
bool PluginSpecImpl::initializePlugin()
|
||||||
{
|
{
|
||||||
if (hasError)
|
if (hasError())
|
||||||
return false;
|
return false;
|
||||||
if (state != PluginSpec::Loaded) {
|
|
||||||
if (state == PluginSpec::Initialized)
|
if (state() != PluginSpecImpl::Loaded) {
|
||||||
|
if (state() == PluginSpecImpl::Initialized)
|
||||||
return true;
|
return true;
|
||||||
errorString = ::ExtensionSystem::Tr::tr(
|
setError(
|
||||||
"Initializing the plugin failed because state != Loaded");
|
::ExtensionSystem::Tr::tr("Initializing the plugin failed because state != Loaded"));
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!plugin) {
|
if (!d->plugin) {
|
||||||
errorString = ::ExtensionSystem::Tr::tr(
|
setError(
|
||||||
"Internal error: have no plugin instance to initialize");
|
::ExtensionSystem::Tr::tr("Internal error: have no plugin instance to initialize"));
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QString err;
|
QString err;
|
||||||
if (!plugin->initialize(arguments, &err)) {
|
if (!d->plugin->initialize(arguments(), &err)) {
|
||||||
errorString = ::ExtensionSystem::Tr::tr("Plugin initialization failed: %1").arg(err);
|
setError(::ExtensionSystem::Tr::tr("Plugin initialization failed: %1").arg(err));
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
state = PluginSpec::Initialized;
|
setState(PluginSpecImpl::Initialized);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::initializeExtensions()
|
bool PluginSpecImpl::initializeExtensions()
|
||||||
{
|
{
|
||||||
if (hasError)
|
if (hasError())
|
||||||
return false;
|
return false;
|
||||||
if (state != PluginSpec::Initialized) {
|
|
||||||
if (state == PluginSpec::Running)
|
if (state() != PluginSpecImpl::Initialized) {
|
||||||
|
if (state() == PluginSpecImpl::Running)
|
||||||
return true;
|
return true;
|
||||||
errorString = ::ExtensionSystem::Tr::tr(
|
setError(::ExtensionSystem::Tr::tr(
|
||||||
"Cannot perform extensionsInitialized because state != Initialized");
|
"Cannot perform extensionsInitialized because state != Initialized"));
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!plugin) {
|
if (!d->plugin) {
|
||||||
errorString = ::ExtensionSystem::Tr::tr(
|
setError(::ExtensionSystem::Tr::tr(
|
||||||
"Internal error: have no plugin instance to perform extensionsInitialized");
|
"Internal error: have no plugin instance to perform extensionsInitialized"));
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
plugin->extensionsInitialized();
|
d->plugin->extensionsInitialized();
|
||||||
state = PluginSpec::Running;
|
setState(PluginSpecImpl::Running);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
bool PluginSpecPrivate::delayedInitialize()
|
bool PluginSpecImpl::delayedInitialize()
|
||||||
{
|
{
|
||||||
if (hasError)
|
if (hasError())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (state() != PluginSpecImpl::Running)
|
||||||
return false;
|
return false;
|
||||||
if (state != PluginSpec::Running)
|
if (!d->plugin) {
|
||||||
return false;
|
setError(::ExtensionSystem::Tr::tr(
|
||||||
if (!plugin) {
|
"Internal error: have no plugin instance to perform delayedInitialize"));
|
||||||
errorString = ::ExtensionSystem::Tr::tr(
|
|
||||||
"Internal error: have no plugin instance to perform delayedInitialize");
|
|
||||||
hasError = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const bool res = plugin->delayedInitialize();
|
const bool res = d->plugin->delayedInitialize();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
IPlugin::ShutdownFlag PluginSpecPrivate::stop()
|
IPlugin::ShutdownFlag PluginSpecImpl::stop()
|
||||||
{
|
{
|
||||||
if (!plugin)
|
if (hasError())
|
||||||
|
return IPlugin::ShutdownFlag::SynchronousShutdown;
|
||||||
|
|
||||||
|
if (!d->plugin)
|
||||||
return IPlugin::SynchronousShutdown;
|
return IPlugin::SynchronousShutdown;
|
||||||
state = PluginSpec::Stopped;
|
setState(PluginSpecImpl::Stopped);
|
||||||
return plugin->aboutToShutdown();
|
return d->plugin->aboutToShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
void PluginSpecPrivate::kill()
|
void PluginSpecImpl::kill()
|
||||||
{
|
{
|
||||||
if (!plugin)
|
if (hasError())
|
||||||
return;
|
return;
|
||||||
delete plugin;
|
|
||||||
plugin = nullptr;
|
|
||||||
state = PluginSpec::Deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // ExtensionSystem
|
if (!d->plugin)
|
||||||
|
return;
|
||||||
|
delete d->plugin;
|
||||||
|
d->plugin = nullptr;
|
||||||
|
setState(PluginSpecImpl::Deleted);
|
||||||
|
}
|
||||||
|
} // namespace ExtensionSystem
|
||||||
|
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
#include "extensionsystem_global.h"
|
#include "extensionsystem_global.h"
|
||||||
|
|
||||||
|
#include "iplugin.h"
|
||||||
|
|
||||||
|
#include <utils/expected.h>
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QStaticPlugin>
|
#include <QStaticPlugin>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@@ -14,17 +18,19 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QRegularExpression;
|
class QRegularExpression;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class tst_PluginSpec;
|
||||||
|
|
||||||
namespace ExtensionSystem {
|
namespace ExtensionSystem {
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class OptionsParser;
|
class OptionsParser;
|
||||||
class PluginSpecPrivate;
|
class PluginSpecImplPrivate;
|
||||||
class PluginManagerPrivate;
|
class PluginManagerPrivate;
|
||||||
|
class PluginSpecPrivate;
|
||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
|
|
||||||
class IPlugin;
|
|
||||||
class PluginView;
|
class PluginView;
|
||||||
|
|
||||||
struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
||||||
@@ -37,8 +43,6 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
|||||||
|
|
||||||
PluginDependency() : type(Required) {}
|
PluginDependency() : type(Required) {}
|
||||||
|
|
||||||
friend size_t qHash(const PluginDependency &value);
|
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
QString version;
|
QString version;
|
||||||
Type type;
|
Type type;
|
||||||
@@ -46,6 +50,8 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
|||||||
QString toString() const;
|
QString toString() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t EXTENSIONSYSTEM_EXPORT qHash(const PluginDependency &value);
|
||||||
|
|
||||||
struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription
|
struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription
|
||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
@@ -73,77 +79,126 @@ struct EXTENSIONSYSTEM_EXPORT PerformanceData
|
|||||||
|
|
||||||
class EXTENSIONSYSTEM_EXPORT PluginSpec
|
class EXTENSIONSYSTEM_EXPORT PluginSpec
|
||||||
{
|
{
|
||||||
|
friend class ::tst_PluginSpec;
|
||||||
|
friend class Internal::PluginManagerPrivate;
|
||||||
|
friend class Internal::OptionsParser;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted};
|
PluginSpec();
|
||||||
|
virtual ~PluginSpec();
|
||||||
~PluginSpec();
|
|
||||||
|
|
||||||
// information from the xml file, valid after 'Read' state is reached
|
|
||||||
QString name() const;
|
|
||||||
QString version() const;
|
|
||||||
QString compatVersion() const;
|
|
||||||
QString vendor() const;
|
|
||||||
QString copyright() const;
|
|
||||||
QString license() const;
|
|
||||||
QString description() const;
|
|
||||||
QString longDescription() const;
|
|
||||||
QString url() const;
|
|
||||||
QString category() const;
|
|
||||||
QString revision() const;
|
|
||||||
QRegularExpression platformSpecification() const;
|
|
||||||
bool isAvailableForHostPlatform() const;
|
|
||||||
bool isRequired() const;
|
|
||||||
bool isExperimental() const;
|
|
||||||
bool isDeprecated() const;
|
|
||||||
bool isEnabledByDefault() const;
|
|
||||||
bool isEnabledBySettings() const;
|
|
||||||
bool isEffectivelyEnabled() const;
|
|
||||||
bool isEnabledIndirectly() const;
|
|
||||||
bool isForceEnabled() const;
|
|
||||||
bool isForceDisabled() const;
|
|
||||||
bool isSoftLoadable() const;
|
|
||||||
QVector<PluginDependency> dependencies() const;
|
|
||||||
QJsonObject metaData() const;
|
|
||||||
const PerformanceData &performanceData() const;
|
|
||||||
|
|
||||||
using PluginArgumentDescriptions = QVector<PluginArgumentDescription>;
|
using PluginArgumentDescriptions = QVector<PluginArgumentDescription>;
|
||||||
PluginArgumentDescriptions argumentDescriptions() const;
|
enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted};
|
||||||
|
|
||||||
// other information, valid after 'Read' state is reached
|
// information read from the plugin, valid after 'Read' state is reached
|
||||||
QString location() const;
|
virtual QString name() const;
|
||||||
QString filePath() const;
|
virtual QString version() const;
|
||||||
|
virtual QString compatVersion() const;
|
||||||
|
virtual QString vendor() const;
|
||||||
|
virtual QString copyright() const;
|
||||||
|
virtual QString license() const;
|
||||||
|
virtual QString description() const;
|
||||||
|
virtual QString longDescription() const;
|
||||||
|
virtual QString url() const;
|
||||||
|
virtual QString category() const;
|
||||||
|
virtual QString revision() const;
|
||||||
|
virtual QRegularExpression platformSpecification() const;
|
||||||
|
|
||||||
QStringList arguments() const;
|
virtual bool isAvailableForHostPlatform() const;
|
||||||
void setArguments(const QStringList &arguments);
|
virtual bool isRequired() const;
|
||||||
void addArgument(const QString &argument);
|
virtual bool isExperimental() const;
|
||||||
|
virtual bool isDeprecated() const;
|
||||||
|
virtual bool isEnabledByDefault() const;
|
||||||
|
virtual bool isEnabledBySettings() const;
|
||||||
|
virtual bool isEffectivelyEnabled() const;
|
||||||
|
virtual bool isEnabledIndirectly() const;
|
||||||
|
virtual bool isForceEnabled() const;
|
||||||
|
virtual bool isForceDisabled() const;
|
||||||
|
virtual bool isSoftLoadable() const;
|
||||||
|
|
||||||
bool provides(const QString &pluginName, const QString &version) const;
|
virtual QVector<PluginDependency> dependencies() const;
|
||||||
|
virtual QJsonObject metaData() const;
|
||||||
|
virtual PerformanceData &performanceData() const;
|
||||||
|
virtual PluginArgumentDescriptions argumentDescriptions() const;
|
||||||
|
virtual QString location() const;
|
||||||
|
virtual QString filePath() const;
|
||||||
|
virtual QStringList arguments() const;
|
||||||
|
virtual void setArguments(const QStringList &arguments);
|
||||||
|
virtual void addArgument(const QString &argument);
|
||||||
|
virtual QHash<PluginDependency, PluginSpec *> dependencySpecs() const;
|
||||||
|
|
||||||
// dependency specs, valid after 'Resolved' state is reached
|
virtual bool provides(const QString &pluginName, const QString &pluginVersion) const;
|
||||||
QHash<PluginDependency, PluginSpec *> dependencySpecs() const;
|
virtual bool requiresAny(const QSet<PluginSpec *> &plugins) const;
|
||||||
bool requiresAny(const QSet<PluginSpec *> &plugins) const;
|
virtual QVector<PluginSpec *> enableDependenciesIndirectly(bool enableTestDependencies);
|
||||||
|
virtual bool resolveDependencies(const QVector<PluginSpec *> &pluginSpecs);
|
||||||
|
|
||||||
// linked plugin instance, valid after 'Loaded' state is reached
|
virtual IPlugin *plugin() const = 0;
|
||||||
IPlugin *plugin() const;
|
virtual State state() const;
|
||||||
|
virtual bool hasError() const;
|
||||||
|
virtual QString errorString() const;
|
||||||
|
|
||||||
// state
|
static bool isValidVersion(const QString &version);
|
||||||
State state() const;
|
static int versionCompare(const QString &version1, const QString &version2);
|
||||||
bool hasError() const;
|
|
||||||
QString errorString() const;
|
|
||||||
|
|
||||||
void setEnabledBySettings(bool value);
|
virtual void setEnabledBySettings(bool value);
|
||||||
|
|
||||||
static PluginSpec *read(const QString &filePath);
|
protected:
|
||||||
static PluginSpec *read(const QStaticPlugin &plugin);
|
virtual void setEnabledByDefault(bool value);
|
||||||
|
virtual void setEnabledIndirectly(bool value);
|
||||||
|
virtual void setForceDisabled(bool value);
|
||||||
|
virtual void setForceEnabled(bool value);
|
||||||
|
|
||||||
|
virtual bool loadLibrary() = 0;
|
||||||
|
virtual bool initializePlugin() = 0;
|
||||||
|
virtual bool initializeExtensions() = 0;
|
||||||
|
virtual bool delayedInitialize() = 0;
|
||||||
|
virtual IPlugin::ShutdownFlag stop() = 0;
|
||||||
|
virtual void kill() = 0;
|
||||||
|
|
||||||
|
virtual void setError(const QString &errorString);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setState(State state);
|
||||||
|
|
||||||
|
virtual void setLocation(const QString &location);
|
||||||
|
virtual void setFilePath(const QString &filePath);
|
||||||
|
virtual Utils::expected_str<void> readMetaData(const QJsonObject &metaData);
|
||||||
|
Utils::expected_str<void> reportError(const QString &error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginSpec();
|
std::unique_ptr<Internal::PluginSpecPrivate> d;
|
||||||
|
};
|
||||||
|
|
||||||
Internal::PluginSpecPrivate *d;
|
class EXTENSIONSYSTEM_TEST_EXPORT PluginSpecImpl : public PluginSpec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~PluginSpecImpl() override;
|
||||||
|
|
||||||
|
// linked plugin instance, valid after 'Loaded' state is reached
|
||||||
|
IPlugin *plugin() const override;
|
||||||
|
|
||||||
|
bool loadLibrary() override;
|
||||||
|
bool initializePlugin() override;
|
||||||
|
bool initializeExtensions() override;
|
||||||
|
bool delayedInitialize() override;
|
||||||
|
IPlugin::ShutdownFlag stop() override;
|
||||||
|
void kill() override;
|
||||||
|
|
||||||
|
static Utils::expected_str<PluginSpec *> read(const QString &filePath);
|
||||||
|
static Utils::expected_str<PluginSpec *> read(const QStaticPlugin &plugin);
|
||||||
|
|
||||||
|
Utils::expected_str<void> readMetaData(const QJsonObject &pluginMetaData) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PluginSpecImpl();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Internal::PluginSpecImplPrivate> d;
|
||||||
friend class PluginView;
|
friend class PluginView;
|
||||||
friend class Internal::OptionsParser;
|
friend class Internal::OptionsParser;
|
||||||
friend class Internal::PluginManagerPrivate;
|
friend class Internal::PluginManagerPrivate;
|
||||||
friend class Internal::PluginSpecPrivate;
|
friend class Internal::PluginSpecImplPrivate;
|
||||||
|
friend class ::tst_PluginSpec;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ExtensionSystem
|
} // namespace ExtensionSystem
|
||||||
|
@@ -1,107 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pluginspec.h"
|
|
||||||
#include "iplugin.h"
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QPluginLoader>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QVector>
|
|
||||||
#include <QXmlStreamReader>
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
namespace ExtensionSystem {
|
|
||||||
|
|
||||||
class IPlugin;
|
|
||||||
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class EXTENSIONSYSTEM_TEST_EXPORT PluginSpecPrivate : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PluginSpecPrivate(PluginSpec *spec);
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
bool read(const QString &fileName);
|
|
||||||
bool read(const QStaticPlugin &plugin);
|
|
||||||
bool provides(const QString &pluginName, const QString &version) const;
|
|
||||||
bool resolveDependencies(const QVector<PluginSpec *> &specs);
|
|
||||||
bool loadLibrary();
|
|
||||||
bool initializePlugin();
|
|
||||||
bool initializeExtensions();
|
|
||||||
bool delayedInitialize();
|
|
||||||
IPlugin::ShutdownFlag stop();
|
|
||||||
void kill();
|
|
||||||
|
|
||||||
void setEnabledBySettings(bool value);
|
|
||||||
void setEnabledByDefault(bool value);
|
|
||||||
void setForceEnabled(bool value);
|
|
||||||
void setForceDisabled(bool value);
|
|
||||||
void setSoftLoadable(bool value);
|
|
||||||
|
|
||||||
std::optional<QPluginLoader> loader;
|
|
||||||
std::optional<QStaticPlugin> staticPlugin;
|
|
||||||
|
|
||||||
QString name;
|
|
||||||
QString version;
|
|
||||||
QString compatVersion;
|
|
||||||
bool required = false;
|
|
||||||
bool experimental = false;
|
|
||||||
bool enabledByDefault = true;
|
|
||||||
bool deprecated = false;
|
|
||||||
QString vendor;
|
|
||||||
QString copyright;
|
|
||||||
QString license;
|
|
||||||
QString description;
|
|
||||||
QString longDescription;
|
|
||||||
QString url;
|
|
||||||
QString category;
|
|
||||||
QRegularExpression platformSpecification;
|
|
||||||
QVector<PluginDependency> dependencies;
|
|
||||||
QJsonObject metaData;
|
|
||||||
bool enabledBySettings = true;
|
|
||||||
bool enabledIndirectly = false;
|
|
||||||
bool forceEnabled = false;
|
|
||||||
bool forceDisabled = false;
|
|
||||||
bool softLoadable = false;
|
|
||||||
|
|
||||||
QString location;
|
|
||||||
QString filePath;
|
|
||||||
QStringList arguments;
|
|
||||||
|
|
||||||
QHash<PluginDependency, PluginSpec *> dependencySpecs;
|
|
||||||
PluginSpec::PluginArgumentDescriptions argumentDescriptions;
|
|
||||||
IPlugin *plugin = nullptr;
|
|
||||||
|
|
||||||
QList<TestCreator> registeredPluginTests;
|
|
||||||
|
|
||||||
PluginSpec::State state = PluginSpec::Invalid;
|
|
||||||
bool hasError = false;
|
|
||||||
QString errorString;
|
|
||||||
|
|
||||||
PerformanceData performanceData;
|
|
||||||
|
|
||||||
static bool isValidVersion(const QString &version);
|
|
||||||
static int versionCompare(const QString &version1, const QString &version2);
|
|
||||||
|
|
||||||
QVector<PluginSpec *> enableDependenciesIndirectly(bool enableTestDependencies = false);
|
|
||||||
|
|
||||||
bool readMetaData(const QJsonObject &pluginMetaData);
|
|
||||||
|
|
||||||
private:
|
|
||||||
PluginSpec *q;
|
|
||||||
|
|
||||||
bool reportError(const QString &err);
|
|
||||||
static const QRegularExpression &versionRegExp();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ExtensionSystem
|
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "extensionsystemtr.h"
|
#include "extensionsystemtr.h"
|
||||||
#include "pluginmanager.h"
|
#include "pluginmanager.h"
|
||||||
#include "pluginspec_p.h"
|
#include "pluginspec.h"
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/categorysortfiltermodel.h>
|
#include <utils/categorysortfiltermodel.h>
|
||||||
@@ -416,8 +416,8 @@ bool PluginView::setPluginsEnabled(const QSet<PluginSpec *> &plugins, bool enabl
|
|||||||
});
|
});
|
||||||
QTC_ASSERT(item, continue);
|
QTC_ASSERT(item, continue);
|
||||||
if (m_affectedPlugins.find(spec) == m_affectedPlugins.end())
|
if (m_affectedPlugins.find(spec) == m_affectedPlugins.end())
|
||||||
m_affectedPlugins[spec] = spec->d->enabledBySettings;
|
m_affectedPlugins[spec] = spec->isEnabledBySettings();
|
||||||
spec->d->setEnabledBySettings(enable);
|
spec->setEnabledBySettings(enable);
|
||||||
item->updateColumn(LoadedColumn);
|
item->updateColumn(LoadedColumn);
|
||||||
item->parent()->updateColumn(LoadedColumn);
|
item->parent()->updateColumn(LoadedColumn);
|
||||||
}
|
}
|
||||||
@@ -428,7 +428,7 @@ bool PluginView::setPluginsEnabled(const QSet<PluginSpec *> &plugins, bool enabl
|
|||||||
void PluginView::cancelChanges()
|
void PluginView::cancelChanges()
|
||||||
{
|
{
|
||||||
for (auto element : m_affectedPlugins)
|
for (auto element : m_affectedPlugins)
|
||||||
element.first->d->setEnabledBySettings(element.second);
|
element.first->setEnabledBySettings(element.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ExtensionSystem
|
} // namespace ExtensionSystem
|
||||||
|
@@ -154,11 +154,11 @@ void checkContents(QPromise<ArchiveIssue> &promise, const FilePath &tempDir)
|
|||||||
if (promise.isCanceled())
|
if (promise.isCanceled())
|
||||||
return;
|
return;
|
||||||
it.next();
|
it.next();
|
||||||
PluginSpec *spec = PluginSpec::read(it.filePath());
|
expected_str<PluginSpec *> spec = PluginSpecImpl::read(it.filePath());
|
||||||
if (spec) {
|
if (spec) {
|
||||||
// Is a Qt Creator plugin. Let's see if we find a Core dependency and check the
|
// Is a Qt Creator plugin. Let's see if we find a Core dependency and check the
|
||||||
// version
|
// version
|
||||||
const QVector<PluginDependency> dependencies = spec->dependencies();
|
const QVector<PluginDependency> dependencies = (*spec)->dependencies();
|
||||||
const auto found = std::find_if(dependencies.constBegin(), dependencies.constEnd(),
|
const auto found = std::find_if(dependencies.constBegin(), dependencies.constEnd(),
|
||||||
[coreplugin](const PluginDependency &d) { return d.name == coreplugin->name(); });
|
[coreplugin](const PluginDependency &d) { return d.name == coreplugin->name(); });
|
||||||
if (found == dependencies.constEnd())
|
if (found == dependencies.constEnd())
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
"end of terms"
|
"end of terms"
|
||||||
],
|
],
|
||||||
"Description" : [
|
"Description" : [
|
||||||
|
"This spec is broken because no name is set.",
|
||||||
"This plugin is just a test.",
|
"This plugin is just a test.",
|
||||||
" it demonstrates the great use of the plugin spec."
|
" it demonstrates the great use of the plugin spec."
|
||||||
],
|
],
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
"end of terms"
|
"end of terms"
|
||||||
],
|
],
|
||||||
"Description" : [
|
"Description" : [
|
||||||
|
"This spec is wrong because no version is set.",
|
||||||
"This plugin is just a test.",
|
"This plugin is just a test.",
|
||||||
" it demonstrates the great use of the plugin spec."
|
" it demonstrates the great use of the plugin spec."
|
||||||
],
|
],
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
"end of terms"
|
"end of terms"
|
||||||
],
|
],
|
||||||
"Description" : [
|
"Description" : [
|
||||||
|
"This spec is wrong because the first dependency has no name.",
|
||||||
"This plugin is just a test.",
|
"This plugin is just a test.",
|
||||||
" it demonstrates the great use of the plugin spec."
|
" it demonstrates the great use of the plugin spec."
|
||||||
],
|
],
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
"end of terms"
|
"end of terms"
|
||||||
],
|
],
|
||||||
"Description" : [
|
"Description" : [
|
||||||
|
"This spec is wrong because the first dependencies version is invalid.",
|
||||||
"This plugin is just a test.",
|
"This plugin is just a test.",
|
||||||
" it demonstrates the great use of the plugin spec."
|
" it demonstrates the great use of the plugin spec."
|
||||||
],
|
],
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include <extensionsystem/pluginspec.h>
|
|
||||||
#include <extensionsystem/pluginspec_p.h>
|
|
||||||
#include <extensionsystem/pluginmanager_p.h>
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
#include <extensionsystem/pluginmanager_p.h>
|
||||||
|
#include <extensionsystem/pluginspec.h>
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@@ -85,109 +84,110 @@ void tst_PluginSpec::cleanupTestCase()
|
|||||||
|
|
||||||
void tst_PluginSpec::read()
|
void tst_PluginSpec::read()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
PluginSpecImpl spec;
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/spec1.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/spec1.json")));
|
||||||
QVERIFY(!spec.hasError);
|
QVERIFY(!spec.hasError());
|
||||||
QVERIFY(spec.errorString.isEmpty());
|
QVERIFY(spec.errorString().isEmpty());
|
||||||
QCOMPARE(spec.name, QString("test"));
|
QCOMPARE(spec.name(), QString("test"));
|
||||||
QCOMPARE(spec.version, QString("1.0.1"));
|
QCOMPARE(spec.version(), QString("1.0.1"));
|
||||||
QCOMPARE(spec.compatVersion, QString("1.0.0"));
|
QCOMPARE(spec.compatVersion(), QString("1.0.0"));
|
||||||
QCOMPARE(spec.required, false);
|
QCOMPARE(spec.isRequired(), false);
|
||||||
QCOMPARE(spec.experimental, false);
|
QCOMPARE(spec.isExperimental(), false);
|
||||||
QCOMPARE(spec.enabledBySettings, true);
|
QCOMPARE(spec.isEnabledBySettings(), true);
|
||||||
QCOMPARE(spec.vendor, QString("The Qt Company Ltd"));
|
QCOMPARE(spec.vendor(), QString("The Qt Company Ltd"));
|
||||||
QCOMPARE(spec.copyright, QString("(C) 2015 The Qt Company Ltd"));
|
QCOMPARE(spec.copyright(), QString("(C) 2015 The Qt Company Ltd"));
|
||||||
QCOMPARE(spec.license, QString("This is a default license bla\nblubbblubb\nend of terms"));
|
QCOMPARE(spec.license(), QString("This is a default license bla\nblubbblubb\nend of terms"));
|
||||||
QCOMPARE(spec.description, QString("This plugin is just a test."));
|
QCOMPARE(spec.description(), QString("This plugin is just a test."));
|
||||||
QCOMPARE(
|
QCOMPARE(
|
||||||
spec.longDescription,
|
spec.longDescription(),
|
||||||
QString(
|
QString(
|
||||||
"This plugin is just a test.\n it demonstrates the great use of the plugin spec."));
|
"This plugin is just a test.\n it demonstrates the great use of the plugin spec."));
|
||||||
QCOMPARE(spec.url, QString("http://www.qt.io"));
|
QCOMPARE(spec.url(), QString("http://www.qt.io"));
|
||||||
PluginDependency dep1;
|
PluginDependency dep1;
|
||||||
dep1.name = QString("SomeOtherPlugin");
|
dep1.name = QString("SomeOtherPlugin");
|
||||||
dep1.version = QString("2.3.0_2");
|
dep1.version = QString("2.3.0_2");
|
||||||
PluginDependency dep2;
|
PluginDependency dep2;
|
||||||
dep2.name = QString("EvenOther");
|
dep2.name = QString("EvenOther");
|
||||||
dep2.version = QString("1.0.0");
|
dep2.version = QString("1.0.0");
|
||||||
QCOMPARE(spec.dependencies, QVector<PluginDependency>() << dep1 << dep2);
|
QCOMPARE(spec.dependencies(), QVector<PluginDependency>() << dep1 << dep2);
|
||||||
|
|
||||||
// test missing compatVersion behavior
|
// test missing compatVersion behavior
|
||||||
// and 'required' attribute
|
// and 'required' attribute
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/spec2.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/spec2.json")));
|
||||||
QCOMPARE(spec.version, QString("3.1.4_10"));
|
QCOMPARE(spec.version(), QString("3.1.4_10"));
|
||||||
QCOMPARE(spec.compatVersion, QString("3.1.4_10"));
|
QCOMPARE(spec.compatVersion(), QString("3.1.4_10"));
|
||||||
QCOMPARE(spec.required, true);
|
QCOMPARE(spec.isRequired(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::readError()
|
void tst_PluginSpec::readError()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
PluginSpecImpl spec;
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(!spec.readMetaData(metaData("non-existing-file.json")));
|
QVERIFY(!spec.readMetaData(metaData("non-existing-file.json")));
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(!spec.hasError);
|
QVERIFY(!spec.hasError());
|
||||||
QVERIFY(spec.errorString.isEmpty());
|
QVERIFY(spec.errorString().isEmpty());
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong2.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong2.json")));
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(spec.hasError);
|
QVERIFY(spec.hasError());
|
||||||
QVERIFY(!spec.errorString.isEmpty());
|
QVERIFY(!spec.errorString().isEmpty());
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong3.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong3.json")));
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(spec.hasError);
|
QVERIFY(spec.hasError());
|
||||||
QVERIFY(!spec.errorString.isEmpty());
|
QVERIFY(!spec.errorString().isEmpty());
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong4.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong4.json")));
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(spec.hasError);
|
QVERIFY(spec.hasError());
|
||||||
QVERIFY(!spec.errorString.isEmpty());
|
QVERIFY(!spec.errorString().isEmpty());
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong5.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong5.json")));
|
||||||
QCOMPARE(spec.state, PluginSpec::Invalid);
|
QCOMPARE(spec.state(), PluginSpec::Invalid);
|
||||||
QVERIFY(spec.hasError);
|
QVERIFY(spec.hasError());
|
||||||
QVERIFY(!spec.errorString.isEmpty());
|
QVERIFY(!spec.errorString().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::isValidVersion()
|
void tst_PluginSpec::isValidVersion()
|
||||||
{
|
{
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("2"));
|
QVERIFY(PluginSpec::isValidVersion("2"));
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("53"));
|
QVERIFY(PluginSpec::isValidVersion("53"));
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("52_1"));
|
QVERIFY(PluginSpec::isValidVersion("52_1"));
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("3.12"));
|
QVERIFY(PluginSpec::isValidVersion("3.12"));
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1_12"));
|
QVERIFY(PluginSpec::isValidVersion("31.1_12"));
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1.0"));
|
QVERIFY(PluginSpec::isValidVersion("31.1.0"));
|
||||||
QVERIFY(Internal::PluginSpecPrivate::isValidVersion("1.0.2_1"));
|
QVERIFY(PluginSpec::isValidVersion("1.0.2_1"));
|
||||||
|
|
||||||
QVERIFY(!Internal::PluginSpecPrivate::isValidVersion(""));
|
QVERIFY(!PluginSpec::isValidVersion(""));
|
||||||
QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1..0"));
|
QVERIFY(!PluginSpec::isValidVersion("1..0"));
|
||||||
QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0_"));
|
QVERIFY(!PluginSpec::isValidVersion("1.0_"));
|
||||||
QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0.0.0"));
|
QVERIFY(!PluginSpec::isValidVersion("1.0.0.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::versionCompare()
|
void tst_PluginSpec::versionCompare()
|
||||||
{
|
{
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3") == 0);
|
QVERIFY(PluginSpec::versionCompare("3", "3") == 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0", "3") == 0);
|
QVERIFY(PluginSpec::versionCompare("3.0.0", "3") == 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0", "3") == 0);
|
QVERIFY(PluginSpec::versionCompare("3.0", "3") == 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0_1", "3_1") == 0);
|
QVERIFY(PluginSpec::versionCompare("3.0.0_1", "3_1") == 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0_21", "3_21") == 0);
|
QVERIFY(PluginSpec::versionCompare("3.0_21", "3_21") == 0);
|
||||||
|
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1") > 0);
|
QVERIFY(PluginSpec::versionCompare("3", "1") > 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1.0_12") > 0);
|
QVERIFY(PluginSpec::versionCompare("3", "1.0_12") > 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3_1", "3") > 0);
|
QVERIFY(PluginSpec::versionCompare("3_1", "3") > 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1.0_23", "3.1") > 0);
|
QVERIFY(PluginSpec::versionCompare("3.1.0_23", "3.1") > 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_23", "3.1_12") > 0);
|
QVERIFY(PluginSpec::versionCompare("3.1_23", "3.1_12") > 0);
|
||||||
|
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("1", "3") < 0);
|
QVERIFY(PluginSpec::versionCompare("1", "3") < 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("1.0_12", "3") < 0);
|
QVERIFY(PluginSpec::versionCompare("1.0_12", "3") < 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3_1") < 0);
|
QVERIFY(PluginSpec::versionCompare("3", "3_1") < 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1", "3.1.0_23") < 0);
|
QVERIFY(PluginSpec::versionCompare("3.1", "3.1.0_23") < 0);
|
||||||
QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_12", "3.1_23") < 0);
|
QVERIFY(PluginSpec::versionCompare("3.1_12", "3.1_23") < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::provides()
|
void tst_PluginSpec::provides()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
PluginSpecImpl spec;
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec.json")));
|
||||||
|
|
||||||
QVERIFY(!spec.provides("SomeOtherPlugin", "2.2.3_9"));
|
QVERIFY(!spec.provides("SomeOtherPlugin", "2.2.3_9"));
|
||||||
QVERIFY(!spec.provides("MyPlugin", "2.2.3_10"));
|
QVERIFY(!spec.provides("MyPlugin", "2.2.3_10"));
|
||||||
QVERIFY(!spec.provides("MyPlugin", "2.2.4"));
|
QVERIFY(!spec.provides("MyPlugin", "2.2.4"));
|
||||||
@@ -211,112 +211,132 @@ void tst_PluginSpec::provides()
|
|||||||
|
|
||||||
void tst_PluginSpec::experimental()
|
void tst_PluginSpec::experimental()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
PluginSpecImpl spec;
|
||||||
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec_experimental.json")));
|
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec_experimental.json")));
|
||||||
QCOMPARE(spec.experimental, true);
|
|
||||||
QCOMPARE(spec.enabledBySettings, false);
|
QCOMPARE(spec.isExperimental(), true);
|
||||||
|
QCOMPARE(spec.isEnabledBySettings(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::locationAndPath()
|
void tst_PluginSpec::locationAndPath()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
Utils::expected_str<PluginSpec *> ps = PluginSpecImpl::read(
|
||||||
QVERIFY(spec.read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
|
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
|
||||||
QCOMPARE(spec.location, QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin")));
|
+ libraryName(QLatin1String("test")));
|
||||||
QCOMPARE(spec.filePath, QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
|
QVERIFY(ps);
|
||||||
|
PluginSpecImpl *spec = static_cast<PluginSpecImpl *>(ps.value());
|
||||||
|
QCOMPARE(spec->location(), QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin")));
|
||||||
|
QCOMPARE(spec->filePath(),
|
||||||
|
QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
|
||||||
|
+ libraryName(QLatin1String("test"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::resolveDependencies()
|
void tst_PluginSpec::resolveDependencies()
|
||||||
{
|
{
|
||||||
QVector<PluginSpec *> specs;
|
QVector<PluginSpec *> specs;
|
||||||
PluginSpec *spec1 = Internal::PluginManagerPrivate::createSpec();
|
PluginSpec *spec1 = new PluginSpecImpl();
|
||||||
specs.append(spec1);
|
specs.append(spec1);
|
||||||
Internal::PluginSpecPrivate *spec1Priv = Internal::PluginManagerPrivate::privateSpec(spec1);
|
spec1->readMetaData(metaData("testdependencies/spec1.json"));
|
||||||
spec1Priv->readMetaData(metaData("testdependencies/spec1.json"));
|
spec1->setState(PluginSpec::Read); // fake read state for plugin resolving
|
||||||
spec1Priv->state = PluginSpec::Read; // fake read state for plugin resolving
|
|
||||||
|
|
||||||
PluginSpec *spec2 = Internal::PluginManagerPrivate::createSpec();
|
PluginSpec *spec2 = new PluginSpecImpl();
|
||||||
specs.append(spec2);
|
specs.append(spec2);
|
||||||
Internal::PluginSpecPrivate *spec2Priv = Internal::PluginManagerPrivate::privateSpec(spec2);
|
spec2->readMetaData(metaData("testdependencies/spec2.json"));
|
||||||
spec2Priv->readMetaData(metaData("testdependencies/spec2.json"));
|
spec2->setState(PluginSpec::Read); // fake read state for plugin resolving
|
||||||
spec2Priv->state = PluginSpec::Read; // fake read state for plugin resolving
|
|
||||||
|
|
||||||
PluginSpec *spec3 = Internal::PluginManagerPrivate::createSpec();
|
PluginSpec *spec3 = new PluginSpecImpl();
|
||||||
specs.append(spec3);
|
specs.append(spec3);
|
||||||
Internal::PluginSpecPrivate *spec3Priv = Internal::PluginManagerPrivate::privateSpec(spec3);
|
spec3->readMetaData(metaData("testdependencies/spec3.json"));
|
||||||
spec3Priv->readMetaData(metaData("testdependencies/spec3.json"));
|
spec3->setState(PluginSpec::Read); // fake read state for plugin resolving
|
||||||
spec3Priv->state = PluginSpec::Read; // fake read state for plugin resolving
|
|
||||||
|
|
||||||
PluginSpec *spec4 = Internal::PluginManagerPrivate::createSpec();
|
PluginSpec *spec4 = new PluginSpecImpl();
|
||||||
specs.append(spec4);
|
specs.append(spec4);
|
||||||
Internal::PluginSpecPrivate *spec4Priv = Internal::PluginManagerPrivate::privateSpec(spec4);
|
spec4->readMetaData(metaData("testdependencies/spec4.json"));
|
||||||
spec4Priv->readMetaData(metaData("testdependencies/spec4.json"));
|
spec4->setState(PluginSpec::Read); // fake read state for plugin resolving
|
||||||
spec4Priv->state = PluginSpec::Read; // fake read state for plugin resolving
|
|
||||||
|
|
||||||
PluginSpec *spec5 = Internal::PluginManagerPrivate::createSpec();
|
PluginSpec *spec5 = new PluginSpecImpl();
|
||||||
specs.append(spec5);
|
specs.append(spec5);
|
||||||
Internal::PluginSpecPrivate *spec5Priv = Internal::PluginManagerPrivate::privateSpec(spec5);
|
spec5->readMetaData(metaData("testdependencies/spec5.json"));
|
||||||
spec5Priv->readMetaData(metaData("testdependencies/spec5.json"));
|
spec5->setState(PluginSpec::Read); // fake read state for plugin resolving
|
||||||
spec5Priv->state = PluginSpec::Read; // fake read state for plugin resolving
|
|
||||||
|
|
||||||
QVERIFY(spec1Priv->resolveDependencies(specs));
|
QVERIFY(spec1->resolveDependencies(specs));
|
||||||
QCOMPARE(spec1Priv->dependencySpecs.size(), 2);
|
QCOMPARE(spec1->dependencySpecs().size(), 2);
|
||||||
QVERIFY(!spec1Priv->dependencySpecs.key(spec2).name.isEmpty());
|
QVERIFY(!spec1->dependencySpecs().key(spec2).name.isEmpty());
|
||||||
QVERIFY(!spec1Priv->dependencySpecs.key(spec3).name.isEmpty());
|
QVERIFY(!spec1->dependencySpecs().key(spec3).name.isEmpty());
|
||||||
QCOMPARE(spec1Priv->state, PluginSpec::Resolved);
|
QCOMPARE(spec1->state(), PluginSpec::Resolved);
|
||||||
QVERIFY(!spec4Priv->resolveDependencies(specs));
|
QVERIFY(!spec4->resolveDependencies(specs));
|
||||||
QVERIFY(spec4Priv->hasError);
|
QVERIFY(spec4->hasError());
|
||||||
QCOMPARE(spec4Priv->state, PluginSpec::Read);
|
QCOMPARE(spec4->state(), PluginSpec::Read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::loadLibrary()
|
void tst_PluginSpec::loadLibrary()
|
||||||
{
|
{
|
||||||
PluginSpec *ps = Internal::PluginManagerPrivate::createSpec();
|
Utils::expected_str<PluginSpec *> ps = PluginSpecImpl::read(
|
||||||
Internal::PluginSpecPrivate *spec = Internal::PluginManagerPrivate::privateSpec(ps);
|
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
|
||||||
QVERIFY(spec->read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
|
+ libraryName(QLatin1String("test")));
|
||||||
|
|
||||||
|
QVERIFY(ps);
|
||||||
|
PluginSpecImpl *spec = static_cast<PluginSpecImpl *>(ps.value());
|
||||||
|
|
||||||
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
|
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
|
||||||
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString));
|
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
|
||||||
QVERIFY(spec->plugin != 0);
|
QVERIFY(spec->plugin() != 0);
|
||||||
QVERIFY(QLatin1String(spec->plugin->metaObject()->className()) == QLatin1String("MyPlugin::MyPluginImpl"));
|
QVERIFY(QLatin1String(spec->plugin()->metaObject()->className())
|
||||||
QCOMPARE(spec->state, PluginSpec::Loaded);
|
== QLatin1String("MyPlugin::MyPluginImpl"));
|
||||||
QVERIFY(!spec->hasError);
|
QCOMPARE(spec->state(), PluginSpec::Loaded);
|
||||||
QCOMPARE(spec->plugin, ps->plugin());
|
QVERIFY(!spec->hasError());
|
||||||
delete ps;
|
|
||||||
|
delete *ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::initializePlugin()
|
void tst_PluginSpec::initializePlugin()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
Utils::expected_str<PluginSpec *> ps = PluginSpecImpl::read(
|
||||||
QVERIFY(spec.read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
|
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
|
||||||
QVERIFY(spec.resolveDependencies(QVector<PluginSpec *>()));
|
+ libraryName(QLatin1String("test")));
|
||||||
QVERIFY2(spec.loadLibrary(), qPrintable(spec.errorString));
|
QVERIFY(ps);
|
||||||
|
PluginSpecImpl *spec = static_cast<PluginSpecImpl *>(ps.value());
|
||||||
|
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
|
||||||
|
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
|
||||||
bool isInitialized;
|
bool isInitialized;
|
||||||
QMetaObject::invokeMethod(spec.plugin, "isInitialized",
|
QMetaObject::invokeMethod(spec->plugin(),
|
||||||
Qt::DirectConnection, Q_RETURN_ARG(bool, isInitialized));
|
"isInitialized",
|
||||||
|
Qt::DirectConnection,
|
||||||
|
Q_RETURN_ARG(bool, isInitialized));
|
||||||
QVERIFY(!isInitialized);
|
QVERIFY(!isInitialized);
|
||||||
QVERIFY(spec.initializePlugin());
|
QVERIFY(spec->initializePlugin());
|
||||||
QCOMPARE(spec.state, PluginSpec::Initialized);
|
QCOMPARE(spec->state(), PluginSpec::Initialized);
|
||||||
QVERIFY(!spec.hasError);
|
QVERIFY(!spec->hasError());
|
||||||
QMetaObject::invokeMethod(spec.plugin, "isInitialized",
|
QMetaObject::invokeMethod(spec->plugin(),
|
||||||
Qt::DirectConnection, Q_RETURN_ARG(bool, isInitialized));
|
"isInitialized",
|
||||||
|
Qt::DirectConnection,
|
||||||
|
Q_RETURN_ARG(bool, isInitialized));
|
||||||
QVERIFY(isInitialized);
|
QVERIFY(isInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_PluginSpec::initializeExtensions()
|
void tst_PluginSpec::initializeExtensions()
|
||||||
{
|
{
|
||||||
Internal::PluginSpecPrivate spec(0);
|
Utils::expected_str<PluginSpec *> ps = PluginSpecImpl::read(
|
||||||
QVERIFY(spec.read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
|
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
|
||||||
QVERIFY(spec.resolveDependencies(QVector<PluginSpec *>()));
|
+ libraryName(QLatin1String("test")));
|
||||||
QVERIFY2(spec.loadLibrary(), qPrintable(spec.errorString));
|
QVERIFY(ps);
|
||||||
|
PluginSpecImpl *spec = static_cast<PluginSpecImpl *>(ps.value());
|
||||||
|
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
|
||||||
|
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
|
||||||
bool isExtensionsInitialized;
|
bool isExtensionsInitialized;
|
||||||
QVERIFY(spec.initializePlugin());
|
QVERIFY(spec->initializePlugin());
|
||||||
QMetaObject::invokeMethod(spec.plugin, "isExtensionsInitialized",
|
QMetaObject::invokeMethod(spec->plugin(),
|
||||||
Qt::DirectConnection, Q_RETURN_ARG(bool, isExtensionsInitialized));
|
"isExtensionsInitialized",
|
||||||
|
Qt::DirectConnection,
|
||||||
|
Q_RETURN_ARG(bool, isExtensionsInitialized));
|
||||||
QVERIFY(!isExtensionsInitialized);
|
QVERIFY(!isExtensionsInitialized);
|
||||||
QVERIFY(spec.initializeExtensions());
|
QVERIFY(spec->initializeExtensions());
|
||||||
QCOMPARE(spec.state, PluginSpec::Running);
|
QCOMPARE(spec->state(), PluginSpec::Running);
|
||||||
QVERIFY(!spec.hasError);
|
QVERIFY(!spec->hasError());
|
||||||
QMetaObject::invokeMethod(spec.plugin, "isExtensionsInitialized",
|
QMetaObject::invokeMethod(spec->plugin(),
|
||||||
Qt::DirectConnection, Q_RETURN_ARG(bool, isExtensionsInitialized));
|
"isExtensionsInitialized",
|
||||||
|
Qt::DirectConnection,
|
||||||
|
Q_RETURN_ARG(bool, isExtensionsInitialized));
|
||||||
QVERIFY(isExtensionsInitialized);
|
QVERIFY(isExtensionsInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user