forked from qt-creator/qt-creator
Python: detect pythons async
Change-Id: I74484a4f2c33c4fd7754f87bfbf3b9d711542741 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -21,13 +21,14 @@
|
|||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/async.h>
|
||||||
#include <utils/detailswidget.h>
|
#include <utils/detailswidget.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/listmodel.h>
|
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
|
#include <utils/listmodel.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/treemodel.h>
|
#include <utils/treemodel.h>
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
@@ -366,14 +367,6 @@ private:
|
|||||||
InterpreterOptionsWidget *m_widget = nullptr;
|
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 &interpreterOptionsPage()
|
||||||
{
|
{
|
||||||
static InterpreterOptionsPage page;
|
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 pythonRegistry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore",
|
||||||
QSettings::NativeFormat);
|
QSettings::NativeFormat);
|
||||||
for (const QString &versionGroup : pythonRegistry.childGroups()) {
|
for (const QString &versionGroup : pythonRegistry.childGroups()) {
|
||||||
@@ -636,7 +630,7 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
|
|||||||
QVariant regVal = pythonRegistry.value("InstallPath/ExecutablePath");
|
QVariant regVal = pythonRegistry.value("InstallPath/ExecutablePath");
|
||||||
if (regVal.isValid()) {
|
if (regVal.isValid()) {
|
||||||
const FilePath &executable = FilePath::fromUserInput(regVal.toString());
|
const FilePath &executable = FilePath::fromUserInput(regVal.toString());
|
||||||
if (executable.exists() && !alreadyRegistered(pythons, executable)) {
|
if (executable.exists()) {
|
||||||
pythons << Interpreter{QUuid::createUuid().toString(),
|
pythons << Interpreter{QUuid::createUuid().toString(),
|
||||||
name,
|
name,
|
||||||
FilePath::fromUserInput(regVal.toString())};
|
FilePath::fromUserInput(regVal.toString())};
|
||||||
@@ -645,7 +639,7 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
|
|||||||
regVal = pythonRegistry.value("InstallPath/WindowedExecutablePath");
|
regVal = pythonRegistry.value("InstallPath/WindowedExecutablePath");
|
||||||
if (regVal.isValid()) {
|
if (regVal.isValid()) {
|
||||||
const FilePath &executable = FilePath::fromUserInput(regVal.toString());
|
const FilePath &executable = FilePath::fromUserInput(regVal.toString());
|
||||||
if (executable.exists() && !alreadyRegistered(pythons, executable)) {
|
if (executable.exists()) {
|
||||||
pythons << Interpreter{QUuid::createUuid().toString(),
|
pythons << Interpreter{QUuid::createUuid().toString(),
|
||||||
//: <python display name> (Windowed)
|
//: <python display name> (Windowed)
|
||||||
Tr::tr("%1 (Windowed)").arg(name),
|
Tr::tr("%1 (Windowed)").arg(name),
|
||||||
@@ -656,28 +650,30 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
|
|||||||
if (regVal.isValid()) {
|
if (regVal.isValid()) {
|
||||||
const FilePath &path = FilePath::fromUserInput(regVal.toString());
|
const FilePath &path = FilePath::fromUserInput(regVal.toString());
|
||||||
const FilePath python = path.pathAppended("python").withExecutableSuffix();
|
const FilePath python = path.pathAppended("python").withExecutableSuffix();
|
||||||
if (python.exists() && !alreadyRegistered(pythons, python))
|
if (python.exists())
|
||||||
pythons << createInterpreter(python, "Python " + versionGroup);
|
pythons << createInterpreter(python, "Python " + versionGroup);
|
||||||
const FilePath pythonw = path.pathAppended("pythonw").withExecutableSuffix();
|
const FilePath pythonw = path.pathAppended("pythonw").withExecutableSuffix();
|
||||||
if (pythonw.exists() && !alreadyRegistered(pythons, pythonw))
|
if (pythonw.exists())
|
||||||
pythons << createInterpreter(pythonw, "Python " + versionGroup, "(Windowed)");
|
pythons << createInterpreter(pythonw, "Python " + versionGroup, "(Windowed)");
|
||||||
}
|
}
|
||||||
pythonRegistry.endGroup();
|
pythonRegistry.endGroup();
|
||||||
}
|
}
|
||||||
|
return pythons;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addPythonsFromPath(QList<Interpreter> &pythons)
|
static QList<Interpreter> pythonsFromPath()
|
||||||
{
|
{
|
||||||
|
QList<Interpreter> pythons;
|
||||||
if (HostOsInfo::isWindowsHost()) {
|
if (HostOsInfo::isWindowsHost()) {
|
||||||
for (const FilePath &executable : FilePath("python").searchAllInPath()) {
|
for (const FilePath &executable : FilePath("python").searchAllInPath()) {
|
||||||
// Windows creates empty redirector files that may interfere
|
// Windows creates empty redirector files that may interfere
|
||||||
if (executable.toFileInfo().size() == 0)
|
if (executable.toFileInfo().size() == 0)
|
||||||
continue;
|
continue;
|
||||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
if (executable.exists())
|
||||||
pythons << createInterpreter(executable, "Python from Path");
|
pythons << createInterpreter(executable, "Python from Path");
|
||||||
}
|
}
|
||||||
for (const FilePath &executable : FilePath("pythonw").searchAllInPath()) {
|
for (const FilePath &executable : FilePath("pythonw").searchAllInPath()) {
|
||||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
if (executable.exists())
|
||||||
pythons << createInterpreter(executable, "Python from Path", "(Windowed)");
|
pythons << createInterpreter(executable, "Python from Path", "(Windowed)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -690,11 +686,12 @@ static void addPythonsFromPath(QList<Interpreter> &pythons)
|
|||||||
const QDir dir(path.toString());
|
const QDir dir(path.toString());
|
||||||
for (const QFileInfo &fi : dir.entryInfoList(filters)) {
|
for (const QFileInfo &fi : dir.entryInfoList(filters)) {
|
||||||
const FilePath executable = Utils::FilePath::fromFileInfo(fi);
|
const FilePath executable = Utils::FilePath::fromFileInfo(fi);
|
||||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
if (executable.exists())
|
||||||
pythons << createInterpreter(executable, "Python from Path");
|
pythons << createInterpreter(executable, "Python from Path");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return pythons;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString idForPythonFromPath(const QList<Interpreter> &pythons)
|
static QString idForPythonFromPath(const QList<Interpreter> &pythons)
|
||||||
@@ -713,6 +710,51 @@ static QString idForPythonFromPath(const QList<Interpreter> &pythons)
|
|||||||
|
|
||||||
static PythonSettings *settingsInstance = nullptr;
|
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()
|
PythonSettings::PythonSettings()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!settingsInstance, return);
|
QTC_ASSERT(!settingsInstance, return);
|
||||||
@@ -723,9 +765,7 @@ PythonSettings::PythonSettings()
|
|||||||
|
|
||||||
initFromSettings(Core::ICore::settings());
|
initFromSettings(Core::ICore::settings());
|
||||||
|
|
||||||
if (HostOsInfo::isWindowsHost())
|
scanSystemForInterpreters();
|
||||||
addPythonsFromRegistry(m_interpreters);
|
|
||||||
addPythonsFromPath(m_interpreters);
|
|
||||||
|
|
||||||
if (m_defaultInterpreterId.isEmpty())
|
if (m_defaultInterpreterId.isEmpty())
|
||||||
m_defaultInterpreterId = idForPythonFromPath(m_interpreters);
|
m_defaultInterpreterId = idForPythonFromPath(m_interpreters);
|
||||||
|
|||||||
Reference in New Issue
Block a user