Commit 044eeacd authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Eike Ziller

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: default avatarLeena Miettinen <riitta-leena.miettinen@theqtcompany.com>
Reviewed-by: default avatarEike Ziller <eike.ziller@theqtcompany.com>
parent da67c7c6
...@@ -199,8 +199,9 @@ ...@@ -199,8 +199,9 @@
\row \row
\li Type \li Type
\li String \li String
\li Optional. Value \c Required or \c Optional. Defines if the dependency is \li Optional. Value \c Required, \c Optional, or \c Test. Defines if the dependency is
a hard requirement or optional. Defaults to \c{Required}. a hard requirement, optional, or required for running the plugin's tests.
Defaults to \c{Required}.
\endtable \endtable
\section3 Optional Dependencies \section3 Optional Dependencies
...@@ -223,6 +224,18 @@ ...@@ -223,6 +224,18 @@
ExtensionSystem::PluginManager::getObjectByClassName(), and use QMetaObject functions to call ExtensionSystem::PluginManager::getObjectByClassName(), and use QMetaObject functions to call
functions on it. 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 \section2 Command Line Arguments
Plugins can register command line arguments that the user can give Plugins can register command line arguments that the user can give
......
...@@ -8,6 +8,7 @@ QtcProduct { ...@@ -8,6 +8,7 @@ QtcProduct {
property var pluginJsonReplacements property var pluginJsonReplacements
property var pluginRecommends: [] property var pluginRecommends: []
property var pluginTestDepends: []
property string minimumQtVersion: "5.3.1" property string minimumQtVersion: "5.3.1"
condition: QtcFunctions.versionIsAtLeast(Qt.core.version, minimumQtVersion) condition: QtcFunctions.versionIsAtLeast(Qt.core.version, minimumQtVersion)
......
...@@ -36,6 +36,7 @@ Module { ...@@ -36,6 +36,7 @@ Module {
} }
} }
cmd.plugin_recommends = product.pluginRecommends cmd.plugin_recommends = product.pluginRecommends
cmd.plugin_test_depends = product.pluginTestDepends
cmd.sourceCode = function() { cmd.sourceCode = function() {
var i; var i;
...@@ -57,6 +58,9 @@ Module { ...@@ -57,6 +58,9 @@ Module {
for (i in plugin_recommends) { for (i in plugin_recommends) {
deplist.push(" { \"Name\" : \"" + plugin_recommends[i] + "\", \"Version\" : \"" + project.qtcreator_version + "\", \"Type\" : \"optional\" }"); 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") deplist = deplist.join(",\n")
vars['dependencyList'] = "\"Dependencies\" : [\n" + deplist + "\n ]"; vars['dependencyList'] = "\"Dependencies\" : [\n" + deplist + "\n ]";
for (i in vars) { for (i in vars) {
......
...@@ -91,6 +91,7 @@ bool OptionsParser::parse() ...@@ -91,6 +91,7 @@ bool OptionsParser::parse()
} }
if (m_isDependencyRefreshNeeded) if (m_isDependencyRefreshNeeded)
m_pmPrivate->resolveDependencies(); m_pmPrivate->resolveDependencies();
m_pmPrivate->enableOnlyTestedSpecs();
return !m_hasError; return !m_hasError;
} }
......
...@@ -98,8 +98,16 @@ void PluginDetailsView::update(PluginSpec *spec) ...@@ -98,8 +98,16 @@ void PluginDetailsView::update(PluginSpec *spec)
QString depString = dep.name; QString depString = dep.name;
depString += QLatin1String(" ("); depString += QLatin1String(" (");
depString += dep.version; depString += dep.version;
if (dep.type == PluginDependency::Optional) switch (dep.type) {
case PluginDependency::Required:
break;
case PluginDependency::Optional:
depString += QLatin1String(", optional"); depString += QLatin1String(", optional");
break;
case PluginDependency::Test:
depString += QLatin1String(", test");
break;
}
depString += QLatin1Char(')'); depString += QLatin1Char(')');
depStrings.append(depString); depStrings.append(depString);
} }
......
...@@ -1255,7 +1255,14 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queu ...@@ -1255,7 +1255,14 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queu
} }
// add dependencies // 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)) { if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
spec->d->hasError = true; spec->d->hasError = true;
spec->d->errorString = spec->d->errorString =
...@@ -1299,7 +1306,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt ...@@ -1299,7 +1306,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs()); QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs());
while (it.hasNext()) { while (it.hasNext()) {
it.next(); it.next();
if (it.key().type == PluginDependency::Optional) if (it.key().type != PluginDependency::Required)
continue; continue;
PluginSpec *depSpec = it.value(); PluginSpec *depSpec = it.value();
if (depSpec->state() != destState) { if (depSpec->state() != destState) {
...@@ -1423,6 +1430,35 @@ void PluginManagerPrivate::resolveDependencies() ...@@ -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. // Look in argument descriptions of the specs for the option.
PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const
{ {
......
...@@ -73,6 +73,7 @@ public: ...@@ -73,6 +73,7 @@ public:
QList<PluginSpec *> loadQueue(); QList<PluginSpec *> loadQueue();
void loadPlugin(PluginSpec *spec, PluginSpec::State destState); void loadPlugin(PluginSpec *spec, PluginSpec::State destState);
void resolveDependencies(); void resolveDependencies();
void enableOnlyTestedSpecs();
void initProfiling(); void initProfiling();
void profilingSummary() const; void profilingSummary() const;
void profilingReport(const char *what, const PluginSpec *spec = 0); void profilingReport(const char *what, const PluginSpec *spec = 0);
......
...@@ -86,6 +86,8 @@ ...@@ -86,6 +86,8 @@
Dependency is not necessarily needed. You need to make sure that Dependency is not necessarily needed. You need to make sure that
the plugin is able to load without this dependency installed, so the plugin is able to load without this dependency installed, so
for example you may not link to the dependency's library. 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 { ...@@ -471,6 +473,7 @@ namespace {
const char DEPENDENCY_TYPE[] = "Type"; const char DEPENDENCY_TYPE[] = "Type";
const char DEPENDENCY_TYPE_SOFT[] = "optional"; const char DEPENDENCY_TYPE_SOFT[] = "optional";
const char DEPENDENCY_TYPE_HARD[] = "required"; const char DEPENDENCY_TYPE_HARD[] = "required";
const char DEPENDENCY_TYPE_TEST[] = "test";
const char ARGUMENTS[] = "Arguments"; const char ARGUMENTS[] = "Arguments";
const char ARGUMENT_NAME[] = "Name"; const char ARGUMENT_NAME[] = "Name";
const char ARGUMENT_PARAMETER[] = "Parameter"; const char ARGUMENT_PARAMETER[] = "Parameter";
...@@ -763,6 +766,8 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData) ...@@ -763,6 +766,8 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
dep.type = PluginDependency::Required; dep.type = PluginDependency::Required;
} else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_SOFT)) { } else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_SOFT)) {
dep.type = PluginDependency::Optional; dep.type = PluginDependency::Optional;
} else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_TEST)) {
dep.type = PluginDependency::Test;
} else { } else {
return reportError(tr("Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\")") return reportError(tr("Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\")")
.arg(QLatin1String(DEPENDENCY_TYPE), .arg(QLatin1String(DEPENDENCY_TYPE),
...@@ -917,7 +922,7 @@ void PluginSpecPrivate::disableIndirectlyIfDependencyDisabled() ...@@ -917,7 +922,7 @@ void PluginSpecPrivate::disableIndirectlyIfDependencyDisabled()
QHashIterator<PluginDependency, PluginSpec *> it(dependencySpecs); QHashIterator<PluginDependency, PluginSpec *> it(dependencySpecs);
while (it.hasNext()) { while (it.hasNext()) {
it.next(); it.next();
if (it.key().type == PluginDependency::Optional) if (it.key().type != PluginDependency::Required)
continue; continue;
PluginSpec *dependencySpec = it.value(); PluginSpec *dependencySpec = it.value();
if (!dependencySpec->isEffectivelyEnabled()) { if (!dependencySpec->isEffectivelyEnabled()) {
......
...@@ -55,7 +55,8 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency ...@@ -55,7 +55,8 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency
{ {
enum Type { enum Type {
Required, Required,
Optional Optional,
Test
}; };
PluginDependency() : type(Required) {} PluginDependency() : type(Required) {}
......
...@@ -16,6 +16,10 @@ QtcPlugin { ...@@ -16,6 +16,10 @@ QtcPlugin {
Depends { name: "app_version_header" } Depends { name: "app_version_header" }
pluginTestDepends: [
"QmakeProjectManager",
]
files: [ files: [
"cppautocompleter.cpp", "cppautocompleter.h", "cppautocompleter.cpp", "cppautocompleter.h",
"cppcanonicalsymbol.cpp", "cppcanonicalsymbol.h", "cppcanonicalsymbol.cpp", "cppcanonicalsymbol.h",
......
...@@ -9,3 +9,5 @@ QTC_PLUGIN_DEPENDS += \ ...@@ -9,3 +9,5 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \ coreplugin \
cpptools \ cpptools \
projectexplorer projectexplorer
QTC_TEST_DEPENDS += \
qmakeprojectmanager
...@@ -14,6 +14,11 @@ QtcPlugin { ...@@ -14,6 +14,11 @@ QtcPlugin {
Depends { name: "ProjectExplorer" } Depends { name: "ProjectExplorer" }
Depends { name: "app_version_header" } Depends { name: "app_version_header" }
pluginTestDepends: [
"CppEditor",
"QmakeProjectManager",
]
cpp.defines: base cpp.defines: base
Properties { Properties {
condition: qbs.toolchain.contains("msvc") condition: qbs.toolchain.contains("msvc")
......
...@@ -8,3 +8,6 @@ QTC_PLUGIN_DEPENDS += \ ...@@ -8,3 +8,6 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \ coreplugin \
projectexplorer \ projectexplorer \
texteditor texteditor
QTC_TEST_DEPENDS += \
cppeditor \
qmakeprojectmanager
...@@ -10,6 +10,7 @@ exists($$depfile) { ...@@ -10,6 +10,7 @@ exists($$depfile) {
TARGET = $$QTC_PLUGIN_NAME TARGET = $$QTC_PLUGIN_NAME
plugin_deps = $$QTC_PLUGIN_DEPENDS plugin_deps = $$QTC_PLUGIN_DEPENDS
plugin_test_deps = $$QTC_TEST_DEPENDS
plugin_recmds = $$QTC_PLUGIN_RECOMMENDS plugin_recmds = $$QTC_PLUGIN_RECOMMENDS
include(../qtcreator.pri) include(../qtcreator.pri)
...@@ -36,6 +37,9 @@ for(dep, plugin_deps) { ...@@ -36,6 +37,9 @@ for(dep, plugin_deps) {
for(dep, plugin_recmds) { for(dep, plugin_recmds) {
dependencyList += " { \"Name\" : \"$$dependencyName($$dep)\", \"Version\" : \"$$QTCREATOR_VERSION\", \"Type\" : \"optional\" }" 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 = $$join(dependencyList, ",$$escape_expand(\\n)")
dependencyList = "\"Dependencies\" : [$$escape_expand(\\n)$$dependencyList$$escape_expand(\\n) ]" dependencyList = "\"Dependencies\" : [$$escape_expand(\\n)$$dependencyList$$escape_expand(\\n) ]"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment