Docker: Provide a means to select search paths for auto-detection

A combobox in the device dialog to select between the (docker image's)
system path and a semicolon-separated set of user defined paths.

Use it for cmake and gdb detection; qmake and toolchains currently missing.

Change-Id: I3c478ca914a1bf02dcb69ebcb9ea6e358d24aaf9
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
hjk
2021-12-03 10:21:57 +01:00
parent 2000491108
commit 16c25d99c8
8 changed files with 83 additions and 35 deletions

View File

@@ -180,15 +180,14 @@ void CMakeToolManager::updateDocumentation()
Core::HelpManager::registerDocumentation(docs); Core::HelpManager::registerDocumentation(docs);
} }
void CMakeToolManager::autoDetectCMakeForDevice(const FilePath &deviceRoot, void CMakeToolManager::autoDetectCMakeForDevice(const FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage) QString *logMessage)
{ {
QStringList messages{tr("Searching CMake binaries...")}; QStringList messages{tr("Searching CMake binaries...")};
const FilePaths candidates = {deviceRoot.withNewPath("cmake")}; for (const FilePath &path : searchPaths) {
for (const FilePath &candidate : candidates) { const FilePath cmake = path.pathAppended("cmake").withExecutableSuffix();
const FilePath cmake = candidate.searchInPath(); if (cmake.isExecutableFile()) {
if (!cmake.isEmpty()) {
registerCMakeByPath(cmake, detectionSource); registerCMakeByPath(cmake, detectionSource);
messages.append(tr("Found \"%1\"").arg(cmake.toUserOutput())); messages.append(tr("Found \"%1\"").arg(cmake.toUserOutput()));
} }

View File

@@ -63,7 +63,7 @@ public:
static void updateDocumentation(); static void updateDocumentation();
public slots: public slots:
void autoDetectCMakeForDevice(const Utils::FilePath &deviceRoot, void autoDetectCMakeForDevice(const Utils::FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage); QString *logMessage);
void registerCMakeByPath(const Utils::FilePath &cmakePath, void registerCMakeByPath(const Utils::FilePath &cmakePath,

View File

@@ -92,7 +92,7 @@ public:
QVariant registerDebugger(const DebuggerItem &item); QVariant registerDebugger(const DebuggerItem &item);
void readDebuggers(const FilePath &fileName, bool isSystem); void readDebuggers(const FilePath &fileName, bool isSystem);
void autoDetectCdbDebuggers(); void autoDetectCdbDebuggers();
void autoDetectGdbOrLldbDebuggers(const FilePath &deviceRoot, void autoDetectGdbOrLldbDebuggers(const FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage = nullptr); QString *logMessage = nullptr);
void autoDetectUvscDebuggers(); void autoDetectUvscDebuggers();
@@ -724,7 +724,7 @@ static Utils::FilePaths searchGdbPathsFromRegistry()
return searchPaths; return searchPaths;
} }
void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePath &deviceRoot, void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage) QString *logMessage)
{ {
@@ -752,7 +752,10 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePath &de
} }
*/ */
IDevice::ConstPtr device = DeviceManager::deviceForPath(deviceRoot); if (searchPaths.isEmpty())
return;
IDevice::ConstPtr device = DeviceManager::deviceForPath(searchPaths.front());
QTC_ASSERT(device, return); QTC_ASSERT(device, return);
FilePaths suspects; FilePaths suspects;
@@ -773,15 +776,14 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePath &de
} }
} }
FilePaths paths = device->systemEnvironment().path(); FilePaths paths = searchPaths;
if (!deviceRoot.needsDevice()) if (!searchPaths.front().needsDevice())
paths.append(searchGdbPathsFromRegistry()); paths.append(searchGdbPathsFromRegistry());
paths = Utils::filteredUnique(paths); paths = Utils::filteredUnique(paths);
for (const FilePath &path : paths) { for (const FilePath &path : paths) {
const FilePath globalPath = path.onDevice(deviceRoot); suspects.append(device->directoryEntries(path, filters, QDir::Files | QDir::Executable));
suspects.append(device->directoryEntries(globalPath, filters, QDir::Files | QDir::Executable));
} }
QStringList logMessages{tr("Searching debuggers...")}; QStringList logMessages{tr("Searching debuggers...")};
@@ -1044,11 +1046,11 @@ void DebuggerItemManager::deregisterDebugger(const QVariant &id)
}); });
} }
void DebuggerItemManager::autoDetectDebuggersForDevice(const FilePath &deviceRoot, void DebuggerItemManager::autoDetectDebuggersForDevice(const FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage) QString *logMessage)
{ {
d->autoDetectGdbOrLldbDebuggers(deviceRoot, detectionSource, logMessage); d->autoDetectGdbOrLldbDebuggers(searchPaths, detectionSource, logMessage);
} }
void DebuggerItemManager::removeDetectedDebuggers(const QString &detectionSource, void DebuggerItemManager::removeDetectedDebuggers(const QString &detectionSource,

View File

@@ -28,13 +28,13 @@
#include "debugger_global.h" #include "debugger_global.h"
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include <utils/filepath.h>
#include <QList> #include <QList>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QCoreApplication> #include <QCoreApplication>
namespace Utils { class FilePath; }
namespace Debugger { namespace Debugger {
class DebuggerItem; class DebuggerItem;
@@ -52,7 +52,7 @@ public:
static QVariant registerDebugger(const DebuggerItem &item); static QVariant registerDebugger(const DebuggerItem &item);
static void deregisterDebugger(const QVariant &id); static void deregisterDebugger(const QVariant &id);
static void autoDetectDebuggersForDevice(const Utils::FilePath &deviceRoot, static void autoDetectDebuggersForDevice(const Utils::FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage); QString *logMessage);
static void removeDetectedDebuggers(const QString &detectionSource, QString *logMessage); static void removeDetectedDebuggers(const QString &detectionSource, QString *logMessage);

View File

@@ -1748,11 +1748,11 @@ void DebuggerPlugin::getEnginesState(QByteArray *json) const
*json = QJsonDocument(QJsonObject::fromVariantMap(result)).toJson(); *json = QJsonDocument(QJsonObject::fromVariantMap(result)).toJson();
} }
void DebuggerPlugin::autoDetectDebuggersForDevice(const FilePath &deviceRoot, void DebuggerPlugin::autoDetectDebuggersForDevice(const FilePaths &searchPaths,
const QString &detectionSource, const QString &detectionSource,
QString *logMessage) QString *logMessage)
{ {
dd->m_debuggerItemManager.autoDetectDebuggersForDevice(deviceRoot, detectionSource, logMessage); dd->m_debuggerItemManager.autoDetectDebuggersForDevice(searchPaths, detectionSource, logMessage);
} }
void DebuggerPlugin::removeDetectedDebuggers(const QString &detectionSource, QString *logMessage) void DebuggerPlugin::removeDetectedDebuggers(const QString &detectionSource, QString *logMessage)

View File

@@ -26,10 +26,11 @@
#pragma once #pragma once
#include "debugger_global.h" #include "debugger_global.h"
#include <extensionsystem/iplugin.h> #include <extensionsystem/iplugin.h>
#include <utils/filepath.h>
namespace ProjectExplorer { class RunControl; } namespace ProjectExplorer { class RunControl; }
namespace Utils { class FilePath; }
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -59,7 +60,7 @@ private:
Q_SLOT void getEnginesState(QByteArray *json) const; Q_SLOT void getEnginesState(QByteArray *json) const;
// Called from DockerDevice // Called from DockerDevice
Q_SLOT void autoDetectDebuggersForDevice(const Utils::FilePath &deviceRoot, Q_SLOT void autoDetectDebuggersForDevice(const Utils::FilePaths &searchPaths,
const QString &detectionId, const QString &detectionId,
QString *logMessage); QString *logMessage);
Q_SLOT void removeDetectedDebuggers(const QString &detectionId, QString *logMessage); Q_SLOT void removeDetectedDebuggers(const QString &detectionId, QString *logMessage);

View File

@@ -64,6 +64,7 @@
#include <QApplication> #include <QApplication>
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox>
#include <QDateTime> #include <QDateTime>
#include <QDialog> #include <QDialog>
#include <QDialogButtonBox> #include <QDialogButtonBox>
@@ -262,6 +263,10 @@ public:
void undoAutoDetect() const; void undoAutoDetect() const;
void listAutoDetected() const; void listAutoDetected() const;
void setSharedId(const QString &sharedId) { m_sharedId = sharedId; }
void setSearchPaths(const FilePaths &searchPaths) { m_searchPaths = searchPaths; }
private:
QList<BaseQtVersion *> autoDetectQtVersions() const; QList<BaseQtVersion *> autoDetectQtVersions() const;
QList<ToolChain *> autoDetectToolChains(); QList<ToolChain *> autoDetectToolChains();
void autoDetectCMake(); void autoDetectCMake();
@@ -270,6 +275,7 @@ public:
KitDetector *q; KitDetector *q;
IDevice::ConstPtr m_device; IDevice::ConstPtr m_device;
QString m_sharedId; QString m_sharedId;
FilePaths m_searchPaths;
}; };
KitDetector::KitDetector(const IDevice::ConstPtr &device) KitDetector::KitDetector(const IDevice::ConstPtr &device)
@@ -281,21 +287,22 @@ KitDetector::~KitDetector()
delete d; delete d;
} }
void KitDetector::autoDetect(const QString &sharedId) const void KitDetector::autoDetect(const QString &sharedId, const FilePaths &searchPaths) const
{ {
d->m_sharedId = sharedId; d->setSharedId(sharedId);
d->setSearchPaths(searchPaths);
d->autoDetect(); d->autoDetect();
} }
void KitDetector::undoAutoDetect(const QString &sharedId) const void KitDetector::undoAutoDetect(const QString &sharedId) const
{ {
d->m_sharedId = sharedId; d->setSharedId(sharedId);
d->undoAutoDetect(); d->undoAutoDetect();
} }
void KitDetector::listAutoDetected(const QString &sharedId) const void KitDetector::listAutoDetected(const QString &sharedId) const
{ {
d->m_sharedId = sharedId; d->setSharedId(sharedId);
d->listAutoDetected(); d->listAutoDetected();
} }
@@ -415,10 +422,35 @@ public:
auto undoAutoDetectButton = new QPushButton(tr("Remove Auto-Detected Kit Items")); auto undoAutoDetectButton = new QPushButton(tr("Remove Auto-Detected Kit Items"));
auto listAutoDetectedButton = new QPushButton(tr("List Auto-Detected Kit Items")); auto listAutoDetectedButton = new QPushButton(tr("List Auto-Detected Kit Items"));
connect(autoDetectButton, &QPushButton::clicked, this, [this, logView, id = data.id(), dockerDevice] { auto searchDirsComboBox = new QComboBox;
searchDirsComboBox->addItem(tr("Search in PATH"));
searchDirsComboBox->addItem(tr("Search in selected directories"));
auto searchDirsLineEdit = new QLineEdit;
searchDirsLineEdit->setText("/usr/bin;/opt");
searchDirsLineEdit->setToolTip(
tr("Select the paths in the Docker image that should be scanned for Kit entries"));
auto searchPaths = [this, searchDirsComboBox, searchDirsLineEdit, dockerDevice] {
FilePaths paths;
if (searchDirsComboBox->currentIndex() == 0) {
paths = dockerDevice->systemEnvironment().path();
} else {
for (const QString &path : searchDirsLineEdit->text().split(';'))
paths.append(FilePath::fromString(path.trimmed()));
}
paths = Utils::transform(paths, [dockerDevice](const FilePath &path) {
return dockerDevice->mapToGlobalPath(path);
});
return paths;
};
connect(autoDetectButton, &QPushButton::clicked, this,
[this, logView, id = data.id(), dockerDevice, searchPaths] {
logView->clear(); logView->clear();
dockerDevice->tryCreateLocalFileAccess(); dockerDevice->tryCreateLocalFileAccess();
m_kitItemDetector.autoDetect(id);
m_kitItemDetector.autoDetect(id, searchPaths());
if (DockerPlugin::isDaemonRunning().value_or(false) == false) if (DockerPlugin::isDaemonRunning().value_or(false) == false)
logView->append(tr("Docker daemon appears to be not running.")); logView->append(tr("Docker daemon appears to be not running."));
@@ -451,11 +483,27 @@ public:
}, Break(), }, Break(),
Column { Column {
Space(20), Space(20),
Row { autoDetectButton, undoAutoDetectButton, listAutoDetectedButton, Stretch() }, Row {
searchDirsComboBox,
searchDirsLineEdit
},
Row {
autoDetectButton,
undoAutoDetectButton,
listAutoDetectedButton,
Stretch(),
},
new QLabel(tr("Detection log:")), new QLabel(tr("Detection log:")),
logView logView
} }
}.attachTo(this); }.attachTo(this);
searchDirsLineEdit->setVisible(false);
auto updateDirectoriesLineEdit = [this, searchDirsLineEdit](int index) {
searchDirsLineEdit->setVisible(index == 1);
};
QObject::connect(searchDirsComboBox, qOverload<int>(&QComboBox::activated),
this, updateDirectoriesLineEdit);
} }
void updateDeviceFromUi() final {} void updateDeviceFromUi() final {}
@@ -658,7 +706,7 @@ QList<BaseQtVersion *> KitDetectorPrivate::autoDetectQtVersions() const
emit q->logOutput('\n' + tr("Searching Qt installations...")); emit q->logOutput('\n' + tr("Searching Qt installations..."));
for (const QString &candidate : candidates) { for (const QString &candidate : candidates) {
emit q->logOutput(tr("Searching for %1 executable...").arg(candidate)); emit q->logOutput(tr("Searching for %1 executable...").arg(candidate));
const FilePath qmake = m_device->searchExecutableInPath(candidate); const FilePath qmake = m_device->searchExecutable(candidate, m_searchPaths);
if (qmake.isEmpty()) if (qmake.isEmpty())
continue; continue;
BaseQtVersion *qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, m_sharedId, &error); BaseQtVersion *qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, m_sharedId, &error);
@@ -703,11 +751,10 @@ void KitDetectorPrivate::autoDetectCMake()
if (!cmakeManager) if (!cmakeManager)
return; return;
const FilePath deviceRoot = m_device->mapToGlobalPath({});
QString logMessage; QString logMessage;
const bool res = QMetaObject::invokeMethod(cmakeManager, const bool res = QMetaObject::invokeMethod(cmakeManager,
"autoDetectCMakeForDevice", "autoDetectCMakeForDevice",
Q_ARG(Utils::FilePath, deviceRoot), Q_ARG(Utils::FilePaths, m_searchPaths),
Q_ARG(QString, m_sharedId), Q_ARG(QString, m_sharedId),
Q_ARG(QString *, &logMessage)); Q_ARG(QString *, &logMessage));
QTC_CHECK(res); QTC_CHECK(res);
@@ -720,11 +767,10 @@ void KitDetectorPrivate::autoDetectDebugger()
if (!debuggerPlugin) if (!debuggerPlugin)
return; return;
const FilePath deviceRoot = m_device->mapToGlobalPath({});
QString logMessage; QString logMessage;
const bool res = QMetaObject::invokeMethod(debuggerPlugin, const bool res = QMetaObject::invokeMethod(debuggerPlugin,
"autoDetectDebuggersForDevice", "autoDetectDebuggersForDevice",
Q_ARG(Utils::FilePath, deviceRoot), Q_ARG(Utils::FilePaths, m_searchPaths),
Q_ARG(QString, m_sharedId), Q_ARG(QString, m_sharedId),
Q_ARG(QString *, &logMessage)); Q_ARG(QString *, &logMessage));
QTC_CHECK(res); QTC_CHECK(res);

View File

@@ -144,7 +144,7 @@ public:
explicit KitDetector(const ProjectExplorer::IDevice::ConstPtr &device); explicit KitDetector(const ProjectExplorer::IDevice::ConstPtr &device);
~KitDetector() override; ~KitDetector() override;
void autoDetect(const QString &sharedId) const; void autoDetect(const QString &sharedId, const Utils::FilePaths &selectedPaths) const;
void undoAutoDetect(const QString &sharedId) const; void undoAutoDetect(const QString &sharedId) const;
void listAutoDetected(const QString &sharedId) const; void listAutoDetected(const QString &sharedId) const;