From 044eeacde5ee1add8b06a8a53b86fd5c6991d488 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh <orgad.shaneh@audiocodes.com> Date: Wed, 4 Mar 2015 09:25:08 +0200 Subject: [PATCH] Load only tested plugins when invoked with -test By default, a clean settings path is used for test environment. All the default plugins are loaded, although they're not needed. This change significantly improves loading time for tests. Change-Id: I24254f3e538e3f0e6d233d0989738dc1ce238209 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@theqtcompany.com> Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com> --- doc/api/plugin-metadata.qdoc | 17 +++++++- qbs/imports/QtcPlugin.qbs | 1 + qbs/modules/pluginjson/pluginjson.qbs | 4 ++ src/libs/extensionsystem/optionsparser.cpp | 1 + .../extensionsystem/plugindetailsview.cpp | 10 ++++- src/libs/extensionsystem/pluginmanager.cpp | 40 ++++++++++++++++++- src/libs/extensionsystem/pluginmanager_p.h | 1 + src/libs/extensionsystem/pluginspec.cpp | 7 +++- src/libs/extensionsystem/pluginspec.h | 3 +- src/plugins/cppeditor/cppeditor.qbs | 4 ++ .../cppeditor/cppeditor_dependencies.pri | 2 + src/plugins/cpptools/cpptools.qbs | 5 +++ .../cpptools/cpptools_dependencies.pri | 3 ++ src/qtcreatorplugin.pri | 4 ++ 14 files changed, 95 insertions(+), 7 deletions(-) diff --git a/doc/api/plugin-metadata.qdoc b/doc/api/plugin-metadata.qdoc index 4477ecb66a8..4675202ec90 100644 --- a/doc/api/plugin-metadata.qdoc +++ b/doc/api/plugin-metadata.qdoc @@ -199,8 +199,9 @@ \row \li Type \li String - \li Optional. Value \c Required or \c Optional. Defines if the dependency is - a hard requirement or optional. Defaults to \c{Required}. + \li Optional. Value \c Required, \c Optional, or \c Test. Defines if the dependency is + a hard requirement, optional, or required for running the plugin's tests. + Defaults to \c{Required}. \endtable \section3 Optional Dependencies @@ -223,6 +224,18 @@ ExtensionSystem::PluginManager::getObjectByClassName(), and use QMetaObject functions to call functions on it. + \section3 Test Dependencies + + When the user runs the application with the \c{-test} command line argument, only + the specified plugins and their dependencies are loaded. This is done in order to + speed up the execution of tests by avoiding the loading of unneeded plugins. + + A plugin can specify additional dependencies that are required for running its + tests, but not for its normal execution, by declaring dependencies with + \c {"Type" : "Test"}. Test dependencies are force loaded, and do not affect load order. + + This type of dependency is not transitive. + \section2 Command Line Arguments Plugins can register command line arguments that the user can give diff --git a/qbs/imports/QtcPlugin.qbs b/qbs/imports/QtcPlugin.qbs index 713e388c3ae..9d1e99d90ec 100644 --- a/qbs/imports/QtcPlugin.qbs +++ b/qbs/imports/QtcPlugin.qbs @@ -8,6 +8,7 @@ QtcProduct { property var pluginJsonReplacements property var pluginRecommends: [] + property var pluginTestDepends: [] property string minimumQtVersion: "5.3.1" condition: QtcFunctions.versionIsAtLeast(Qt.core.version, minimumQtVersion) diff --git a/qbs/modules/pluginjson/pluginjson.qbs b/qbs/modules/pluginjson/pluginjson.qbs index 3a2515ae139..8bbfe754e73 100644 --- a/qbs/modules/pluginjson/pluginjson.qbs +++ b/qbs/modules/pluginjson/pluginjson.qbs @@ -36,6 +36,7 @@ Module { } } cmd.plugin_recommends = product.pluginRecommends + cmd.plugin_test_depends = product.pluginTestDepends cmd.sourceCode = function() { var i; @@ -57,6 +58,9 @@ Module { for (i in plugin_recommends) { deplist.push(" { \"Name\" : \"" + plugin_recommends[i] + "\", \"Version\" : \"" + project.qtcreator_version + "\", \"Type\" : \"optional\" }"); } + for (i in plugin_test_depends) { + deplist.push(" { \"Name\" : \"" + plugin_test_depends[i] + "\", \"Version\" : \"" + project.qtcreator_version + "\", \"Type\" : \"test\" }"); + } deplist = deplist.join(",\n") vars['dependencyList'] = "\"Dependencies\" : [\n" + deplist + "\n ]"; for (i in vars) { diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp index 9882c3121fe..8d50d722e75 100644 --- a/src/libs/extensionsystem/optionsparser.cpp +++ b/src/libs/extensionsystem/optionsparser.cpp @@ -91,6 +91,7 @@ bool OptionsParser::parse() } if (m_isDependencyRefreshNeeded) m_pmPrivate->resolveDependencies(); + m_pmPrivate->enableOnlyTestedSpecs(); return !m_hasError; } diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp index 35e64f4ee63..310ef48b9d0 100644 --- a/src/libs/extensionsystem/plugindetailsview.cpp +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -98,8 +98,16 @@ void PluginDetailsView::update(PluginSpec *spec) QString depString = dep.name; depString += QLatin1String(" ("); depString += dep.version; - if (dep.type == PluginDependency::Optional) + switch (dep.type) { + case PluginDependency::Required: + break; + case PluginDependency::Optional: depString += QLatin1String(", optional"); + break; + case PluginDependency::Test: + depString += QLatin1String(", test"); + break; + } depString += QLatin1Char(')'); depStrings.append(depString); } diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 5f2785236d0..d34db47d255 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -1255,7 +1255,14 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queu } // add dependencies - foreach (PluginSpec *depSpec, spec->dependencySpecs()) { + QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs()); + while (it.hasNext()) { + it.next(); + // Skip test dependencies since they are not real dependencies but just force-loaded + // plugins when running tests + if (it.key().type == PluginDependency::Test) + continue; + PluginSpec *depSpec = it.value(); if (!loadQueue(depSpec, queue, circularityCheckQueue)) { spec->d->hasError = true; spec->d->errorString = @@ -1299,7 +1306,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs()); while (it.hasNext()) { it.next(); - if (it.key().type == PluginDependency::Optional) + if (it.key().type != PluginDependency::Required) continue; PluginSpec *depSpec = it.value(); if (depSpec->state() != destState) { @@ -1423,6 +1430,35 @@ void PluginManagerPrivate::resolveDependencies() } } +void PluginManagerPrivate::enableOnlyTestedSpecs() +{ + if (testSpecs.isEmpty()) + return; + + QList<PluginSpec *> specsForTests; + foreach (const TestSpec &testSpec, testSpecs) { + QList<PluginSpec *> circularityCheckQueue; + loadQueue(testSpec.pluginSpec, specsForTests, circularityCheckQueue); + // add plugins that must be force loaded when running tests for the plugin + // (aka "test dependencies") + QHashIterator<PluginDependency, PluginSpec *> it(testSpec.pluginSpec->dependencySpecs()); + while (it.hasNext()) { + it.next(); + if (it.key().type != PluginDependency::Test) + continue; + PluginSpec *depSpec = it.value(); + circularityCheckQueue.clear(); + loadQueue(depSpec, specsForTests, circularityCheckQueue); + } + } + foreach (PluginSpec *spec, pluginSpecs) + spec->setForceDisabled(true); + foreach (PluginSpec *spec, specsForTests) { + spec->setForceDisabled(false); + spec->setForceEnabled(true); + } +} + // Look in argument descriptions of the specs for the option. PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const { diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h index 0400ceb0fc2..f219d5c0dae 100644 --- a/src/libs/extensionsystem/pluginmanager_p.h +++ b/src/libs/extensionsystem/pluginmanager_p.h @@ -73,6 +73,7 @@ public: QList<PluginSpec *> loadQueue(); void loadPlugin(PluginSpec *spec, PluginSpec::State destState); void resolveDependencies(); + void enableOnlyTestedSpecs(); void initProfiling(); void profilingSummary() const; void profilingReport(const char *what, const PluginSpec *spec = 0); diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index 9d470cd5b20..858dfd9510e 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -86,6 +86,8 @@ Dependency is not necessarily needed. You need to make sure that the plugin is able to load without this dependency installed, so for example you may not link to the dependency's library. + \value Test + Dependency needs to be force-loaded for running tests of the plugin. */ /*! @@ -471,6 +473,7 @@ namespace { const char DEPENDENCY_TYPE[] = "Type"; const char DEPENDENCY_TYPE_SOFT[] = "optional"; const char DEPENDENCY_TYPE_HARD[] = "required"; + const char DEPENDENCY_TYPE_TEST[] = "test"; const char ARGUMENTS[] = "Arguments"; const char ARGUMENT_NAME[] = "Name"; const char ARGUMENT_PARAMETER[] = "Parameter"; @@ -763,6 +766,8 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData) dep.type = PluginDependency::Required; } else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_SOFT)) { dep.type = PluginDependency::Optional; + } else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_TEST)) { + dep.type = PluginDependency::Test; } else { return reportError(tr("Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\")") .arg(QLatin1String(DEPENDENCY_TYPE), @@ -917,7 +922,7 @@ void PluginSpecPrivate::disableIndirectlyIfDependencyDisabled() QHashIterator<PluginDependency, PluginSpec *> it(dependencySpecs); while (it.hasNext()) { it.next(); - if (it.key().type == PluginDependency::Optional) + if (it.key().type != PluginDependency::Required) continue; PluginSpec *dependencySpec = it.value(); if (!dependencySpec->isEffectivelyEnabled()) { diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h index 9272403e9aa..56860135a97 100644 --- a/src/libs/extensionsystem/pluginspec.h +++ b/src/libs/extensionsystem/pluginspec.h @@ -55,7 +55,8 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency { enum Type { Required, - Optional + Optional, + Test }; PluginDependency() : type(Required) {} diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index cb1248508e1..243fb637742 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -16,6 +16,10 @@ QtcPlugin { Depends { name: "app_version_header" } + pluginTestDepends: [ + "QmakeProjectManager", + ] + files: [ "cppautocompleter.cpp", "cppautocompleter.h", "cppcanonicalsymbol.cpp", "cppcanonicalsymbol.h", diff --git a/src/plugins/cppeditor/cppeditor_dependencies.pri b/src/plugins/cppeditor/cppeditor_dependencies.pri index 2b90476fc37..751d75224ac 100644 --- a/src/plugins/cppeditor/cppeditor_dependencies.pri +++ b/src/plugins/cppeditor/cppeditor_dependencies.pri @@ -9,3 +9,5 @@ QTC_PLUGIN_DEPENDS += \ coreplugin \ cpptools \ projectexplorer +QTC_TEST_DEPENDS += \ + qmakeprojectmanager diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index 9d8e6c7d85f..72b68b9a9a1 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -14,6 +14,11 @@ QtcPlugin { Depends { name: "ProjectExplorer" } Depends { name: "app_version_header" } + pluginTestDepends: [ + "CppEditor", + "QmakeProjectManager", + ] + cpp.defines: base Properties { condition: qbs.toolchain.contains("msvc") diff --git a/src/plugins/cpptools/cpptools_dependencies.pri b/src/plugins/cpptools/cpptools_dependencies.pri index 705d6334f37..27d0f90d681 100644 --- a/src/plugins/cpptools/cpptools_dependencies.pri +++ b/src/plugins/cpptools/cpptools_dependencies.pri @@ -8,3 +8,6 @@ QTC_PLUGIN_DEPENDS += \ coreplugin \ projectexplorer \ texteditor +QTC_TEST_DEPENDS += \ + cppeditor \ + qmakeprojectmanager diff --git a/src/qtcreatorplugin.pri b/src/qtcreatorplugin.pri index 5381b6de835..0f57dfc88a9 100644 --- a/src/qtcreatorplugin.pri +++ b/src/qtcreatorplugin.pri @@ -10,6 +10,7 @@ exists($$depfile) { TARGET = $$QTC_PLUGIN_NAME plugin_deps = $$QTC_PLUGIN_DEPENDS +plugin_test_deps = $$QTC_TEST_DEPENDS plugin_recmds = $$QTC_PLUGIN_RECOMMENDS include(../qtcreator.pri) @@ -36,6 +37,9 @@ for(dep, plugin_deps) { for(dep, plugin_recmds) { dependencyList += " { \"Name\" : \"$$dependencyName($$dep)\", \"Version\" : \"$$QTCREATOR_VERSION\", \"Type\" : \"optional\" }" } +for(dep, plugin_test_deps) { + dependencyList += " { \"Name\" : \"$$dependencyName($$dep)\", \"Version\" : \"$$QTCREATOR_VERSION\", \"Type\" : \"test\" }" +} dependencyList = $$join(dependencyList, ",$$escape_expand(\\n)") dependencyList = "\"Dependencies\" : [$$escape_expand(\\n)$$dependencyList$$escape_expand(\\n) ]" -- GitLab