2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2022-03-16 09:35:02 +01:00
|
|
|
|
|
|
|
|
#include "pyside.h"
|
|
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
#include "pipsupport.h"
|
2022-03-16 09:35:02 +01:00
|
|
|
#include "pythonplugin.h"
|
|
|
|
|
#include "pythonsettings.h"
|
2022-07-15 11:49:34 +02:00
|
|
|
#include "pythontr.h"
|
2022-03-16 09:35:02 +01:00
|
|
|
#include "pythonutils.h"
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
2022-04-13 12:26:54 +02:00
|
|
|
|
|
|
|
|
#include <projectexplorer/runconfigurationaspects.h>
|
2022-03-16 09:35:02 +01:00
|
|
|
#include <projectexplorer/target.h>
|
2022-04-13 12:26:54 +02:00
|
|
|
|
2022-03-16 09:35:02 +01:00
|
|
|
#include <texteditor/textdocument.h>
|
2022-04-13 12:26:54 +02:00
|
|
|
|
2022-03-16 09:35:02 +01:00
|
|
|
#include <utils/algorithm.h>
|
2023-03-09 17:11:29 +01:00
|
|
|
#include <utils/asynctask.h>
|
2022-03-16 09:35:02 +01:00
|
|
|
#include <utils/infobar.h>
|
2022-07-27 12:38:07 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2022-07-15 11:49:34 +02:00
|
|
|
#include <utils/qtcprocess.h>
|
2022-03-16 09:35:02 +01:00
|
|
|
|
|
|
|
|
#include <QRegularExpression>
|
|
|
|
|
#include <QTextCursor>
|
|
|
|
|
|
|
|
|
|
using namespace Utils;
|
2022-04-13 12:26:54 +02:00
|
|
|
using namespace ProjectExplorer;
|
2022-03-16 09:35:02 +01:00
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
namespace Python::Internal {
|
2022-03-16 09:35:02 +01:00
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
const char installPySideInfoBarId[] = "Python::InstallPySide";
|
2022-03-16 09:35:02 +01:00
|
|
|
|
|
|
|
|
PySideInstaller *PySideInstaller::instance()
|
|
|
|
|
{
|
2022-07-15 11:49:34 +02:00
|
|
|
static PySideInstaller *instance = new PySideInstaller; // FIXME: Leaks.
|
2022-03-16 09:35:02 +01:00
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-26 10:21:12 +02:00
|
|
|
void PySideInstaller::checkPySideInstallation(const FilePath &python,
|
2022-03-16 09:35:02 +01:00
|
|
|
TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
document->infoBar()->removeInfo(installPySideInfoBarId);
|
|
|
|
|
const QString pySide = importedPySide(document->plainText());
|
|
|
|
|
if (pySide == "PySide2" || pySide == "PySide6")
|
2022-04-26 10:21:12 +02:00
|
|
|
instance()->runPySideChecker(python, pySide, document);
|
2022-03-16 09:35:02 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-26 10:21:12 +02:00
|
|
|
bool PySideInstaller::missingPySideInstallation(const FilePath &pythonPath,
|
2022-03-16 09:35:02 +01:00
|
|
|
const QString &pySide)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!pySide.isEmpty(), return false);
|
|
|
|
|
static QMap<FilePath, QSet<QString>> pythonWithPyside;
|
|
|
|
|
if (pythonWithPyside[pythonPath].contains(pySide))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
QtcProcess pythonProcess;
|
2022-04-26 10:21:12 +02:00
|
|
|
pythonProcess.setCommand({pythonPath, {"-c", "import " + pySide}});
|
2022-03-16 09:35:02 +01:00
|
|
|
pythonProcess.runBlocking();
|
|
|
|
|
const bool missing = pythonProcess.result() != ProcessResult::FinishedWithSuccess;
|
|
|
|
|
if (!missing)
|
|
|
|
|
pythonWithPyside[pythonPath].insert(pySide);
|
|
|
|
|
return missing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PySideInstaller::importedPySide(const QString &text)
|
|
|
|
|
{
|
|
|
|
|
static QRegularExpression importScanner("^\\s*(import|from)\\s+(PySide\\d)",
|
|
|
|
|
QRegularExpression::MultilineOption);
|
|
|
|
|
const QRegularExpressionMatch match = importScanner.match(text);
|
|
|
|
|
return match.captured(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PySideInstaller::PySideInstaller()
|
|
|
|
|
: QObject(PythonPlugin::instance())
|
|
|
|
|
{}
|
|
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
void PySideInstaller::installPyside(const FilePath &python,
|
2022-03-16 09:35:02 +01:00
|
|
|
const QString &pySide,
|
|
|
|
|
TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
document->infoBar()->removeInfo(installPySideInfoBarId);
|
|
|
|
|
|
|
|
|
|
auto install = new PipInstallTask(python);
|
|
|
|
|
connect(install, &PipInstallTask::finished, install, &QObject::deleteLater);
|
2022-06-16 15:33:32 +02:00
|
|
|
connect(install, &PipInstallTask::finished, this, [=](bool success){
|
|
|
|
|
if (success)
|
|
|
|
|
emit pySideInstalled(python, pySide);
|
|
|
|
|
});
|
2023-01-24 11:28:28 +01:00
|
|
|
install->setPackages({PipPackage(pySide)});
|
2022-03-16 09:35:02 +01:00
|
|
|
install->run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PySideInstaller::handlePySideMissing(const FilePath &python,
|
|
|
|
|
const QString &pySide,
|
|
|
|
|
TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
if (!document || !document->infoBar()->canInfoBeAdded(installPySideInfoBarId))
|
|
|
|
|
return;
|
2022-07-15 11:49:34 +02:00
|
|
|
const QString message = Tr::tr("%1 installation missing for %2 (%3)")
|
2022-03-16 09:35:02 +01:00
|
|
|
.arg(pySide, pythonName(python), python.toUserOutput());
|
|
|
|
|
InfoBarEntry info(installPySideInfoBarId, message, InfoBarEntry::GlobalSuppression::Enabled);
|
|
|
|
|
auto installCallback = [=]() { installPyside(python, pySide, document); };
|
2022-07-15 11:49:34 +02:00
|
|
|
const QString installTooltip = Tr::tr("Install %1 for %2 using pip package installer.")
|
2022-03-16 09:35:02 +01:00
|
|
|
.arg(pySide, python.toUserOutput());
|
2022-07-15 11:49:34 +02:00
|
|
|
info.addCustomButton(Tr::tr("Install"), installCallback, installTooltip);
|
2022-03-16 09:35:02 +01:00
|
|
|
document->infoBar()->addInfo(info);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
void PySideInstaller::runPySideChecker(const FilePath &python,
|
2022-03-16 09:35:02 +01:00
|
|
|
const QString &pySide,
|
|
|
|
|
TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
using CheckPySideWatcher = QFutureWatcher<bool>;
|
|
|
|
|
|
|
|
|
|
QPointer<CheckPySideWatcher> watcher = new CheckPySideWatcher();
|
|
|
|
|
|
|
|
|
|
// cancel and delete watcher after a 10 second timeout
|
|
|
|
|
QTimer::singleShot(10000, this, [watcher]() {
|
|
|
|
|
if (watcher) {
|
|
|
|
|
watcher->cancel();
|
|
|
|
|
watcher->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
connect(watcher,
|
|
|
|
|
&CheckPySideWatcher::resultReadyAt,
|
|
|
|
|
this,
|
|
|
|
|
[=, document = QPointer<TextEditor::TextDocument>(document)]() {
|
|
|
|
|
if (watcher->result())
|
|
|
|
|
handlePySideMissing(python, pySide, document);
|
|
|
|
|
watcher->deleteLater();
|
|
|
|
|
});
|
2023-03-09 17:11:29 +01:00
|
|
|
watcher->setFuture(Utils::asyncRun(&missingPySideInstallation, python, pySide));
|
2022-03-16 09:35:02 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
} // Python::Internal
|