Docker: Create a partial kit on device creation

Device, Toolchain, and Qt; no Debugger, cmake, ...

Change-Id: Icca660aef62470dda638050fddb74fb1a3032af2
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2021-05-18 06:16:25 +02:00
parent 8ffeecc633
commit 83ae140e8c
2 changed files with 78 additions and 34 deletions

View File

@@ -33,11 +33,14 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <projectexplorer/devicesupport/idevicewidget.h> #include <projectexplorer/devicesupport/idevicewidget.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/runcontrol.h> #include <projectexplorer/runcontrol.h>
#include <projectexplorer/toolchain.h> #include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h> #include <projectexplorer/toolchainmanager.h>
#include <qtsupport/baseqtversion.h> #include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionfactory.h> #include <qtsupport/qtversionfactory.h>
#include <qtsupport/qtversionmanager.h> #include <qtsupport/qtversionmanager.h>
@@ -268,7 +271,7 @@ IDeviceWidget *DockerDevice::createWidget()
class DockerDevicePrivate : public QObject class DockerDevicePrivate : public QObject
{ {
public: public:
DockerDevicePrivate() DockerDevicePrivate(DockerDevice *parent) : q(parent)
{ {
connect(&m_mergedDirWatcher, &QFileSystemWatcher::fileChanged, this, [](const QString &path) { connect(&m_mergedDirWatcher, &QFileSystemWatcher::fileChanged, this, [](const QString &path) {
Q_UNUSED(path) Q_UNUSED(path)
@@ -284,6 +287,14 @@ public:
int runSynchronously(const CommandLine &cmd) const; int runSynchronously(const CommandLine &cmd) const;
void tryCreateLocalFileAccess();
void setupKit();
BaseQtVersion *autoDetectQtVersion() const;
QList<ToolChain *> autoDetectToolChains();
void autoDetectCMake();
DockerDevice *q;
DockerDeviceData m_data; DockerDeviceData m_data;
// For local file access // For local file access
@@ -294,7 +305,7 @@ public:
}; };
DockerDevice::DockerDevice(const DockerDeviceData &data) DockerDevice::DockerDevice(const DockerDeviceData &data)
: d(new DockerDevicePrivate) : d(new DockerDevicePrivate(this))
{ {
d->m_data = data; d->m_data = data;
@@ -346,59 +357,97 @@ const DockerDeviceData &DockerDevice::data() const
return d->m_data; return d->m_data;
} }
void DockerDevice::autoDetectQtVersion() const BaseQtVersion *DockerDevicePrivate::autoDetectQtVersion() const
{ {
QString error; QString error;
QString source = "docker:" + d->m_data.imageId; QString source = "docker:" + m_data.imageId;
const QStringList candidates = {"/usr/local/bin/qmake", "/usr/bin/qmake"}; const QStringList candidates = {"/usr/local/bin/qmake", "/usr/bin/qmake"};
for (const QString &candidate : candidates) { for (const QString &candidate : candidates) {
const FilePath qmake = mapToGlobalPath(FilePath::fromString(candidate)); const FilePath qmake = q->mapToGlobalPath(FilePath::fromString(candidate));
if (auto qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, source, &error)) { if (auto qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake, false, source, &error)) {
QtVersionManager::addVersion(qtVersion); QtVersionManager::addVersion(qtVersion);
return; return qtVersion;
} }
} }
return nullptr;
} }
void DockerDevice::autoDetectToolChains() QList<ToolChain *> DockerDevicePrivate::autoDetectToolChains()
{ {
const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories(); const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories();
QList<ToolChain *> toolChains; QList<ToolChain *> toolChains;
for (ToolChainFactory *factory : factories) { for (ToolChainFactory *factory : factories) {
const QList<ToolChain *> newToolChains = factory->autoDetect(toolChains, sharedFromThis()); const QList<ToolChain *> newToolChains = factory->autoDetect(toolChains, q->sharedFromThis());
for (ToolChain *toolChain : newToolChains) { for (ToolChain *toolChain : newToolChains) {
LOG("Found ToolChain: " << toolChain->compilerCommand().toUserOutput()); LOG("Found ToolChain: " << toolChain->compilerCommand().toUserOutput());
ToolChainManager::registerToolChain(toolChain); ToolChainManager::registerToolChain(toolChain);
toolChains.append(toolChain); toolChains.append(toolChain);
} }
} }
return toolChains;
} }
void DockerDevice::autoDetectCMake() void DockerDevicePrivate::autoDetectCMake()
{ {
QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager"); QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager");
if (!cmakeManager) if (!cmakeManager)
return; return;
QString error; QString error;
QString source = "docker:" + d->m_data.imageId; QString source = "docker:" + m_data.imageId;
const QStringList candidates = {"/usr/local/bin/cmake", "/usr/bin/cmake"}; const QStringList candidates = {"/usr/local/bin/cmake", "/usr/bin/cmake"};
for (const QString &candidate : candidates) { for (const QString &candidate : candidates) {
const FilePath cmake = mapToGlobalPath(FilePath::fromString(candidate)); const FilePath cmake = q->mapToGlobalPath(FilePath::fromString(candidate));
QTC_CHECK(hasLocalFileAccess()); QTC_CHECK(q->hasLocalFileAccess());
if (cmake.isExecutableFile()) { if (cmake.isExecutableFile()) {
const bool res = QMetaObject::invokeMethod(cmakeManager, const bool res = QMetaObject::invokeMethod(cmakeManager,
"registerCMakeByPath", "registerCMakeByPath",
Q_ARG(Utils::FilePath, cmake)); Q_ARG(Utils::FilePath, cmake));
QTC_CHECK(res); QTC_CHECK(res);
} }
} }
}
void DockerDevicePrivate::setupKit()
{
tryCreateLocalFileAccess();
QList<ToolChain *> toolChains = autoDetectToolChains();
BaseQtVersion *qt = autoDetectQtVersion();
autoDetectCMake();
const auto initializeKit = [this, toolChains, qt](Kit *k) {
k->setAutoDetected(false);
k->setAutoDetectionSource("DockerDevice:" + m_data.imageId);
k->setUnexpandedDisplayName("%{Device:Name}");
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DOCKER_DEVICE_TYPE);
DeviceKitAspect::setDevice(k, q->sharedFromThis());
for (ToolChain *tc : toolChains)
ToolChainKitAspect::setToolChain(k, tc);
QtSupport::QtKitAspect::setQtVersion(k, qt);
k->setSticky(ToolChainKitAspect::id(), true);
k->setSticky(QtSupport::QtKitAspect::id(), true);
k->setSticky(DeviceKitAspect::id(), true);
k->setSticky(DeviceTypeKitAspect::id(), true);
};
KitManager::registerKit(initializeKit);
} }
void DockerDevice::tryCreateLocalFileAccess() const void DockerDevice::tryCreateLocalFileAccess() const
{ {
if (!d->m_container.isEmpty()) d->tryCreateLocalFileAccess();
}
void DockerDevicePrivate::tryCreateLocalFileAccess()
{
if (!m_container.isEmpty())
return; return;
QString tempFileName; QString tempFileName;
@@ -409,25 +458,25 @@ void DockerDevice::tryCreateLocalFileAccess() const
tempFileName = temp.fileName(); tempFileName = temp.fileName();
} }
d->m_shell = new QtcProcess; m_shell = new QtcProcess;
// FIXME: Make mounts flexible // FIXME: Make mounts flexible
d->m_shell->setCommand({"docker", {"run", "-i", "--cidfile=" + tempFileName, m_shell->setCommand({"docker", {"run", "-i", "--cidfile=" + tempFileName,
"-v", "/opt:/opt", "-v", "/opt:/opt",
"-v", "/data:/data", "-v", "/data:/data",
"-e", "DISPLAY=:0", "-e", "DISPLAY=:0",
"-e", "XAUTHORITY=/.Xauthority", "-e", "XAUTHORITY=/.Xauthority",
"--net", "host", "--net", "host",
d->m_data.imageId, "/bin/sh"}}); m_data.imageId, "/bin/sh"}});
LOG("RUNNING: " << d->m_shell->commandLine().toUserOutput()); LOG("RUNNING: " << m_shell->commandLine().toUserOutput());
d->m_shell->start(); m_shell->start();
d->m_shell->waitForStarted(); m_shell->waitForStarted();
LOG("CHECKING: " << tempFileName); LOG("CHECKING: " << tempFileName);
for (int i = 0; i <= 10; ++i) { for (int i = 0; i <= 10; ++i) {
QFile file(tempFileName); QFile file(tempFileName);
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
d->m_container = QString::fromUtf8(file.readAll()).trimmed(); m_container = QString::fromUtf8(file.readAll()).trimmed();
if (!d->m_container.isEmpty()) { if (!m_container.isEmpty()) {
LOG("Container: " << d->m_container); LOG("Container: " << d->m_container);
break; break;
} }
@@ -439,16 +488,16 @@ void DockerDevice::tryCreateLocalFileAccess() const
} }
QtcProcess proc; QtcProcess proc;
proc.setCommand({"docker", {"inspect", "--format={{.GraphDriver.Data.MergedDir}}", d->m_container}}); proc.setCommand({"docker", {"inspect", "--format={{.GraphDriver.Data.MergedDir}}", m_container}});
//LOG(proc2.commandLine().toUserOutput()); //LOG(proc2.commandLine().toUserOutput());
proc.start(); proc.start();
proc.waitForFinished(); proc.waitForFinished();
const QByteArray out = proc.readAllStandardOutput(); const QByteArray out = proc.readAllStandardOutput();
d->m_mergedDir = QString::fromUtf8(out).trimmed(); m_mergedDir = QString::fromUtf8(out).trimmed();
if (d->m_mergedDir.endsWith('/')) if (m_mergedDir.endsWith('/'))
d->m_mergedDir.chop(1); m_mergedDir.chop(1);
d->m_mergedDirWatcher.addPath(d->m_mergedDir); m_mergedDirWatcher.addPath(m_mergedDir);
} }
bool DockerDevice::hasLocalFileAccess() const bool DockerDevice::hasLocalFileAccess() const
@@ -822,10 +871,7 @@ public:
device->setType(Constants::DOCKER_DEVICE_TYPE); device->setType(Constants::DOCKER_DEVICE_TYPE);
device->setMachineType(IDevice::Hardware); device->setMachineType(IDevice::Hardware);
device->tryCreateLocalFileAccess(); device->d->setupKit();
device->autoDetectToolChains();
device->autoDetectQtVersion();
device->autoDetectCMake();
return device; return device;
} }

View File

@@ -85,9 +85,6 @@ public:
void runProcess(Utils::QtcProcess &process) const override; void runProcess(Utils::QtcProcess &process) const override;
const DockerDeviceData &data() const; const DockerDeviceData &data() const;
void autoDetectQtVersion() const;
void autoDetectToolChains();
void autoDetectCMake();
void tryCreateLocalFileAccess() const; void tryCreateLocalFileAccess() const;
bool hasLocalFileAccess() const; bool hasLocalFileAccess() const;
@@ -101,6 +98,7 @@ private:
QVariantMap toMap() const final; QVariantMap toMap() const final;
class DockerDevicePrivate *d = nullptr; class DockerDevicePrivate *d = nullptr;
friend class DockerDeviceSetupWizard;
}; };
class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory