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 @@
\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
......
......@@ -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)
......
......@@ -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) {
......
......@@ -91,6 +91,7 @@ bool OptionsParser::parse()
}
if (m_isDependencyRefreshNeeded)
m_pmPrivate->resolveDependencies();
m_pmPrivate->enableOnlyTestedSpecs();
return !m_hasError;
}
......
......@@ -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);
}
......
......@@ -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
{
......
......@@ -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);
......
......@@ -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()) {
......
......@@ -55,7 +55,8 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency
{
enum Type {
Required,
Optional
Optional,
Test
};
PluginDependency() : type(Required) {}
......
......@@ -16,6 +16,10 @@ QtcPlugin {
Depends { name: "app_version_header" }
pluginTestDepends: [
"QmakeProjectManager",
]
files: [
"cppautocompleter.cpp", "cppautocompleter.h",
"cppcanonicalsymbol.cpp", "cppcanonicalsymbol.h",
......
......@@ -9,3 +9,5 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \
cpptools \
projectexplorer
QTC_TEST_DEPENDS += \
qmakeprojectmanager
......@@ -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")
......
......@@ -8,3 +8,6 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \
projectexplorer \
texteditor
QTC_TEST_DEPENDS += \
cppeditor \
qmakeprojectmanager
......@@ -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) ]"
......
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