summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/python/pipsupport.cpp83
-rw-r--r--src/plugins/python/pipsupport.h44
-rw-r--r--src/plugins/python/pythonrunconfiguration.cpp100
-rw-r--r--src/plugins/python/pythonrunconfiguration.h9
4 files changed, 161 insertions, 75 deletions
diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp
index 8c98bd423d..848184b462 100644
--- a/src/plugins/python/pipsupport.cpp
+++ b/src/plugins/python/pipsupport.cpp
@@ -3,6 +3,7 @@
#include "pipsupport.h"
+#include "pythonplugin.h"
#include "pythontr.h"
#include <coreplugin/messagemanager.h>
@@ -15,6 +16,7 @@
#include <utils/algorithm.h>
#include <utils/mimeutils.h>
#include <utils/qtcprocess.h>
+#include <utils/runextensions.h>
using namespace Utils;
@@ -100,36 +102,6 @@ void PipInstallTask::handleError()
Core::MessageManager::writeSilently(stdErr);
}
-PipPackageInfo PipPackage::info(const FilePath &python) const
-{
- PipPackageInfo result;
-
- QtcProcess pip;
- pip.setCommand(CommandLine(python, {"-m", "pip", "show", "-f", packageName}));
- pip.runBlocking();
- QString fieldName;
- QStringList data;
- const QString pipOutput = pip.allOutput();
- for (const QString &line : pipOutput.split('\n')) {
- if (line.isEmpty())
- continue;
- if (line.front().isSpace()) {
- data.append(line.trimmed());
- } else {
- result.parseField(fieldName, data);
- if (auto colonPos = line.indexOf(':'); colonPos >= 0) {
- fieldName = line.left(colonPos);
- data = QStringList(line.mid(colonPos + 1).trimmed());
- } else {
- fieldName.clear();
- data.clear();
- }
- }
- }
- result.parseField(fieldName, data);
- return result;
-}
-
void PipPackageInfo::parseField(const QString &field, const QStringList &data)
{
if (field.isEmpty())
@@ -162,4 +134,55 @@ void PipPackageInfo::parseField(const QString &field, const QStringList &data)
}
}
+Pip *Pip::instance(const FilePath &python)
+{
+ static QMap<FilePath, Pip *> pips;
+ auto it = pips.find(python);
+ if (it == pips.end())
+ it = pips.insert(python, new Pip(python));
+ return it.value();
+}
+
+QFuture<PipPackageInfo> Pip::info(const PipPackage &package)
+{
+ return Utils::runAsync(&Pip::infoImpl, this, package);
+}
+
+PipPackageInfo Pip::infoImpl(const PipPackage &package)
+{
+ PipPackageInfo result;
+
+ QtcProcess pip;
+ pip.setCommand(CommandLine(m_python, {"-m", "pip", "show", "-f", package.packageName}));
+ m_lock.lock();
+ pip.runBlocking();
+ m_lock.unlock();
+ QString fieldName;
+ QStringList data;
+ const QString pipOutput = pip.allOutput();
+ for (const QString &line : pipOutput.split('\n')) {
+ if (line.isEmpty())
+ continue;
+ if (line.front().isSpace()) {
+ data.append(line.trimmed());
+ } else {
+ result.parseField(fieldName, data);
+ if (auto colonPos = line.indexOf(':'); colonPos >= 0) {
+ fieldName = line.left(colonPos);
+ data = QStringList(line.mid(colonPos + 1).trimmed());
+ } else {
+ fieldName.clear();
+ data.clear();
+ }
+ }
+ }
+ result.parseField(fieldName, data);
+ return result;
+}
+
+Pip::Pip(const Utils::FilePath &python)
+ : QObject(PythonPlugin::instance())
+ , m_python(python)
+{}
+
} // Python::Internal
diff --git a/src/plugins/python/pipsupport.h b/src/plugins/python/pipsupport.h
index a26360392d..e5f53768ce 100644
--- a/src/plugins/python/pipsupport.h
+++ b/src/plugins/python/pipsupport.h
@@ -12,7 +12,23 @@
namespace Python::Internal {
-class PipPackageInfo;
+class PipPackageInfo
+{
+public:
+ QString name;
+ QString version;
+ QString summary;
+ QUrl homePage;
+ QString author;
+ QString authorEmail;
+ QString license;
+ Utils::FilePath location;
+ QStringList requiresPackage;
+ QStringList requiredByPackage;
+ Utils::FilePaths files;
+
+ void parseField(const QString &field, const QStringList &value);
+};
class PipPackage
{
@@ -27,26 +43,22 @@ public:
QString packageName;
QString displayName;
QString version;
-
- PipPackageInfo info(const Utils::FilePath &python) const;
};
-class PipPackageInfo
+class Pip : public QObject
{
public:
- QString name;
- QString version;
- QString summary;
- QUrl homePage;
- QString author;
- QString authorEmail;
- QString license;
- Utils::FilePath location;
- QStringList requiresPackage;
- QStringList requiredByPackage;
- Utils::FilePaths files;
+ static Pip *instance(const Utils::FilePath &python);
- void parseField(const QString &field, const QStringList &value);
+ QFuture<PipPackageInfo> info(const PipPackage &package);
+
+private:
+ Pip(const Utils::FilePath &python);
+
+ PipPackageInfo infoImpl(const PipPackage &package);
+
+ QMutex m_lock;
+ Utils::FilePath m_python;
};
class PipInstallTask : public QObject
diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp
index 480f3f153f..2163e2b7ed 100644
--- a/src/plugins/python/pythonrunconfiguration.cpp
+++ b/src/plugins/python/pythonrunconfiguration.cpp
@@ -117,8 +117,35 @@ private:
////////////////////////////////////////////////////////////////
+class PythonRunConfigurationPrivate
+{
+public:
+ PythonRunConfigurationPrivate(PythonRunConfiguration *rc)
+ : q(rc)
+ {}
+ ~PythonRunConfigurationPrivate()
+ {
+ qDeleteAll(m_extraCompilers);
+ }
+
+ void checkForPySide(const Utils::FilePath &python);
+ void checkForPySide(const Utils::FilePath &python, const QString &pySidePackageName);
+ void handlePySidePackageInfo(const PipPackageInfo &pySideInfo,
+ const Utils::FilePath &python,
+ const QString &requestedPackageName);
+ void updateExtraCompilers();
+ Utils::FilePath m_pySideUicPath;
+
+ PythonRunConfiguration *q;
+ QList<PySideUicExtraCompiler *> m_extraCompilers;
+ QFutureWatcher<PipPackageInfo> m_watcher;
+ QMetaObject::Connection m_watcherConnection;
+
+};
+
PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id)
: RunConfiguration(target, id)
+ , d(new PythonRunConfigurationPrivate(this))
{
auto interpreterAspect = addAspect<InterpreterAspect>();
interpreterAspect->setSettingsKey("PythonEditor.RunConfiguation.Interpreter");
@@ -185,7 +212,7 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id)
});
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
- connect(target, &Target::buildSystemUpdated, this, &PythonRunConfiguration::updateExtraCompilers);
+ connect(target, &Target::buildSystemUpdated, this, [this]() { d->updateExtraCompilers(); });
currentInterpreterChanged();
setRunnableModifier([](Runnable &r) {
@@ -195,25 +222,53 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id)
connect(PySideInstaller::instance(), &PySideInstaller::pySideInstalled, this,
[this](const FilePath &python) {
if (python == aspect<InterpreterAspect>()->currentInterpreter().command)
- checkForPySide(python);
+ d->checkForPySide(python);
});
}
PythonRunConfiguration::~PythonRunConfiguration()
{
- qDeleteAll(m_extraCompilers);
+ delete d;
}
-struct PythonTools
+void PythonRunConfigurationPrivate::checkForPySide(const FilePath &python)
{
- FilePath pySideProjectPath;
- FilePath pySideUicPath;
-};
+ checkForPySide(python, "PySide6-Essentials");
+}
+
+void PythonRunConfigurationPrivate::checkForPySide(const FilePath &python,
+ const QString &pySidePackageName)
+{
+ const PipPackage package(pySidePackageName);
+ QObject::disconnect(m_watcherConnection);
+ m_watcherConnection = QObject::connect(&m_watcher,
+ &QFutureWatcher<PipPackageInfo>::finished,
+ q,
+ [=]() {
+ handlePySidePackageInfo(m_watcher.result(),
+ python,
+ pySidePackageName);
+ });
+ m_watcher.setFuture(Pip::instance(python)->info(package));
+}
-void PythonRunConfiguration::checkForPySide(const FilePath &python)
+void PythonRunConfigurationPrivate::handlePySidePackageInfo(const PipPackageInfo &pySideInfo,
+ const Utils::FilePath &python,
+ const QString &requestedPackageName)
{
- BuildStepList *buildSteps = target()->activeBuildConfiguration()->buildSteps();
+ struct PythonTools
+ {
+ FilePath pySideProjectPath;
+ FilePath pySideUicPath;
+ };
+ BuildStepList *buildSteps = nullptr;
+ if (Target *target = q->target()) {
+ if (auto buildConfiguration = target->activeBuildConfiguration())
+ buildSteps = buildConfiguration->buildSteps();
+ }
+ if (!buildSteps)
+ return;
const auto findPythonTools = [](const FilePaths &files,
const FilePath &location,
@@ -239,13 +294,10 @@ void PythonRunConfiguration::checkForPySide(const FilePath &python)
return {};
};
- const PipPackage pySide6EssentialPackage("PySide6-Essentials");
- PipPackageInfo info = pySide6EssentialPackage.info(python);
- PythonTools pythonTools = findPythonTools(info.files, info.location, python);
- if (!pythonTools.pySideProjectPath.isExecutableFile()) {
- const PipPackage pySide6Package("PySide6");
- info = pySide6Package.info(python);
- pythonTools = findPythonTools(info.files, info.location, python);
+ PythonTools pythonTools = findPythonTools(pySideInfo.files, pySideInfo.location, python);
+ if (!pythonTools.pySideProjectPath.isExecutableFile() && requestedPackageName != "PySide6") {
+ checkForPySide(python, "PySide6");
+ return;
}
m_pySideUicPath = pythonTools.pySideUicPath;
@@ -259,7 +311,7 @@ void PythonRunConfiguration::checkForPySide(const FilePath &python)
void PythonRunConfiguration::currentInterpreterChanged()
{
const FilePath python = aspect<InterpreterAspect>()->currentInterpreter().command;
- checkForPySide(python);
+ d->checkForPySide(python);
for (FilePath &file : project()->files(Project::AllFiles)) {
if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) {
@@ -274,10 +326,10 @@ void PythonRunConfiguration::currentInterpreterChanged()
QList<PySideUicExtraCompiler *> PythonRunConfiguration::extraCompilers() const
{
- return m_extraCompilers;
+ return d->m_extraCompilers;
}
-void PythonRunConfiguration::updateExtraCompilers()
+void PythonRunConfigurationPrivate::updateExtraCompilers()
{
QList<PySideUicExtraCompiler *> oldCompilers = m_extraCompilers;
m_extraCompilers.clear();
@@ -288,21 +340,21 @@ void PythonRunConfiguration::updateExtraCompilers()
return fileNode->fileType() == ProjectExplorer::FileType::Form;
return false;
};
- const FilePaths uiFiles = project()->files(uiMatcher);
+ const FilePaths uiFiles = q->project()->files(uiMatcher);
for (const FilePath &uiFile : uiFiles) {
FilePath generated = uiFile.parentDir();
generated = generated.pathAppended("/ui_" + uiFile.baseName() + ".py");
int index = Utils::indexOf(oldCompilers, [&](PySideUicExtraCompiler *oldCompiler) {
return oldCompiler->pySideUicPath() == m_pySideUicPath
- && oldCompiler->project() == project() && oldCompiler->source() == uiFile
+ && oldCompiler->project() == q->project() && oldCompiler->source() == uiFile
&& oldCompiler->targets() == FilePaths{generated};
});
if (index < 0) {
m_extraCompilers << new PySideUicExtraCompiler(m_pySideUicPath,
- project(),
+ q->project(),
uiFile,
{generated},
- this);
+ q);
} else {
m_extraCompilers << oldCompilers.takeAt(index);
}
@@ -310,7 +362,7 @@ void PythonRunConfiguration::updateExtraCompilers()
}
for (LanguageClient::Client *client : LanguageClient::LanguageClientManager::clients()) {
if (auto pylsClient = qobject_cast<PyLSClient *>(client))
- pylsClient->updateExtraCompilers(project(), m_extraCompilers);
+ pylsClient->updateExtraCompilers(q->project(), m_extraCompilers);
}
qDeleteAll(oldCompilers);
}
diff --git a/src/plugins/python/pythonrunconfiguration.h b/src/plugins/python/pythonrunconfiguration.h
index 0def9af0a2..605e3c42aa 100644
--- a/src/plugins/python/pythonrunconfiguration.h
+++ b/src/plugins/python/pythonrunconfiguration.h
@@ -6,8 +6,11 @@
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/runcontrol.h>
+#include <QFutureWatcher>
+
namespace Python::Internal {
+class PythonRunConfigurationPrivate;
class PySideUicExtraCompiler;
class PythonRunConfiguration : public ProjectExplorer::RunConfiguration
@@ -20,11 +23,7 @@ public:
QList<PySideUicExtraCompiler *> extraCompilers() const;
private:
- void checkForPySide(const Utils::FilePath &python);
- void updateExtraCompilers();
- Utils::FilePath m_pySideUicPath;
-
- QList<PySideUicExtraCompiler *> m_extraCompilers;
+ PythonRunConfigurationPrivate *d = nullptr;
};
class PythonRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory