From 9ebe20ca27fbce2ca2934e40dfd1a7a21aaa6658 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 21 Sep 2018 13:15:47 +0200 Subject: Avoid scanning extension directory over and over again And get rid of separate management of a list of loaded extensions. Instead save the name and state of an extension in a separate class. It will probably get more information about the extension, like its location. The extension manager UI now can also iterate over that list once. Change-Id: I4872e55d621837a7d476e69b919f06aeb491ff03 Reviewed-by: Eike Ziller --- docs/extensions.md | 5 +- .../bindingheaders/pythonextensions_extension.h | 0 plugins/pythonextensions/pythonextensions.pro | 1 + .../pythonextensions/pythonextensionsplugin.cpp | 76 ++++++++++++++-------- plugins/pythonextensions/pythonextensionsplugin.h | 13 +++- plugins/pythonextensions/pyutil.h | 2 +- plugins/pythonextensions/typesystem_qtcreator.xml | 1 + python/extensionmanager/actions.py | 4 +- python/extensionmanager/list.py | 6 +- 9 files changed, 69 insertions(+), 39 deletions(-) create mode 100644 plugins/pythonextensions/bindingheaders/pythonextensions_extension.h diff --git a/docs/extensions.md b/docs/extensions.md index ae5cb5c..709acff 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -21,9 +21,8 @@ from PythonExtension import PluginInstance as inst inst.extensionDir() # Returns a list with the names of all Python extensions -# If loaded only is supplied as True, only extensions that -# where loaded successfully are returned -inst.extensionList(loadedOnly = False) +# Each extension has properties 'name' and 'loaded' +inst.extensionList() # Returns the path of the custom location to # where missing dependencies should be pip installed diff --git a/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h b/plugins/pythonextensions/bindingheaders/pythonextensions_extension.h new file mode 100644 index 0000000..e69de29 diff --git a/plugins/pythonextensions/pythonextensions.pro b/plugins/pythonextensions/pythonextensions.pro index c8fe73d..e28b860 100644 --- a/plugins/pythonextensions/pythonextensions.pro +++ b/plugins/pythonextensions/pythonextensions.pro @@ -36,6 +36,7 @@ WRAPPED_CLASSES = \ bindingheaders/pythonextensions.h \ bindingheaders/pythonextensions_internal.h \ bindingheaders/pythonextensions_internal_pythonextensionsplugin.h \ + bindingheaders/pythonextensions_extension.h \ bindingheaders/core.h \ bindingheaders/core_actioncontainer.h \ bindingheaders/core_actionmanager.h \ diff --git a/plugins/pythonextensions/pythonextensionsplugin.cpp b/plugins/pythonextensions/pythonextensionsplugin.cpp index 3136bbc..b3730b4 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.cpp +++ b/plugins/pythonextensions/pythonextensionsplugin.cpp @@ -39,6 +39,8 @@ #include #include +#include + #include #include #include @@ -131,19 +133,32 @@ QDir PythonExtensionsPlugin::extensionDir() return extension_dir; } -QStringList PythonExtensionsPlugin::extensionList(const bool loadedOnly) +static QVector getExtensionList(const QDir &directory) { - if (loadedOnly) - return m_loadedExtensions; + if (!directory.exists()) + return {}; + + QStringList entries = directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + entries.removeAll("site-packages"); + entries.removeAll("__pycache__"); + return Utils::transform(entries, [](const QString &entry) { + return Extension({entry, false}); + }); +} - QDir extension_dir = extensionDir(); - if (!extension_dir.exists()) - return QStringList(); +QVector PythonExtensionsPlugin::extensionList() +{ + return extensionListRef(); +} - QStringList extension_list = extension_dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); - extension_list.removeAll("site-packages"); - extension_list.removeAll("__pycache__"); - return extension_list; +QVector &PythonExtensionsPlugin::extensionListRef() +{ + static bool initialized = false; + if (!initialized) { + m_extensions = getExtensionList(extensionDir()); + initialized = true; + } + return m_extensions; } QString PythonExtensionsPlugin::pythonPackagePath() @@ -207,16 +222,18 @@ void PythonExtensionsPlugin::installRequirements() if (!extension_dir.exists()) return; - QStringList extension_list = extensionList(); - for (const QString &extension : extension_list) { - QString extension_requirements(extension_dir.absolutePath() + "/" + extension + "/requirements.txt"); - if (QFileInfo::exists(extension_requirements) && !QFileInfo::exists(extension_requirements + ".installed")) { - if (!PyUtil::pipInstallRequirements( - extension_requirements.toStdString(), - pythonPackagePath().toStdString() - )) { - qWarning() << "Failed to install requirements for extension" << extension; - Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Failed to install requirements for extension ") + extension); + QVector extension_list = extensionListRef(); + for (const Extension &extension : extension_list) { + QString extension_requirements(extension_dir.absolutePath() + "/" + extension.name + + "/requirements.txt"); + if (QFileInfo::exists(extension_requirements) + && !QFileInfo::exists(extension_requirements + ".installed")) { + if (!PyUtil::pipInstallRequirements(extension_requirements.toStdString(), + pythonPackagePath().toStdString())) { + qWarning() << "Failed to install requirements for extension" << extension.name; + Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + + tr("Failed to install requirements for extension ") + + extension.name); } } } @@ -234,22 +251,25 @@ void PythonExtensionsPlugin::initializePythonExtensions() qDebug() << "Found Python extension directory at location" << extension_dir.absolutePath(); - QStringList extension_list = extensionList(); + QVector &extension_list = extensionListRef(); qDebug() << "Number of Python extensions found:" << extension_list.size(); + int loadedCount = 0; // Run the extension initialization code - for (const QString &extension : extension_list) { - qDebug() << "Trying to initialize extension" << extension; - if (!PyUtil::runScript("import " + extension.toStdString())) { - qWarning() << "Failed to initialize extension" << extension; - Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + tr("Failed to initialize extension ") + extension); + for (Extension &extension : extension_list) { + qDebug() << "Trying to initialize extension" << extension.name; + if (PyUtil::runScript("import " + extension.name.toStdString())) { + extension.loaded = true; + ++loadedCount; } else { - m_loadedExtensions << extension; + qWarning() << "Failed to initialize extension" << extension.name; + Core::MessageManager::write(Constants::MESSAGE_MANAGER_PREFIX + + tr("Failed to initialize extension ") + extension.name); } } - qDebug() << "Number of Python extensions loaded:" << m_loadedExtensions.size(); + qDebug() << "Number of Python extensions loaded:" << loadedCount; } } // namespace Internal diff --git a/plugins/pythonextensions/pythonextensionsplugin.h b/plugins/pythonextensions/pythonextensionsplugin.h index 106ee63..1a4bce3 100644 --- a/plugins/pythonextensions/pythonextensionsplugin.h +++ b/plugins/pythonextensions/pythonextensionsplugin.h @@ -33,6 +33,13 @@ #include namespace PythonExtensions { + +class Extension { +public: + QString name; + bool loaded; +}; + namespace Internal { class PythonExtensionsPlugin : public ExtensionSystem::IPlugin @@ -50,14 +57,16 @@ public: ShutdownFlag aboutToShutdown() final; QDir extensionDir(); - QStringList extensionList(const bool loadedOnly = false); + QVector extensionList(); QString pythonPackagePath(); + private: - QStringList m_loadedExtensions; void initializePythonBindings(); void initializeOptionalBindings(); void installRequirements(); void initializePythonExtensions(); + QVector &extensionListRef(); + QVector m_extensions; }; // Util functions diff --git a/plugins/pythonextensions/pyutil.h b/plugins/pythonextensions/pyutil.h index 62a1622..23fdb37 100644 --- a/plugins/pythonextensions/pyutil.h +++ b/plugins/pythonextensions/pyutil.h @@ -37,7 +37,7 @@ namespace PyUtil { // Note: If modifying the bindings, check these types still align enum QtCreatorTypes { - PythonExtensionsPluginType = 33, // SBK_PYTHONEXTENSIONS_INTERNAL_PYTHONEXTENSIONSPLUGIN_IDX + PythonExtensionsPluginType = 34, // SBK_PYTHONEXTENSIONS_INTERNAL_PYTHONEXTENSIONSPLUGIN_IDX }; enum State diff --git a/plugins/pythonextensions/typesystem_qtcreator.xml b/plugins/pythonextensions/typesystem_qtcreator.xml index 736fe44..49dd794 100644 --- a/plugins/pythonextensions/typesystem_qtcreator.xml +++ b/plugins/pythonextensions/typesystem_qtcreator.xml @@ -47,6 +47,7 @@ + diff --git a/python/extensionmanager/actions.py b/python/extensionmanager/actions.py index 29d64cc..7f05e77 100644 --- a/python/extensionmanager/actions.py +++ b/python/extensionmanager/actions.py @@ -60,8 +60,8 @@ def install(path): # Make sure the extension manager does not overwrite # extensions that are already installed for ext in instance.extensionList(): - if extName == ext: - return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(ext) + if extName == ext.name: + return "The extension \"{}\" is already installed. Uninstall it before trying again.".format(extName) extZip.extractall(instance.extensionDir().absolutePath()) extZip.close() except Exception as e: diff --git a/python/extensionmanager/list.py b/python/extensionmanager/list.py index d213c35..32002b1 100644 --- a/python/extensionmanager/list.py +++ b/python/extensionmanager/list.py @@ -58,11 +58,11 @@ class ExtensionList(QtWidgets.QListWidget): i = 0 for ext in instance.extensionList(): item = QtWidgets.QListWidgetItem(self) - if not ext in instance.extensionList(True): - item.setText(ext + " [did not load]") + if not ext.loaded: + item.setText(ext.name + " [did not load]") item.setIcon(QtGui.QIcon.fromTheme("dialog-error")) else: - item.setText(ext) + item.setText(ext.name) item.setIcon(QtGui.QIcon.fromTheme("applications-development")) if i % 2 == 1: item.setBackground(QtGui.QBrush(QtGui.QColor.fromRgb(240, 240, 240))) -- cgit v1.2.3