Python: detect pythons async

Change-Id: I74484a4f2c33c4fd7754f87bfbf3b9d711542741
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2023-09-20 14:28:21 +02:00
parent 4e90ca1b59
commit 2c298097e9

View File

@@ -21,13 +21,14 @@
#include <texteditor/texteditor.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/async.h>
#include <utils/detailswidget.h>
#include <utils/environment.h>
#include <utils/listmodel.h>
#include <utils/layoutbuilder.h>
#include <utils/listmodel.h>
#include <utils/pathchooser.h>
#include <utils/process.h>
#include <utils/qtcassert.h>
#include <utils/treemodel.h>
#include <utils/utilsicons.h>
@@ -366,14 +367,6 @@ private:
InterpreterOptionsWidget *m_widget = nullptr;
};
static bool alreadyRegistered(const QList<Interpreter> &pythons, const FilePath &pythonExecutable)
{
return Utils::anyOf(pythons, [pythonExecutable](const Interpreter &interpreter) {
return interpreter.command.toFileInfo().canonicalFilePath()
== pythonExecutable.toFileInfo().canonicalFilePath();
});
}
static InterpreterOptionsPage &interpreterOptionsPage()
{
static InterpreterOptionsPage page;
@@ -626,8 +619,9 @@ static void disableOutdatedPyls()
}
}
static void addPythonsFromRegistry(QList<Interpreter> &pythons)
static QList<Interpreter> pythonsFromRegistry()
{
QList<Interpreter> pythons;
QSettings pythonRegistry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore",
QSettings::NativeFormat);
for (const QString &versionGroup : pythonRegistry.childGroups()) {
@@ -636,7 +630,7 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
QVariant regVal = pythonRegistry.value("InstallPath/ExecutablePath");
if (regVal.isValid()) {
const FilePath &executable = FilePath::fromUserInput(regVal.toString());
if (executable.exists() && !alreadyRegistered(pythons, executable)) {
if (executable.exists()) {
pythons << Interpreter{QUuid::createUuid().toString(),
name,
FilePath::fromUserInput(regVal.toString())};
@@ -645,7 +639,7 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
regVal = pythonRegistry.value("InstallPath/WindowedExecutablePath");
if (regVal.isValid()) {
const FilePath &executable = FilePath::fromUserInput(regVal.toString());
if (executable.exists() && !alreadyRegistered(pythons, executable)) {
if (executable.exists()) {
pythons << Interpreter{QUuid::createUuid().toString(),
//: <python display name> (Windowed)
Tr::tr("%1 (Windowed)").arg(name),
@@ -656,28 +650,30 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
if (regVal.isValid()) {
const FilePath &path = FilePath::fromUserInput(regVal.toString());
const FilePath python = path.pathAppended("python").withExecutableSuffix();
if (python.exists() && !alreadyRegistered(pythons, python))
if (python.exists())
pythons << createInterpreter(python, "Python " + versionGroup);
const FilePath pythonw = path.pathAppended("pythonw").withExecutableSuffix();
if (pythonw.exists() && !alreadyRegistered(pythons, pythonw))
if (pythonw.exists())
pythons << createInterpreter(pythonw, "Python " + versionGroup, "(Windowed)");
}
pythonRegistry.endGroup();
}
return pythons;
}
static void addPythonsFromPath(QList<Interpreter> &pythons)
static QList<Interpreter> pythonsFromPath()
{
QList<Interpreter> pythons;
if (HostOsInfo::isWindowsHost()) {
for (const FilePath &executable : FilePath("python").searchAllInPath()) {
// Windows creates empty redirector files that may interfere
if (executable.toFileInfo().size() == 0)
continue;
if (executable.exists() && !alreadyRegistered(pythons, executable))
if (executable.exists())
pythons << createInterpreter(executable, "Python from Path");
}
for (const FilePath &executable : FilePath("pythonw").searchAllInPath()) {
if (executable.exists() && !alreadyRegistered(pythons, executable))
if (executable.exists())
pythons << createInterpreter(executable, "Python from Path", "(Windowed)");
}
} else {
@@ -690,11 +686,12 @@ static void addPythonsFromPath(QList<Interpreter> &pythons)
const QDir dir(path.toString());
for (const QFileInfo &fi : dir.entryInfoList(filters)) {
const FilePath executable = Utils::FilePath::fromFileInfo(fi);
if (executable.exists() && !alreadyRegistered(pythons, executable))
if (executable.exists())
pythons << createInterpreter(executable, "Python from Path");
}
}
}
return pythons;
}
static QString idForPythonFromPath(const QList<Interpreter> &pythons)
@@ -713,6 +710,51 @@ static QString idForPythonFromPath(const QList<Interpreter> &pythons)
static PythonSettings *settingsInstance = nullptr;
static bool alreadyRegistered(const Interpreter &candidate)
{
return Utils::anyOf(settingsInstance->interpreters(),
[candidate = candidate.command](const Interpreter &interpreter) {
return interpreter.command.isSameDevice(candidate)
&& interpreter.command.resolveSymlinks()
== candidate.resolveSymlinks();
});
}
static void scanPath()
{
auto watcher = new QFutureWatcher<QList<Interpreter>>();
QObject::connect(watcher, &QFutureWatcher<QList<Interpreter>>::finished, [watcher]() {
for (const Interpreter &interpreter : watcher->result()) {
if (!alreadyRegistered(interpreter))
settingsInstance->addInterpreter(interpreter);
}
watcher->deleteLater();
});
watcher->setFuture(Utils::asyncRun(pythonsFromPath));
}
static void scanRegistry()
{
auto watcher = new QFutureWatcher<QList<Interpreter>>();
QObject::connect(watcher, &QFutureWatcher<QList<Interpreter>>::finished, [watcher]() {
for (const Interpreter &interpreter : watcher->result()) {
if (!alreadyRegistered(interpreter))
settingsInstance->addInterpreter(interpreter);
}
watcher->deleteLater();
scanPath();
});
watcher->setFuture(Utils::asyncRun(pythonsFromRegistry));
}
static void scanSystemForInterpreters()
{
if (Utils::HostOsInfo::isWindowsHost())
scanRegistry();
else
scanPath();
}
PythonSettings::PythonSettings()
{
QTC_ASSERT(!settingsInstance, return);
@@ -723,9 +765,7 @@ PythonSettings::PythonSettings()
initFromSettings(Core::ICore::settings());
if (HostOsInfo::isWindowsHost())
addPythonsFromRegistry(m_interpreters);
addPythonsFromPath(m_interpreters);
scanSystemForInterpreters();
if (m_defaultInterpreterId.isEmpty())
m_defaultInterpreterId = idForPythonFromPath(m_interpreters);