forked from qt-creator/qt-creator
Docker: detect python in docker images
Change-Id: I841cdb7ce1cb8f34565a5e6993c5c825937e3eab Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -110,6 +110,16 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<ItemData> allData(const std::function<bool(const ItemData &)> &pred) const
|
||||||
|
{
|
||||||
|
QList<ItemData> res;
|
||||||
|
BaseModel::rootItem()->forFirstLevelChildren([pred, &res](ChildType *item) {
|
||||||
|
if (pred(item->itemData))
|
||||||
|
res.append(item->itemData);
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void setAllData(const QList<ItemData> &items)
|
void setAllData(const QList<ItemData> &items)
|
||||||
{
|
{
|
||||||
BaseModel::rootItem()->removeChildren();
|
BaseModel::rootItem()->removeChildren();
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
QtVersions autoDetectQtVersions() const;
|
QtVersions autoDetectQtVersions() const;
|
||||||
QList<ToolChain *> autoDetectToolChains();
|
QList<ToolChain *> autoDetectToolChains();
|
||||||
|
void autoDetectPython();
|
||||||
QList<Id> autoDetectCMake();
|
QList<Id> autoDetectCMake();
|
||||||
void autoDetectDebugger();
|
void autoDetectDebugger();
|
||||||
|
|
||||||
@@ -133,6 +134,16 @@ void KitDetectorPrivate::undoAutoDetect() const
|
|||||||
emit q->logOutput('\n' + logMessage);
|
emit q->logOutput('\n' + logMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto pythonSettings = ExtensionSystem::PluginManager::getObjectByName("PythonSettings")) {
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(pythonSettings,
|
||||||
|
"removeDetectedPython",
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
emit q->logOutput('\n' + ProjectExplorer::Tr::tr("Removal of previously auto-detected kit items finished.") + "\n\n");
|
emit q->logOutput('\n' + ProjectExplorer::Tr::tr("Removal of previously auto-detected kit items finished.") + "\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +191,16 @@ void KitDetectorPrivate::listAutoDetected() const
|
|||||||
emit q->logOutput('\n' + logMessage);
|
emit q->logOutput('\n' + logMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto pythonSettings = ExtensionSystem::PluginManager::getObjectByName("PythonSettings")) {
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(pythonSettings,
|
||||||
|
"listDetectedPython",
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
emit q->logOutput('\n' + ProjectExplorer::Tr::tr("Listing of previously auto-detected kit items finished.") + "\n\n");
|
emit q->logOutput('\n' + ProjectExplorer::Tr::tr("Listing of previously auto-detected kit items finished.") + "\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +273,23 @@ Toolchains KitDetectorPrivate::autoDetectToolChains()
|
|||||||
return allNewToolChains;
|
return allNewToolChains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KitDetectorPrivate::autoDetectPython()
|
||||||
|
{
|
||||||
|
QObject *pythonSettings = ExtensionSystem::PluginManager::getObjectByName("PythonSettings");
|
||||||
|
if (!pythonSettings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(pythonSettings,
|
||||||
|
"detectPythonOnDevice",
|
||||||
|
Q_ARG(Utils::FilePaths, m_searchPaths),
|
||||||
|
Q_ARG(QString, m_device->displayName()),
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
QList<Id> KitDetectorPrivate::autoDetectCMake()
|
QList<Id> KitDetectorPrivate::autoDetectCMake()
|
||||||
{
|
{
|
||||||
QList<Id> result;
|
QList<Id> result;
|
||||||
@@ -302,6 +340,7 @@ void KitDetectorPrivate::autoDetect()
|
|||||||
const QList<Id> cmakeIds = autoDetectCMake();
|
const QList<Id> cmakeIds = autoDetectCMake();
|
||||||
const Id cmakeId = cmakeIds.empty() ? Id() : cmakeIds.first();
|
const Id cmakeId = cmakeIds.empty() ? Id() : cmakeIds.first();
|
||||||
autoDetectDebugger();
|
autoDetectDebugger();
|
||||||
|
autoDetectPython();
|
||||||
|
|
||||||
const auto initializeKit = [this, toolchains, qtVersions, cmakeId](Kit *k) {
|
const auto initializeKit = [this, toolchains, qtVersions, cmakeId](Kit *k) {
|
||||||
k->setAutoDetected(false);
|
k->setAutoDetected(false);
|
||||||
|
|||||||
@@ -209,13 +209,15 @@ public:
|
|||||||
|
|
||||||
inline bool operator==(const Interpreter &other) const
|
inline bool operator==(const Interpreter &other) const
|
||||||
{
|
{
|
||||||
return id == other.id && name == other.name && command == other.command;
|
return id == other.id && name == other.name && command == other.command
|
||||||
|
&& detectionSource == other.detectionSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString id;
|
QString id;
|
||||||
QString name;
|
QString name;
|
||||||
Utils::FilePath command;
|
Utils::FilePath command;
|
||||||
bool autoDetected = true;
|
bool autoDetected = true;
|
||||||
|
QString detectionSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT InterpreterAspect : public Utils::BaseAspect
|
class PROJECTEXPLORER_EXPORT InterpreterAspect : public Utils::BaseAspect
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace Python::Internal {
|
|||||||
|
|
||||||
static Interpreter createInterpreter(const FilePath &python,
|
static Interpreter createInterpreter(const FilePath &python,
|
||||||
const QString &defaultName,
|
const QString &defaultName,
|
||||||
bool windowedSuffix = false)
|
const QString &suffix = {})
|
||||||
{
|
{
|
||||||
Interpreter result;
|
Interpreter result;
|
||||||
result.id = QUuid::createUuid().toString();
|
result.id = QUuid::createUuid().toString();
|
||||||
@@ -67,11 +67,11 @@ static Interpreter createInterpreter(const FilePath &python,
|
|||||||
result.name = pythonProcess.cleanedStdOut().trimmed();
|
result.name = pythonProcess.cleanedStdOut().trimmed();
|
||||||
if (result.name.isEmpty())
|
if (result.name.isEmpty())
|
||||||
result.name = defaultName;
|
result.name = defaultName;
|
||||||
if (windowedSuffix)
|
|
||||||
result.name += " (Windowed)";
|
|
||||||
QDir pythonDir(python.parentDir().toString());
|
QDir pythonDir(python.parentDir().toString());
|
||||||
if (pythonDir.exists() && pythonDir.exists("activate") && pythonDir.cdUp())
|
if (pythonDir.exists() && pythonDir.exists("activate") && pythonDir.cdUp())
|
||||||
result.name += QString(" (%1 Virtual Environment)").arg(pythonDir.dirName());
|
result.name += QString(" (%1 Virtual Environment)").arg(pythonDir.dirName());
|
||||||
|
if (!suffix.isEmpty())
|
||||||
|
result.name += ' ' + suffix;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -125,6 +125,11 @@ public:
|
|||||||
|
|
||||||
void apply() override;
|
void apply() override;
|
||||||
|
|
||||||
|
void addInterpreter(const Interpreter &interpreter);
|
||||||
|
void removeInterpreterFrom(const QString &detectionSource);
|
||||||
|
QList<Interpreter> interpreters() const;
|
||||||
|
QList<Interpreter> interpreterFrom(const QString &detectionSource) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTreeView m_view;
|
QTreeView m_view;
|
||||||
ListModel<Interpreter> m_model;
|
ListModel<Interpreter> m_model;
|
||||||
@@ -218,11 +223,31 @@ InterpreterOptionsWidget::InterpreterOptionsWidget()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InterpreterOptionsWidget::apply()
|
void InterpreterOptionsWidget::apply()
|
||||||
|
{
|
||||||
|
PythonSettings::setInterpreter(interpreters(), m_defaultId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterOptionsWidget::addInterpreter(const Interpreter &interpreter)
|
||||||
|
{
|
||||||
|
m_model.appendItem(interpreter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterpreterOptionsWidget::removeInterpreterFrom(const QString &detectionSource)
|
||||||
|
{
|
||||||
|
m_model.destroyItems(Utils::equal(&Interpreter::detectionSource, detectionSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Interpreter> InterpreterOptionsWidget::interpreters() const
|
||||||
{
|
{
|
||||||
QList<Interpreter> interpreters;
|
QList<Interpreter> interpreters;
|
||||||
for (const TreeItem *treeItem : m_model)
|
for (const TreeItem *treeItem : m_model)
|
||||||
interpreters << static_cast<const ListItem<Interpreter> *>(treeItem)->itemData;
|
interpreters << static_cast<const ListItem<Interpreter> *>(treeItem)->itemData;
|
||||||
PythonSettings::setInterpreter(interpreters, m_defaultId);
|
return interpreters;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Interpreter> InterpreterOptionsWidget::interpreterFrom(const QString &detectionSource) const
|
||||||
|
{
|
||||||
|
return m_model.allData(Utils::equal(&Interpreter::detectionSource, detectionSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterpreterOptionsWidget::currentChanged(const QModelIndex &index, const QModelIndex &previous)
|
void InterpreterOptionsWidget::currentChanged(const QModelIndex &index, const QModelIndex &previous)
|
||||||
@@ -287,6 +312,32 @@ public:
|
|||||||
setCategoryIconPath(":/python/images/settingscategory_python.png");
|
setCategoryIconPath(":/python/images/settingscategory_python.png");
|
||||||
setWidgetCreator([]() { return new InterpreterOptionsWidget(); });
|
setWidgetCreator([]() { return new InterpreterOptionsWidget(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Interpreter> interpreters()
|
||||||
|
{
|
||||||
|
if (auto w = static_cast<InterpreterOptionsWidget *>(widget()))
|
||||||
|
return w->interpreters();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void addInterpreter(const Interpreter &interpreter)
|
||||||
|
{
|
||||||
|
if (auto w = static_cast<InterpreterOptionsWidget *>(widget()))
|
||||||
|
w->addInterpreter(interpreter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeInterpreterFrom(const QString &detectionSource)
|
||||||
|
{
|
||||||
|
if (auto w = static_cast<InterpreterOptionsWidget *>(widget()))
|
||||||
|
w->removeInterpreterFrom(detectionSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Interpreter> interpreterFrom(const QString &detectionSource)
|
||||||
|
{
|
||||||
|
if (auto w = static_cast<InterpreterOptionsWidget *>(widget()))
|
||||||
|
return w->interpreterFrom(detectionSource);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool alreadyRegistered(const QList<Interpreter> &pythons, const FilePath &pythonExecutable)
|
static bool alreadyRegistered(const QList<Interpreter> &pythons, const FilePath &pythonExecutable)
|
||||||
@@ -582,7 +633,7 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
|
|||||||
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() && !alreadyRegistered(pythons, pythonw))
|
||||||
pythons << createInterpreter(pythonw, "Python " + versionGroup, true);
|
pythons << createInterpreter(pythonw, "Python " + versionGroup, "(Windowed)");
|
||||||
}
|
}
|
||||||
pythonRegistry.endGroup();
|
pythonRegistry.endGroup();
|
||||||
}
|
}
|
||||||
@@ -602,7 +653,7 @@ static void addPythonsFromPath(QList<Interpreter> &pythons)
|
|||||||
}
|
}
|
||||||
for (const FilePath &executable : env.findAllInPath("pythonw")) {
|
for (const FilePath &executable : env.findAllInPath("pythonw")) {
|
||||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
||||||
pythons << createInterpreter(executable, "Python from Path", true);
|
pythons << createInterpreter(executable, "Python from Path", "(Windowed)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const QStringList filters = {"python",
|
const QStringList filters = {"python",
|
||||||
@@ -639,6 +690,9 @@ static PythonSettings *settingsInstance = nullptr;
|
|||||||
PythonSettings::PythonSettings()
|
PythonSettings::PythonSettings()
|
||||||
: QObject(PythonPlugin::instance())
|
: QObject(PythonPlugin::instance())
|
||||||
{
|
{
|
||||||
|
setObjectName("PythonSettings");
|
||||||
|
ExtensionSystem::PluginManager::addObject(this);
|
||||||
|
|
||||||
initFromSettings(Core::ICore::settings());
|
initFromSettings(Core::ICore::settings());
|
||||||
|
|
||||||
if (HostOsInfo::isWindowsHost())
|
if (HostOsInfo::isWindowsHost())
|
||||||
@@ -813,6 +867,45 @@ void PythonSettings::writeToSettings(QSettings *settings)
|
|||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PythonSettings::detectPythonOnDevice(const Utils::FilePaths &searchPaths,
|
||||||
|
const QString &deviceName,
|
||||||
|
const QString &detectionSource,
|
||||||
|
QString *logMessage)
|
||||||
|
{
|
||||||
|
QStringList messages{tr("Searching Python binaries...")};
|
||||||
|
auto alreadyConfigured = interpreterOptionsPage().interpreters();
|
||||||
|
for (const FilePath &path : searchPaths) {
|
||||||
|
const FilePath python = path.pathAppended("python3").withExecutableSuffix();
|
||||||
|
if (!python.isExecutableFile())
|
||||||
|
continue;
|
||||||
|
if (Utils::contains(alreadyConfigured, Utils::equal(&Interpreter::command, python)))
|
||||||
|
continue;
|
||||||
|
auto interpreter = createInterpreter(python, "Python on", "on " + deviceName);
|
||||||
|
interpreter.detectionSource = detectionSource;
|
||||||
|
interpreterOptionsPage().addInterpreter(interpreter);
|
||||||
|
messages.append(tr("Found \"%1\" (%2)").arg(interpreter.name, python.toUserOutput()));
|
||||||
|
}
|
||||||
|
if (logMessage)
|
||||||
|
*logMessage = messages.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void PythonSettings::removeDetectedPython(const QString &detectionSource, QString *logMessage)
|
||||||
|
{
|
||||||
|
if (logMessage)
|
||||||
|
logMessage->append(Tr::tr("Removing Python") + '\n');
|
||||||
|
|
||||||
|
interpreterOptionsPage().removeInterpreterFrom(detectionSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PythonSettings::listDetectedPython(const QString &detectionSource, QString *logMessage)
|
||||||
|
{
|
||||||
|
if (!logMessage)
|
||||||
|
return;
|
||||||
|
logMessage->append(Tr::tr("Python:") + '\n');
|
||||||
|
for (Interpreter &interpreter: interpreterOptionsPage().interpreterFrom(detectionSource))
|
||||||
|
logMessage->append(interpreter.name + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
void PythonSettings::saveSettings()
|
void PythonSettings::saveSettings()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(settingsInstance, return);
|
QTC_ASSERT(settingsInstance, return);
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ signals:
|
|||||||
void pylsConfigurationChanged(const QString &configuration);
|
void pylsConfigurationChanged(const QString &configuration);
|
||||||
void pylsEnabledChanged(const bool enabled);
|
void pylsEnabledChanged(const bool enabled);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void detectPythonOnDevice(const Utils::FilePaths &searchPaths,
|
||||||
|
const QString &deviceName,
|
||||||
|
const QString &detectionSource,
|
||||||
|
QString *logMessage);
|
||||||
|
void removeDetectedPython(const QString &detectionSource, QString *logMessage);
|
||||||
|
void listDetectedPython(const QString &detectionSource, QString *logMessage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PythonSettings();
|
PythonSettings();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user