forked from qt-creator/qt-creator
docker-plugin: Split out dockerdevice utility classes
Moved DockerDeviceWidget and KitDetector into their own files Change-Id: I16d52a4f27f611b6278e2144c4718bd370f99b63 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -5,6 +5,8 @@ add_qtc_plugin(Docker
|
|||||||
dockerbuildstep.cpp dockerbuildstep.h
|
dockerbuildstep.cpp dockerbuildstep.h
|
||||||
dockerconstants.h
|
dockerconstants.h
|
||||||
dockerdevice.cpp dockerdevice.h
|
dockerdevice.cpp dockerdevice.h
|
||||||
|
dockerdevicewidget.cpp dockerdevicewidget.h
|
||||||
dockerplugin.cpp dockerplugin.h
|
dockerplugin.cpp dockerplugin.h
|
||||||
dockersettings.cpp dockersettings.h
|
dockersettings.cpp dockersettings.h
|
||||||
|
kitdetector.cpp kitdetector.h
|
||||||
)
|
)
|
||||||
|
@@ -12,15 +12,19 @@ QtcPlugin {
|
|||||||
|
|
||||||
files: [
|
files: [
|
||||||
"docker_global.h",
|
"docker_global.h",
|
||||||
"dockerbuildstep.h",
|
|
||||||
"dockerbuildstep.cpp",
|
"dockerbuildstep.cpp",
|
||||||
|
"dockerbuildstep.h",
|
||||||
"dockerconstants.h",
|
"dockerconstants.h",
|
||||||
"dockerdevice.h",
|
|
||||||
"dockerdevice.cpp",
|
"dockerdevice.cpp",
|
||||||
"dockerplugin.h",
|
"dockerdevice.h",
|
||||||
|
"dockerdevicewidget.cpp",
|
||||||
|
"dockerdevicewidget.h",
|
||||||
"dockerplugin.cpp",
|
"dockerplugin.cpp",
|
||||||
|
"dockerplugin.h",
|
||||||
|
"dockersettings.cpp",
|
||||||
"dockersettings.h",
|
"dockersettings.h",
|
||||||
"dockersettings.cpp"
|
"kitdetector.cpp",
|
||||||
|
"kitdetector.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "dockerconstants.h"
|
#include "dockerconstants.h"
|
||||||
#include "dockerplugin.h"
|
#include "dockerplugin.h"
|
||||||
|
#include "dockerdevicewidget.h"
|
||||||
|
#include "kitdetector.h"
|
||||||
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
@@ -185,61 +187,7 @@ class DockerPortsGatheringMethod : public PortsGatheringMethod
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class KitDetectorPrivate
|
|
||||||
{
|
|
||||||
Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::KitItemDetector)
|
|
||||||
|
|
||||||
public:
|
|
||||||
KitDetectorPrivate(KitDetector *parent, const IDevice::ConstPtr &device)
|
|
||||||
: q(parent), m_device(device)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void autoDetect();
|
|
||||||
void undoAutoDetect() const;
|
|
||||||
void listAutoDetected() const;
|
|
||||||
|
|
||||||
void setSharedId(const QString &sharedId) { m_sharedId = sharedId; }
|
|
||||||
void setSearchPaths(const FilePaths &searchPaths) { m_searchPaths = searchPaths; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
QtVersions autoDetectQtVersions() const;
|
|
||||||
QList<ToolChain *> autoDetectToolChains();
|
|
||||||
void autoDetectCMake();
|
|
||||||
void autoDetectDebugger();
|
|
||||||
|
|
||||||
KitDetector *q;
|
|
||||||
IDevice::ConstPtr m_device;
|
|
||||||
QString m_sharedId;
|
|
||||||
FilePaths m_searchPaths;
|
|
||||||
};
|
|
||||||
|
|
||||||
KitDetector::KitDetector(const IDevice::ConstPtr &device)
|
|
||||||
: d(new KitDetectorPrivate(this, device))
|
|
||||||
{}
|
|
||||||
|
|
||||||
KitDetector::~KitDetector()
|
|
||||||
{
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetector::autoDetect(const QString &sharedId, const FilePaths &searchPaths) const
|
|
||||||
{
|
|
||||||
d->setSharedId(sharedId);
|
|
||||||
d->setSearchPaths(searchPaths);
|
|
||||||
d->autoDetect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetector::undoAutoDetect(const QString &sharedId) const
|
|
||||||
{
|
|
||||||
d->setSharedId(sharedId);
|
|
||||||
d->undoAutoDetect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetector::listAutoDetected(const QString &sharedId) const
|
|
||||||
{
|
|
||||||
d->setSharedId(sharedId);
|
|
||||||
d->listAutoDetected();
|
|
||||||
}
|
|
||||||
|
|
||||||
class DockerDevicePrivate : public QObject
|
class DockerDevicePrivate : public QObject
|
||||||
{
|
{
|
||||||
@@ -274,191 +222,6 @@ public:
|
|||||||
bool m_useFind = true; // prefer find over ls and hacks, but be able to use ls as fallback
|
bool m_useFind = true; // prefer find over ls and hacks, but be able to use ls as fallback
|
||||||
};
|
};
|
||||||
|
|
||||||
class DockerDeviceWidget final : public IDeviceWidget
|
|
||||||
{
|
|
||||||
Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerDevice)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit DockerDeviceWidget(const IDevice::Ptr &device)
|
|
||||||
: IDeviceWidget(device), m_kitItemDetector(device)
|
|
||||||
{
|
|
||||||
auto dockerDevice = device.dynamicCast<DockerDevice>();
|
|
||||||
QTC_ASSERT(dockerDevice, return);
|
|
||||||
|
|
||||||
DockerDeviceData &data = dockerDevice->data();
|
|
||||||
|
|
||||||
auto repoLabel = new QLabel(tr("Repository:"));
|
|
||||||
m_repoLineEdit = new QLineEdit;
|
|
||||||
m_repoLineEdit->setText(data.repo);
|
|
||||||
m_repoLineEdit->setEnabled(false);
|
|
||||||
|
|
||||||
auto tagLabel = new QLabel(tr("Tag:"));
|
|
||||||
m_tagLineEdit = new QLineEdit;
|
|
||||||
m_tagLineEdit->setText(data.tag);
|
|
||||||
m_tagLineEdit->setEnabled(false);
|
|
||||||
|
|
||||||
auto idLabel = new QLabel(tr("Image ID:"));
|
|
||||||
m_idLineEdit = new QLineEdit;
|
|
||||||
m_idLineEdit->setText(data.imageId);
|
|
||||||
m_idLineEdit->setEnabled(false);
|
|
||||||
|
|
||||||
auto daemonStateLabel = new QLabel(tr("Daemon state:"));
|
|
||||||
m_daemonReset = new QToolButton;
|
|
||||||
m_daemonReset->setToolTip(tr("Clears detected daemon state. "
|
|
||||||
"It will be automatically re-evaluated next time access is needed."));
|
|
||||||
|
|
||||||
m_daemonState = new QLabel;
|
|
||||||
updateDaemonStateTexts();
|
|
||||||
|
|
||||||
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
|
|
||||||
DockerPlugin::setGlobalDaemonState(Utils::nullopt);
|
|
||||||
updateDaemonStateTexts();
|
|
||||||
});
|
|
||||||
|
|
||||||
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
|
|
||||||
m_runAsOutsideUser->setToolTip(tr("Uses user ID and group ID of the user running Qt Creator "
|
|
||||||
"in the docker container."));
|
|
||||||
m_runAsOutsideUser->setChecked(data.useLocalUidGid);
|
|
||||||
m_runAsOutsideUser->setEnabled(HostOsInfo::isLinuxHost());
|
|
||||||
|
|
||||||
connect(m_runAsOutsideUser, &QCheckBox::toggled, this, [&data](bool on) {
|
|
||||||
data.useLocalUidGid = on;
|
|
||||||
});
|
|
||||||
|
|
||||||
m_pathsListLabel = new InfoLabel(tr("Paths to mount:"));
|
|
||||||
// FIXME: 8.0: use
|
|
||||||
//m_pathsListLabel->setToolTip(tr("Source directory list should not be empty"));
|
|
||||||
|
|
||||||
m_pathsListEdit = new PathListEditor;
|
|
||||||
// FIXME: 8.0: use
|
|
||||||
//m_pathsListEdit->setPlaceholderText(tr("Host directories to mount into the container"));
|
|
||||||
m_pathsListEdit->setToolTip(tr("Maps paths in this list one-to-one to the "
|
|
||||||
"docker container."));
|
|
||||||
m_pathsListEdit->setPathList(data.mounts);
|
|
||||||
|
|
||||||
auto markupMounts = [this] {
|
|
||||||
const bool isEmpty = m_pathsListEdit->pathList().isEmpty();
|
|
||||||
m_pathsListLabel->setType(isEmpty ? InfoLabel::Warning : InfoLabel::None);
|
|
||||||
};
|
|
||||||
markupMounts();
|
|
||||||
|
|
||||||
connect(m_pathsListEdit, &PathListEditor::changed, this, [dockerDevice, markupMounts, this] {
|
|
||||||
dockerDevice->setMounts(m_pathsListEdit->pathList());
|
|
||||||
markupMounts();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto logView = new QTextBrowser;
|
|
||||||
connect(&m_kitItemDetector, &KitDetector::logOutput,
|
|
||||||
logView, &QTextBrowser::append);
|
|
||||||
|
|
||||||
auto autoDetectButton = new QPushButton(tr("Auto-detect Kit Items"));
|
|
||||||
auto undoAutoDetectButton = new QPushButton(tr("Remove Auto-Detected Kit Items"));
|
|
||||||
auto listAutoDetectedButton = new QPushButton(tr("List Auto-Detected Kit Items"));
|
|
||||||
|
|
||||||
auto searchDirsComboBox = new QComboBox;
|
|
||||||
searchDirsComboBox->addItem(tr("Search in PATH"));
|
|
||||||
searchDirsComboBox->addItem(tr("Search in Selected Directories"));
|
|
||||||
|
|
||||||
auto searchDirsLineEdit = new FancyLineEdit;
|
|
||||||
// FIXME: 8.0: use
|
|
||||||
//searchDirsLineEdit->setPlaceholderText(tr("Semicolon-separated list of directories"));
|
|
||||||
searchDirsLineEdit->setToolTip(
|
|
||||||
tr("Select the paths in the docker image that should be scanned for kit entries."));
|
|
||||||
searchDirsLineEdit->setHistoryCompleter("DockerMounts", true);
|
|
||||||
|
|
||||||
auto searchPaths = [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, dockerDevice, searchPaths] {
|
|
||||||
logView->clear();
|
|
||||||
dockerDevice->updateContainerAccess();
|
|
||||||
|
|
||||||
m_kitItemDetector.autoDetect(dockerDevice->id().toString(), searchPaths());
|
|
||||||
|
|
||||||
if (DockerPlugin::isDaemonRunning().value_or(false) == false)
|
|
||||||
logView->append(tr("Docker daemon appears to be not running."));
|
|
||||||
else
|
|
||||||
logView->append(tr("Docker daemon appears to be running."));
|
|
||||||
updateDaemonStateTexts();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, device] {
|
|
||||||
logView->clear();
|
|
||||||
m_kitItemDetector.undoAutoDetect(device->id().toString());
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, device] {
|
|
||||||
logView->clear();
|
|
||||||
m_kitItemDetector.listAutoDetected(device->id().toString());
|
|
||||||
});
|
|
||||||
|
|
||||||
using namespace Layouting;
|
|
||||||
|
|
||||||
Form {
|
|
||||||
repoLabel, m_repoLineEdit, Break(),
|
|
||||||
tagLabel, m_tagLineEdit, Break(),
|
|
||||||
idLabel, m_idLineEdit, Break(),
|
|
||||||
daemonStateLabel, m_daemonReset, m_daemonState, Break(),
|
|
||||||
m_runAsOutsideUser, Break(),
|
|
||||||
Column {
|
|
||||||
m_pathsListLabel,
|
|
||||||
m_pathsListEdit,
|
|
||||||
}, Break(),
|
|
||||||
Column {
|
|
||||||
Space(20),
|
|
||||||
Row {
|
|
||||||
searchDirsComboBox,
|
|
||||||
searchDirsLineEdit
|
|
||||||
},
|
|
||||||
Row {
|
|
||||||
autoDetectButton,
|
|
||||||
undoAutoDetectButton,
|
|
||||||
listAutoDetectedButton,
|
|
||||||
Stretch(),
|
|
||||||
},
|
|
||||||
new QLabel(tr("Detection log:")),
|
|
||||||
logView
|
|
||||||
}
|
|
||||||
}.attachTo(this);
|
|
||||||
|
|
||||||
searchDirsLineEdit->setVisible(false);
|
|
||||||
auto updateDirectoriesLineEdit = [searchDirsLineEdit](int index) {
|
|
||||||
searchDirsLineEdit->setVisible(index == 1);
|
|
||||||
if (index == 1)
|
|
||||||
searchDirsLineEdit->setFocus();
|
|
||||||
};
|
|
||||||
QObject::connect(searchDirsComboBox, qOverload<int>(&QComboBox::activated),
|
|
||||||
this, updateDirectoriesLineEdit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateDeviceFromUi() final {}
|
|
||||||
void updateDaemonStateTexts();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QLineEdit *m_repoLineEdit;
|
|
||||||
QLineEdit *m_tagLineEdit;
|
|
||||||
QLineEdit *m_idLineEdit;
|
|
||||||
QToolButton *m_daemonReset;
|
|
||||||
QLabel *m_daemonState;
|
|
||||||
QCheckBox *m_runAsOutsideUser;
|
|
||||||
InfoLabel *m_pathsListLabel;
|
|
||||||
PathListEditor *m_pathsListEdit;
|
|
||||||
|
|
||||||
KitDetector m_kitItemDetector;
|
|
||||||
};
|
|
||||||
|
|
||||||
IDeviceWidget *DockerDevice::createWidget()
|
IDeviceWidget *DockerDevice::createWidget()
|
||||||
{
|
{
|
||||||
return new DockerDeviceWidget(sharedFromThis());
|
return new DockerDeviceWidget(sharedFromThis());
|
||||||
@@ -476,7 +239,6 @@ Tasks DockerDevice::validate() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DockerDeviceData
|
// DockerDeviceData
|
||||||
|
|
||||||
QString DockerDeviceData::repoAndTag() const
|
QString DockerDeviceData::repoAndTag() const
|
||||||
@@ -547,236 +309,7 @@ DockerDeviceData &DockerDevice::data()
|
|||||||
return d->m_data;
|
return d->m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KitDetectorPrivate::undoAutoDetect() const
|
|
||||||
{
|
|
||||||
emit q->logOutput(tr("Start removing auto-detected items associated with this docker image."));
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Removing kits..."));
|
|
||||||
for (Kit *kit : KitManager::kits()) {
|
|
||||||
if (kit->autoDetectionSource() == m_sharedId) {
|
|
||||||
emit q->logOutput(tr("Removed \"%1\"").arg(kit->displayName()));
|
|
||||||
KitManager::deregisterKit(kit);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Removing Qt version entries..."));
|
|
||||||
for (QtVersion *qtVersion : QtVersionManager::versions()) {
|
|
||||||
if (qtVersion->detectionSource() == m_sharedId) {
|
|
||||||
emit q->logOutput(tr("Removed \"%1\"").arg(qtVersion->displayName()));
|
|
||||||
QtVersionManager::removeVersion(qtVersion);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Removing toolchain entries..."));
|
|
||||||
const Toolchains toolchains = ToolChainManager::toolchains();
|
|
||||||
for (ToolChain *toolChain : toolchains) {
|
|
||||||
if (toolChain && toolChain->detectionSource() == m_sharedId) {
|
|
||||||
emit q->logOutput(tr("Removed \"%1\"").arg(toolChain->displayName()));
|
|
||||||
ToolChainManager::deregisterToolChain(toolChain);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager")) {
|
|
||||||
QString logMessage;
|
|
||||||
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
|
||||||
"removeDetectedCMake",
|
|
||||||
Q_ARG(QString, m_sharedId),
|
|
||||||
Q_ARG(QString *, &logMessage));
|
|
||||||
QTC_CHECK(res);
|
|
||||||
emit q->logOutput('\n' + logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QObject *debuggerPlugin = ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin")) {
|
|
||||||
QString logMessage;
|
|
||||||
const bool res = QMetaObject::invokeMethod(debuggerPlugin,
|
|
||||||
"removeDetectedDebuggers",
|
|
||||||
Q_ARG(QString, m_sharedId),
|
|
||||||
Q_ARG(QString *, &logMessage));
|
|
||||||
QTC_CHECK(res);
|
|
||||||
emit q->logOutput('\n' + logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Removal of previously auto-detected kit items finished.") + "\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetectorPrivate::listAutoDetected() const
|
|
||||||
{
|
|
||||||
emit q->logOutput(tr("Start listing auto-detected items associated with this docker image."));
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Kits:"));
|
|
||||||
for (Kit *kit : KitManager::kits()) {
|
|
||||||
if (kit->autoDetectionSource() == m_sharedId)
|
|
||||||
emit q->logOutput(kit->displayName());
|
|
||||||
};
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Qt versions:"));
|
|
||||||
for (QtVersion *qtVersion : QtVersionManager::versions()) {
|
|
||||||
if (qtVersion->detectionSource() == m_sharedId)
|
|
||||||
emit q->logOutput(qtVersion->displayName());
|
|
||||||
};
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Toolchains:"));
|
|
||||||
for (ToolChain *toolChain : ToolChainManager::toolchains()) {
|
|
||||||
if (toolChain->detectionSource() == m_sharedId)
|
|
||||||
emit q->logOutput(toolChain->displayName());
|
|
||||||
};
|
|
||||||
|
|
||||||
if (QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager")) {
|
|
||||||
QString logMessage;
|
|
||||||
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
|
||||||
"listDetectedCMake",
|
|
||||||
Q_ARG(QString, m_sharedId),
|
|
||||||
Q_ARG(QString *, &logMessage));
|
|
||||||
QTC_CHECK(res);
|
|
||||||
emit q->logOutput('\n' + logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QObject *debuggerPlugin = ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin")) {
|
|
||||||
QString logMessage;
|
|
||||||
const bool res = QMetaObject::invokeMethod(debuggerPlugin,
|
|
||||||
"listDetectedDebuggers",
|
|
||||||
Q_ARG(QString, m_sharedId),
|
|
||||||
Q_ARG(QString *, &logMessage));
|
|
||||||
QTC_CHECK(res);
|
|
||||||
emit q->logOutput('\n' + logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit q->logOutput('\n' + tr("Listing of previously auto-detected kit items finished.") + "\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
QtVersions KitDetectorPrivate::autoDetectQtVersions() const
|
|
||||||
{
|
|
||||||
QtVersions qtVersions;
|
|
||||||
|
|
||||||
QString error;
|
|
||||||
|
|
||||||
const auto handleQmake = [this, &qtVersions, &error](const FilePath &qmake) {
|
|
||||||
if (QtVersion *qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, m_sharedId, &error)) {
|
|
||||||
qtVersions.append(qtVersion);
|
|
||||||
QtVersionManager::addVersion(qtVersion);
|
|
||||||
emit q->logOutput(tr("Found \"%1\"").arg(qtVersion->qmakeFilePath().toUserOutput()));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
emit q->logOutput(tr("Searching for qmake executables..."));
|
|
||||||
|
|
||||||
const QStringList candidates = {"qmake-qt6", "qmake-qt5", "qmake"};
|
|
||||||
for (const FilePath &searchPath : m_searchPaths) {
|
|
||||||
searchPath.iterateDirectory(handleQmake, {candidates, QDir::Files | QDir::Executable,
|
|
||||||
QDirIterator::Subdirectories});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error.isEmpty())
|
|
||||||
emit q->logOutput(tr("Error: %1.").arg(error));
|
|
||||||
if (qtVersions.isEmpty())
|
|
||||||
emit q->logOutput(tr("No Qt installation found."));
|
|
||||||
return qtVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toolchains KitDetectorPrivate::autoDetectToolChains()
|
|
||||||
{
|
|
||||||
const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories();
|
|
||||||
|
|
||||||
Toolchains alreadyKnown = ToolChainManager::toolchains();
|
|
||||||
Toolchains allNewToolChains;
|
|
||||||
QApplication::processEvents();
|
|
||||||
emit q->logOutput('\n' + tr("Searching toolchains..."));
|
|
||||||
for (ToolChainFactory *factory : factories) {
|
|
||||||
emit q->logOutput(tr("Searching toolchains of type %1").arg(factory->displayName()));
|
|
||||||
const ToolchainDetector detector(alreadyKnown, m_device, m_searchPaths);
|
|
||||||
const Toolchains newToolChains = factory->autoDetect(detector);
|
|
||||||
for (ToolChain *toolChain : newToolChains) {
|
|
||||||
emit q->logOutput(tr("Found \"%1\"").arg(toolChain->compilerCommand().toUserOutput()));
|
|
||||||
toolChain->setDetectionSource(m_sharedId);
|
|
||||||
ToolChainManager::registerToolChain(toolChain);
|
|
||||||
alreadyKnown.append(toolChain);
|
|
||||||
}
|
|
||||||
allNewToolChains.append(newToolChains);
|
|
||||||
}
|
|
||||||
emit q->logOutput(tr("%1 new toolchains found.").arg(allNewToolChains.size()));
|
|
||||||
|
|
||||||
return allNewToolChains;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetectorPrivate::autoDetectCMake()
|
|
||||||
{
|
|
||||||
QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager");
|
|
||||||
if (!cmakeManager)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString logMessage;
|
|
||||||
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
|
||||||
"autoDetectCMakeForDevice",
|
|
||||||
Q_ARG(Utils::FilePaths, m_searchPaths),
|
|
||||||
Q_ARG(QString, m_sharedId),
|
|
||||||
Q_ARG(QString *, &logMessage));
|
|
||||||
QTC_CHECK(res);
|
|
||||||
emit q->logOutput('\n' + logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetectorPrivate::autoDetectDebugger()
|
|
||||||
{
|
|
||||||
QObject *debuggerPlugin = ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin");
|
|
||||||
if (!debuggerPlugin)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString logMessage;
|
|
||||||
const bool res = QMetaObject::invokeMethod(debuggerPlugin,
|
|
||||||
"autoDetectDebuggersForDevice",
|
|
||||||
Q_ARG(Utils::FilePaths, m_searchPaths),
|
|
||||||
Q_ARG(QString, m_sharedId),
|
|
||||||
Q_ARG(QString *, &logMessage));
|
|
||||||
QTC_CHECK(res);
|
|
||||||
emit q->logOutput('\n' + logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KitDetectorPrivate::autoDetect()
|
|
||||||
{
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
||||||
|
|
||||||
undoAutoDetect();
|
|
||||||
|
|
||||||
emit q->logOutput(tr("Starting auto-detection. This will take a while..."));
|
|
||||||
|
|
||||||
const Toolchains toolchains = autoDetectToolChains();
|
|
||||||
const QtVersions qtVersions = autoDetectQtVersions();
|
|
||||||
|
|
||||||
autoDetectCMake();
|
|
||||||
autoDetectDebugger();
|
|
||||||
|
|
||||||
const auto initializeKit = [this, toolchains, qtVersions](Kit *k) {
|
|
||||||
k->setAutoDetected(false);
|
|
||||||
k->setAutoDetectionSource(m_sharedId);
|
|
||||||
k->setUnexpandedDisplayName("%{Device:Name}");
|
|
||||||
|
|
||||||
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DOCKER_DEVICE_TYPE);
|
|
||||||
DeviceKitAspect::setDevice(k, m_device);
|
|
||||||
|
|
||||||
QtVersion *qt = nullptr;
|
|
||||||
if (!qtVersions.isEmpty()) {
|
|
||||||
qt = qtVersions.at(0);
|
|
||||||
QtSupport::QtKitAspect::setQtVersion(k, qt);
|
|
||||||
}
|
|
||||||
Toolchains toolchainsToSet;
|
|
||||||
toolchainsToSet = ToolChainManager::toolchains([qt, this](const ToolChain *tc){
|
|
||||||
return tc->detectionSource() == m_sharedId
|
|
||||||
&& (!qt || qt->qtAbis().contains(tc->targetAbi()));
|
|
||||||
});
|
|
||||||
for (ToolChain *toolChain : toolchainsToSet)
|
|
||||||
ToolChainKitAspect::setToolChain(k, toolChain);
|
|
||||||
|
|
||||||
k->setSticky(ToolChainKitAspect::id(), true);
|
|
||||||
k->setSticky(QtSupport::QtKitAspect::id(), true);
|
|
||||||
k->setSticky(DeviceKitAspect::id(), true);
|
|
||||||
k->setSticky(DeviceTypeKitAspect::id(), true);
|
|
||||||
};
|
|
||||||
|
|
||||||
Kit *kit = KitManager::registerKit(initializeKit);
|
|
||||||
emit q->logOutput('\n' + tr("Registered kit %1").arg(kit->displayName()));
|
|
||||||
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DockerDevice::updateContainerAccess() const
|
void DockerDevice::updateContainerAccess() const
|
||||||
{
|
{
|
||||||
@@ -1662,21 +1195,6 @@ public:
|
|||||||
QString m_selectedId;
|
QString m_selectedId;
|
||||||
};
|
};
|
||||||
|
|
||||||
void DockerDeviceWidget::updateDaemonStateTexts()
|
|
||||||
{
|
|
||||||
Utils::optional<bool> daemonState = DockerPlugin::isDaemonRunning();
|
|
||||||
if (!daemonState.has_value()) {
|
|
||||||
m_daemonReset->setIcon(Icons::INFO.icon());
|
|
||||||
m_daemonState->setText(tr("Daemon state not evaluated."));
|
|
||||||
} else if (daemonState.value()) {
|
|
||||||
m_daemonReset->setIcon(Icons::OK.icon());
|
|
||||||
m_daemonState->setText(tr("Docker daemon running."));
|
|
||||||
} else {
|
|
||||||
m_daemonReset->setIcon(Icons::CRITICAL.icon());
|
|
||||||
m_daemonState->setText(tr("Docker daemon not running."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Factory
|
// Factory
|
||||||
|
|
||||||
DockerDeviceFactory::DockerDeviceFactory()
|
DockerDeviceFactory::DockerDeviceFactory()
|
||||||
|
@@ -129,25 +129,6 @@ private:
|
|||||||
friend class DockerDeviceWidget;
|
friend class DockerDeviceWidget;
|
||||||
};
|
};
|
||||||
|
|
||||||
class KitDetector : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit KitDetector(const ProjectExplorer::IDevice::ConstPtr &device);
|
|
||||||
~KitDetector() override;
|
|
||||||
|
|
||||||
void autoDetect(const QString &sharedId, const Utils::FilePaths &selectedPaths) const;
|
|
||||||
void undoAutoDetect(const QString &sharedId) const;
|
|
||||||
void listAutoDetected(const QString &sharedId) const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void logOutput(const QString &msg);
|
|
||||||
|
|
||||||
private:
|
|
||||||
class KitDetectorPrivate *d = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory
|
class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
225
src/plugins/docker/dockerdevicewidget.cpp
Normal file
225
src/plugins/docker/dockerdevicewidget.cpp
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "dockerdevicewidget.h"
|
||||||
|
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QTextBrowser>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace Docker {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
|
||||||
|
: IDeviceWidget(device), m_kitItemDetector(device)
|
||||||
|
{
|
||||||
|
auto dockerDevice = device.dynamicCast<DockerDevice>();
|
||||||
|
QTC_ASSERT(dockerDevice, return);
|
||||||
|
|
||||||
|
DockerDeviceData &data = dockerDevice->data();
|
||||||
|
|
||||||
|
auto repoLabel = new QLabel(tr("Repository:"));
|
||||||
|
m_repoLineEdit = new QLineEdit;
|
||||||
|
m_repoLineEdit->setText(data.repo);
|
||||||
|
m_repoLineEdit->setEnabled(false);
|
||||||
|
|
||||||
|
auto tagLabel = new QLabel(tr("Tag:"));
|
||||||
|
m_tagLineEdit = new QLineEdit;
|
||||||
|
m_tagLineEdit->setText(data.tag);
|
||||||
|
m_tagLineEdit->setEnabled(false);
|
||||||
|
|
||||||
|
auto idLabel = new QLabel(tr("Image ID:"));
|
||||||
|
m_idLineEdit = new QLineEdit;
|
||||||
|
m_idLineEdit->setText(data.imageId);
|
||||||
|
m_idLineEdit->setEnabled(false);
|
||||||
|
|
||||||
|
auto daemonStateLabel = new QLabel(tr("Daemon state:"));
|
||||||
|
m_daemonReset = new QToolButton;
|
||||||
|
m_daemonReset->setToolTip(tr("Clears detected daemon state. "
|
||||||
|
"It will be automatically re-evaluated next time access is needed."));
|
||||||
|
|
||||||
|
m_daemonState = new QLabel;
|
||||||
|
updateDaemonStateTexts();
|
||||||
|
|
||||||
|
connect(m_daemonReset, &QToolButton::clicked, this, [this, dockerDevice] {
|
||||||
|
DockerPlugin::setGlobalDaemonState(Utils::nullopt);
|
||||||
|
updateDaemonStateTexts();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_runAsOutsideUser = new QCheckBox(tr("Run as outside user"));
|
||||||
|
m_runAsOutsideUser->setToolTip(tr("Uses user ID and group ID of the user running Qt Creator "
|
||||||
|
"in the docker container."));
|
||||||
|
m_runAsOutsideUser->setChecked(data.useLocalUidGid);
|
||||||
|
m_runAsOutsideUser->setEnabled(HostOsInfo::isLinuxHost());
|
||||||
|
|
||||||
|
connect(m_runAsOutsideUser, &QCheckBox::toggled, this, [&data](bool on) {
|
||||||
|
data.useLocalUidGid = on;
|
||||||
|
});
|
||||||
|
|
||||||
|
m_pathsListLabel = new InfoLabel(tr("Paths to mount:"));
|
||||||
|
// FIXME: 8.0: use
|
||||||
|
//m_pathsListLabel->setToolTip(tr("Source directory list should not be empty"));
|
||||||
|
|
||||||
|
m_pathsListEdit = new PathListEditor;
|
||||||
|
// FIXME: 8.0: use
|
||||||
|
//m_pathsListEdit->setPlaceholderText(tr("Host directories to mount into the container"));
|
||||||
|
m_pathsListEdit->setToolTip(tr("Maps paths in this list one-to-one to the "
|
||||||
|
"docker container."));
|
||||||
|
m_pathsListEdit->setPathList(data.mounts);
|
||||||
|
|
||||||
|
auto markupMounts = [this] {
|
||||||
|
const bool isEmpty = m_pathsListEdit->pathList().isEmpty();
|
||||||
|
m_pathsListLabel->setType(isEmpty ? InfoLabel::Warning : InfoLabel::None);
|
||||||
|
};
|
||||||
|
markupMounts();
|
||||||
|
|
||||||
|
connect(m_pathsListEdit, &PathListEditor::changed, this, [dockerDevice, markupMounts, this] {
|
||||||
|
dockerDevice->setMounts(m_pathsListEdit->pathList());
|
||||||
|
markupMounts();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto logView = new QTextBrowser;
|
||||||
|
connect(&m_kitItemDetector, &KitDetector::logOutput,
|
||||||
|
logView, &QTextBrowser::append);
|
||||||
|
|
||||||
|
auto autoDetectButton = new QPushButton(tr("Auto-detect Kit Items"));
|
||||||
|
auto undoAutoDetectButton = new QPushButton(tr("Remove Auto-Detected Kit Items"));
|
||||||
|
auto listAutoDetectedButton = new QPushButton(tr("List Auto-Detected Kit Items"));
|
||||||
|
|
||||||
|
auto searchDirsComboBox = new QComboBox;
|
||||||
|
searchDirsComboBox->addItem(tr("Search in PATH"));
|
||||||
|
searchDirsComboBox->addItem(tr("Search in Selected Directories"));
|
||||||
|
|
||||||
|
auto searchDirsLineEdit = new FancyLineEdit;
|
||||||
|
// FIXME: 8.0: use
|
||||||
|
//searchDirsLineEdit->setPlaceholderText(tr("Semicolon-separated list of directories"));
|
||||||
|
searchDirsLineEdit->setToolTip(
|
||||||
|
tr("Select the paths in the docker image that should be scanned for kit entries."));
|
||||||
|
searchDirsLineEdit->setHistoryCompleter("DockerMounts", true);
|
||||||
|
|
||||||
|
auto searchPaths = [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, dockerDevice, searchPaths] {
|
||||||
|
logView->clear();
|
||||||
|
dockerDevice->updateContainerAccess();
|
||||||
|
|
||||||
|
m_kitItemDetector.autoDetect(dockerDevice->id().toString(), searchPaths());
|
||||||
|
|
||||||
|
if (DockerPlugin::isDaemonRunning().value_or(false) == false)
|
||||||
|
logView->append(tr("Docker daemon appears to be not running."));
|
||||||
|
else
|
||||||
|
logView->append(tr("Docker daemon appears to be running."));
|
||||||
|
updateDaemonStateTexts();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, device] {
|
||||||
|
logView->clear();
|
||||||
|
m_kitItemDetector.undoAutoDetect(device->id().toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, device] {
|
||||||
|
logView->clear();
|
||||||
|
m_kitItemDetector.listAutoDetected(device->id().toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
using namespace Layouting;
|
||||||
|
|
||||||
|
Form {
|
||||||
|
repoLabel, m_repoLineEdit, Break(),
|
||||||
|
tagLabel, m_tagLineEdit, Break(),
|
||||||
|
idLabel, m_idLineEdit, Break(),
|
||||||
|
daemonStateLabel, m_daemonReset, m_daemonState, Break(),
|
||||||
|
m_runAsOutsideUser, Break(),
|
||||||
|
Column {
|
||||||
|
m_pathsListLabel,
|
||||||
|
m_pathsListEdit,
|
||||||
|
}, Break(),
|
||||||
|
Column {
|
||||||
|
Space(20),
|
||||||
|
Row {
|
||||||
|
searchDirsComboBox,
|
||||||
|
searchDirsLineEdit
|
||||||
|
},
|
||||||
|
Row {
|
||||||
|
autoDetectButton,
|
||||||
|
undoAutoDetectButton,
|
||||||
|
listAutoDetectedButton,
|
||||||
|
Stretch(),
|
||||||
|
},
|
||||||
|
new QLabel(tr("Detection log:")),
|
||||||
|
logView
|
||||||
|
}
|
||||||
|
}.attachTo(this);
|
||||||
|
|
||||||
|
searchDirsLineEdit->setVisible(false);
|
||||||
|
auto updateDirectoriesLineEdit = [searchDirsLineEdit](int index) {
|
||||||
|
searchDirsLineEdit->setVisible(index == 1);
|
||||||
|
if (index == 1)
|
||||||
|
searchDirsLineEdit->setFocus();
|
||||||
|
};
|
||||||
|
QObject::connect(searchDirsComboBox, qOverload<int>(&QComboBox::activated),
|
||||||
|
this, updateDirectoriesLineEdit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockerDeviceWidget::updateDaemonStateTexts()
|
||||||
|
{
|
||||||
|
Utils::optional<bool> daemonState = DockerPlugin::isDaemonRunning();
|
||||||
|
if (!daemonState.has_value()) {
|
||||||
|
m_daemonReset->setIcon(Icons::INFO.icon());
|
||||||
|
m_daemonState->setText(tr("Daemon state not evaluated."));
|
||||||
|
} else if (daemonState.value()) {
|
||||||
|
m_daemonReset->setIcon(Icons::OK.icon());
|
||||||
|
m_daemonState->setText(tr("Docker daemon running."));
|
||||||
|
} else {
|
||||||
|
m_daemonReset->setIcon(Icons::CRITICAL.icon());
|
||||||
|
m_daemonState->setText(tr("Docker daemon not running."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Internal
|
||||||
|
} // Docker
|
65
src/plugins/docker/dockerdevicewidget.h
Normal file
65
src/plugins/docker/dockerdevicewidget.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dockerplugin.h"
|
||||||
|
#include "dockerdevice.h"
|
||||||
|
#include "kitdetector.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/devicesupport/idevicewidget.h>
|
||||||
|
|
||||||
|
#include <utils/pathlisteditor.h>
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
|
||||||
|
namespace Docker {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class DockerDeviceWidget final : public ProjectExplorer::IDeviceWidget
|
||||||
|
{
|
||||||
|
Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerDevice)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DockerDeviceWidget(const ProjectExplorer::IDevice::Ptr &device);
|
||||||
|
|
||||||
|
void updateDeviceFromUi() final {}
|
||||||
|
void updateDaemonStateTexts();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLineEdit *m_repoLineEdit;
|
||||||
|
QLineEdit *m_tagLineEdit;
|
||||||
|
QLineEdit *m_idLineEdit;
|
||||||
|
QToolButton *m_daemonReset;
|
||||||
|
QLabel *m_daemonState;
|
||||||
|
QCheckBox *m_runAsOutsideUser;
|
||||||
|
Utils::InfoLabel *m_pathsListLabel;
|
||||||
|
Utils::PathListEditor *m_pathsListEdit;
|
||||||
|
|
||||||
|
KitDetector m_kitItemDetector;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Internal
|
||||||
|
} // Docker
|
339
src/plugins/docker/kitdetector.cpp
Normal file
339
src/plugins/docker/kitdetector.cpp
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "kitdetector.h"
|
||||||
|
#include "dockerconstants.h"
|
||||||
|
|
||||||
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/toolchain.h>
|
||||||
|
#include <projectexplorer/toolchainmanager.h>
|
||||||
|
|
||||||
|
#include <qtsupport/baseqtversion.h>
|
||||||
|
#include <qtsupport/qtkitinformation.h>
|
||||||
|
#include <qtsupport/qtversionfactory.h>
|
||||||
|
#include <qtsupport/qtversionmanager.h>
|
||||||
|
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
using namespace QtSupport;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace Docker {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class KitDetectorPrivate
|
||||||
|
{
|
||||||
|
Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::KitItemDetector)
|
||||||
|
|
||||||
|
public:
|
||||||
|
KitDetectorPrivate(KitDetector *parent, const IDevice::ConstPtr &device)
|
||||||
|
: q(parent), m_device(device)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void autoDetect();
|
||||||
|
void undoAutoDetect() const;
|
||||||
|
void listAutoDetected() const;
|
||||||
|
|
||||||
|
void setSharedId(const QString &sharedId) { m_sharedId = sharedId; }
|
||||||
|
void setSearchPaths(const FilePaths &searchPaths) { m_searchPaths = searchPaths; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QtVersions autoDetectQtVersions() const;
|
||||||
|
QList<ToolChain *> autoDetectToolChains();
|
||||||
|
void autoDetectCMake();
|
||||||
|
void autoDetectDebugger();
|
||||||
|
|
||||||
|
KitDetector *q;
|
||||||
|
IDevice::ConstPtr m_device;
|
||||||
|
QString m_sharedId;
|
||||||
|
FilePaths m_searchPaths;
|
||||||
|
};
|
||||||
|
|
||||||
|
KitDetector::KitDetector(const IDevice::ConstPtr &device)
|
||||||
|
: d(new KitDetectorPrivate(this, device))
|
||||||
|
{}
|
||||||
|
|
||||||
|
KitDetector::~KitDetector()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetector::autoDetect(const QString &sharedId, const FilePaths &searchPaths) const
|
||||||
|
{
|
||||||
|
d->setSharedId(sharedId);
|
||||||
|
d->setSearchPaths(searchPaths);
|
||||||
|
d->autoDetect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetector::undoAutoDetect(const QString &sharedId) const
|
||||||
|
{
|
||||||
|
d->setSharedId(sharedId);
|
||||||
|
d->undoAutoDetect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetector::listAutoDetected(const QString &sharedId) const
|
||||||
|
{
|
||||||
|
d->setSharedId(sharedId);
|
||||||
|
d->listAutoDetected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetectorPrivate::undoAutoDetect() const
|
||||||
|
{
|
||||||
|
emit q->logOutput(tr("Start removing auto-detected items associated with this docker image."));
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Removing kits..."));
|
||||||
|
for (Kit *kit : KitManager::kits()) {
|
||||||
|
if (kit->autoDetectionSource() == m_sharedId) {
|
||||||
|
emit q->logOutput(tr("Removed \"%1\"").arg(kit->displayName()));
|
||||||
|
KitManager::deregisterKit(kit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Removing Qt version entries..."));
|
||||||
|
for (QtVersion *qtVersion : QtVersionManager::versions()) {
|
||||||
|
if (qtVersion->detectionSource() == m_sharedId) {
|
||||||
|
emit q->logOutput(tr("Removed \"%1\"").arg(qtVersion->displayName()));
|
||||||
|
QtVersionManager::removeVersion(qtVersion);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Removing toolchain entries..."));
|
||||||
|
const Toolchains toolchains = ToolChainManager::toolchains();
|
||||||
|
for (ToolChain *toolChain : toolchains) {
|
||||||
|
if (toolChain && toolChain->detectionSource() == m_sharedId) {
|
||||||
|
emit q->logOutput(tr("Removed \"%1\"").arg(toolChain->displayName()));
|
||||||
|
ToolChainManager::deregisterToolChain(toolChain);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager")) {
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
||||||
|
"removeDetectedCMake",
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QObject *debuggerPlugin = ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin")) {
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(debuggerPlugin,
|
||||||
|
"removeDetectedDebuggers",
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Removal of previously auto-detected kit items finished.") + "\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetectorPrivate::listAutoDetected() const
|
||||||
|
{
|
||||||
|
emit q->logOutput(tr("Start listing auto-detected items associated with this docker image."));
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Kits:"));
|
||||||
|
for (Kit *kit : KitManager::kits()) {
|
||||||
|
if (kit->autoDetectionSource() == m_sharedId)
|
||||||
|
emit q->logOutput(kit->displayName());
|
||||||
|
};
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Qt versions:"));
|
||||||
|
for (QtVersion *qtVersion : QtVersionManager::versions()) {
|
||||||
|
if (qtVersion->detectionSource() == m_sharedId)
|
||||||
|
emit q->logOutput(qtVersion->displayName());
|
||||||
|
};
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Toolchains:"));
|
||||||
|
for (ToolChain *toolChain : ToolChainManager::toolchains()) {
|
||||||
|
if (toolChain->detectionSource() == m_sharedId)
|
||||||
|
emit q->logOutput(toolChain->displayName());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager")) {
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
||||||
|
"listDetectedCMake",
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QObject *debuggerPlugin = ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin")) {
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(debuggerPlugin,
|
||||||
|
"listDetectedDebuggers",
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit q->logOutput('\n' + tr("Listing of previously auto-detected kit items finished.") + "\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QtVersions KitDetectorPrivate::autoDetectQtVersions() const
|
||||||
|
{
|
||||||
|
QtVersions qtVersions;
|
||||||
|
|
||||||
|
QString error;
|
||||||
|
|
||||||
|
const auto handleQmake = [this, &qtVersions, &error](const FilePath &qmake) {
|
||||||
|
if (QtVersion *qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, m_sharedId, &error)) {
|
||||||
|
qtVersions.append(qtVersion);
|
||||||
|
QtVersionManager::addVersion(qtVersion);
|
||||||
|
emit q->logOutput(tr("Found \"%1\"").arg(qtVersion->qmakeFilePath().toUserOutput()));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
emit q->logOutput(tr("Searching for qmake executables..."));
|
||||||
|
|
||||||
|
const QStringList candidates = {"qmake-qt6", "qmake-qt5", "qmake"};
|
||||||
|
for (const FilePath &searchPath : m_searchPaths) {
|
||||||
|
searchPath.iterateDirectory(handleQmake, {candidates, QDir::Files | QDir::Executable,
|
||||||
|
QDirIterator::Subdirectories});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error.isEmpty())
|
||||||
|
emit q->logOutput(tr("Error: %1.").arg(error));
|
||||||
|
if (qtVersions.isEmpty())
|
||||||
|
emit q->logOutput(tr("No Qt installation found."));
|
||||||
|
return qtVersions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toolchains KitDetectorPrivate::autoDetectToolChains()
|
||||||
|
{
|
||||||
|
const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories();
|
||||||
|
|
||||||
|
Toolchains alreadyKnown = ToolChainManager::toolchains();
|
||||||
|
Toolchains allNewToolChains;
|
||||||
|
QApplication::processEvents();
|
||||||
|
emit q->logOutput('\n' + tr("Searching toolchains..."));
|
||||||
|
for (ToolChainFactory *factory : factories) {
|
||||||
|
emit q->logOutput(tr("Searching toolchains of type %1").arg(factory->displayName()));
|
||||||
|
const ToolchainDetector detector(alreadyKnown, m_device, m_searchPaths);
|
||||||
|
const Toolchains newToolChains = factory->autoDetect(detector);
|
||||||
|
for (ToolChain *toolChain : newToolChains) {
|
||||||
|
emit q->logOutput(tr("Found \"%1\"").arg(toolChain->compilerCommand().toUserOutput()));
|
||||||
|
toolChain->setDetectionSource(m_sharedId);
|
||||||
|
ToolChainManager::registerToolChain(toolChain);
|
||||||
|
alreadyKnown.append(toolChain);
|
||||||
|
}
|
||||||
|
allNewToolChains.append(newToolChains);
|
||||||
|
}
|
||||||
|
emit q->logOutput(tr("%1 new toolchains found.").arg(allNewToolChains.size()));
|
||||||
|
|
||||||
|
return allNewToolChains;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetectorPrivate::autoDetectCMake()
|
||||||
|
{
|
||||||
|
QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager");
|
||||||
|
if (!cmakeManager)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
||||||
|
"autoDetectCMakeForDevice",
|
||||||
|
Q_ARG(Utils::FilePaths, m_searchPaths),
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetectorPrivate::autoDetectDebugger()
|
||||||
|
{
|
||||||
|
QObject *debuggerPlugin = ExtensionSystem::PluginManager::getObjectByName("DebuggerPlugin");
|
||||||
|
if (!debuggerPlugin)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString logMessage;
|
||||||
|
const bool res = QMetaObject::invokeMethod(debuggerPlugin,
|
||||||
|
"autoDetectDebuggersForDevice",
|
||||||
|
Q_ARG(Utils::FilePaths, m_searchPaths),
|
||||||
|
Q_ARG(QString, m_sharedId),
|
||||||
|
Q_ARG(QString *, &logMessage));
|
||||||
|
QTC_CHECK(res);
|
||||||
|
emit q->logOutput('\n' + logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KitDetectorPrivate::autoDetect()
|
||||||
|
{
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
|
||||||
|
undoAutoDetect();
|
||||||
|
|
||||||
|
emit q->logOutput(tr("Starting auto-detection. This will take a while..."));
|
||||||
|
|
||||||
|
const Toolchains toolchains = autoDetectToolChains();
|
||||||
|
const QtVersions qtVersions = autoDetectQtVersions();
|
||||||
|
|
||||||
|
autoDetectCMake();
|
||||||
|
autoDetectDebugger();
|
||||||
|
|
||||||
|
const auto initializeKit = [this, toolchains, qtVersions](Kit *k) {
|
||||||
|
k->setAutoDetected(false);
|
||||||
|
k->setAutoDetectionSource(m_sharedId);
|
||||||
|
k->setUnexpandedDisplayName("%{Device:Name}");
|
||||||
|
|
||||||
|
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DOCKER_DEVICE_TYPE);
|
||||||
|
DeviceKitAspect::setDevice(k, m_device);
|
||||||
|
|
||||||
|
QtVersion *qt = nullptr;
|
||||||
|
if (!qtVersions.isEmpty()) {
|
||||||
|
qt = qtVersions.at(0);
|
||||||
|
QtSupport::QtKitAspect::setQtVersion(k, qt);
|
||||||
|
}
|
||||||
|
Toolchains toolchainsToSet;
|
||||||
|
toolchainsToSet = ToolChainManager::toolchains([qt, this](const ToolChain *tc){
|
||||||
|
return tc->detectionSource() == m_sharedId
|
||||||
|
&& (!qt || qt->qtAbis().contains(tc->targetAbi()));
|
||||||
|
});
|
||||||
|
for (ToolChain *toolChain : toolchainsToSet)
|
||||||
|
ToolChainKitAspect::setToolChain(k, toolChain);
|
||||||
|
|
||||||
|
k->setSticky(ToolChainKitAspect::id(), true);
|
||||||
|
k->setSticky(QtSupport::QtKitAspect::id(), true);
|
||||||
|
k->setSticky(DeviceKitAspect::id(), true);
|
||||||
|
k->setSticky(DeviceTypeKitAspect::id(), true);
|
||||||
|
};
|
||||||
|
|
||||||
|
Kit *kit = KitManager::registerKit(initializeKit);
|
||||||
|
emit q->logOutput('\n' + tr("Registered kit %1").arg(kit->displayName()));
|
||||||
|
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Internal
|
||||||
|
} // Docker
|
55
src/plugins/docker/kitdetector.h
Normal file
55
src/plugins/docker/kitdetector.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <projectexplorer/devicesupport/idevice.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace Docker {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class KitDetector : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit KitDetector(const ProjectExplorer::IDevice::ConstPtr &device);
|
||||||
|
~KitDetector() override;
|
||||||
|
|
||||||
|
void autoDetect(const QString &sharedId, const Utils::FilePaths &selectedPaths) const;
|
||||||
|
void undoAutoDetect(const QString &sharedId) const;
|
||||||
|
void listAutoDetected(const QString &sharedId) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void logOutput(const QString &msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class KitDetectorPrivate *d = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Internal
|
||||||
|
} // Docker
|
Reference in New Issue
Block a user