docker: Change Settings to single owner

We change DockerSettings to have a single owner.
Since DockerDevices are destroyed after the plugin
is unloaded, we have to make sure to remove the
settings from devices during plugin teardown.

For this we store a list of created devices in
the factory, and call their shutdown function when
the plugin unloads.

Change-Id: Ic9c7d8ad9437c48d68f20c9a8f8ad7449b3cb972
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2022-07-04 14:24:51 +02:00
parent 4d72cb55ba
commit 15c7f08e4a
7 changed files with 67 additions and 32 deletions

View File

@@ -43,7 +43,7 @@ using namespace Utils;
DockerApi *s_instance{nullptr}; DockerApi *s_instance{nullptr};
DockerApi::DockerApi(QSharedPointer<DockerSettings> settings) DockerApi::DockerApi(DockerSettings *settings)
: m_settings(settings) : m_settings(settings)
{ {
s_instance = this; s_instance = this;

View File

@@ -42,7 +42,7 @@ class DockerApi : public QObject
Q_OBJECT Q_OBJECT
public: public:
DockerApi(QSharedPointer<DockerSettings> settings); DockerApi(DockerSettings *settings);
static DockerApi *instance(); static DockerApi *instance();
@@ -63,7 +63,7 @@ private:
private: private:
Utils::optional<bool> m_dockerDaemonAvailable; Utils::optional<bool> m_dockerDaemonAvailable;
QMutex m_daemonCheckGuard; QMutex m_daemonCheckGuard;
QSharedPointer<DockerSettings> m_settings; DockerSettings *m_settings;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -106,7 +106,7 @@ static Q_LOGGING_CATEGORY(dockerDeviceLog, "qtc.docker.device", QtWarningMsg);
class ContainerShell : public Utils::DeviceShell class ContainerShell : public Utils::DeviceShell
{ {
public: public:
ContainerShell(QSharedPointer<DockerSettings> settings, const QString &containerId) ContainerShell(DockerSettings *settings, const QString &containerId)
: m_settings(settings) : m_settings(settings)
, m_containerId(containerId) , m_containerId(containerId)
{ {
@@ -119,7 +119,7 @@ private:
} }
private: private:
QSharedPointer<DockerSettings> m_settings; DockerSettings *m_settings;
QString m_containerId; QString m_containerId;
}; };
@@ -128,7 +128,7 @@ class DockerDevicePrivate : public QObject
Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerDevice) Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerDevice)
public: public:
DockerDevicePrivate(DockerDevice *parent, QSharedPointer<DockerSettings> settings) DockerDevicePrivate(DockerDevice *parent, DockerSettings *settings)
: q(parent) : q(parent)
, m_settings(settings) , m_settings(settings)
{} {}
@@ -147,7 +147,7 @@ public:
DockerDevice *q; DockerDevice *q;
DockerDeviceData m_data; DockerDeviceData m_data;
QSharedPointer<DockerSettings> m_settings; DockerSettings *m_settings;
// For local file access // For local file access
@@ -320,7 +320,7 @@ QString DockerDeviceData::repoAndTag() const
// DockerDevice // DockerDevice
DockerDevice::DockerDevice(QSharedPointer<DockerSettings> settings, const DockerDeviceData &data) DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &data)
: d(new DockerDevicePrivate(this, settings)) : d(new DockerDevicePrivate(this, settings))
{ {
d->m_data = data; d->m_data = data;
@@ -364,6 +364,12 @@ DockerDevice::~DockerDevice()
delete d; delete d;
} }
void DockerDevice::shutdown()
{
d->stopCurrentContainer();
d->m_settings = nullptr;
}
const DockerDeviceData &DockerDevice::data() const const DockerDeviceData &DockerDevice::data() const
{ {
return d->m_data; return d->m_data;
@@ -374,8 +380,6 @@ DockerDeviceData &DockerDevice::data()
return d->m_data; return d->m_data;
} }
void DockerDevice::updateContainerAccess() const void DockerDevice::updateContainerAccess() const
{ {
d->updateContainerAccess(); d->updateContainerAccess();
@@ -383,7 +387,7 @@ void DockerDevice::updateContainerAccess() const
void DockerDevicePrivate::stopCurrentContainer() void DockerDevicePrivate::stopCurrentContainer()
{ {
if (m_container.isEmpty() || !DockerApi::isDockerDaemonAvailable(false).value_or(false)) if (!m_settings || m_container.isEmpty() || !DockerApi::isDockerDaemonAvailable(false).value_or(false))
return; return;
m_shell.reset(); m_shell.reset();
@@ -412,6 +416,9 @@ static QString getLocalIPv4Address()
void DockerDevicePrivate::startContainer() void DockerDevicePrivate::startContainer()
{ {
if (!m_settings)
return;
const QString display = HostOsInfo::isLinuxHost() ? QString(":0") const QString display = HostOsInfo::isLinuxHost() ? QString(":0")
: QString(getLocalIPv4Address() + ":0.0"); : QString(getLocalIPv4Address() + ":0.0");
CommandLine dockerCreate{m_settings->dockerBinaryPath.filePath(), {"create", CommandLine dockerCreate{m_settings->dockerBinaryPath.filePath(), {"create",
@@ -494,6 +501,9 @@ void DockerDevice::setMounts(const QStringList &mounts) const
CommandLine DockerDevice::withDockerExecCmd(const Utils::CommandLine &cmd, bool interactive) const CommandLine DockerDevice::withDockerExecCmd(const Utils::CommandLine &cmd, bool interactive) const
{ {
if (!d->m_settings)
return {};
QStringList args; QStringList args;
args << "exec"; args << "exec";
@@ -1003,8 +1013,9 @@ void DockerDevicePrivate::fetchSystemEnviroment()
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
{ {
if (!DockerApi::isDockerDaemonAvailable(false).value_or(false)) if (!m_settings || !DockerApi::isDockerDaemonAvailable(false).value_or(false))
return false; return false;
CommandLine dcmd{m_settings->dockerBinaryPath.filePath(), {"exec", m_container}}; CommandLine dcmd{m_settings->dockerBinaryPath.filePath(), {"exec", m_container}};
dcmd.addCommandLineAsArgs(cmd); dcmd.addCommandLineAsArgs(cmd);
@@ -1066,7 +1077,7 @@ public:
class DockerDeviceSetupWizard final : public QDialog class DockerDeviceSetupWizard final : public QDialog
{ {
public: public:
DockerDeviceSetupWizard(QSharedPointer<DockerSettings> settings) DockerDeviceSetupWizard(DockerSettings *settings)
: QDialog(ICore::dialogParent()) : QDialog(ICore::dialogParent())
, m_settings(settings) , m_settings(settings)
{ {
@@ -1168,7 +1179,7 @@ public:
TreeView *m_view = nullptr; TreeView *m_view = nullptr;
QTextBrowser *m_log = nullptr; QTextBrowser *m_log = nullptr;
QDialogButtonBox *m_buttons; QDialogButtonBox *m_buttons;
QSharedPointer<DockerSettings> m_settings; DockerSettings *m_settings;
QtcProcess *m_process = nullptr; QtcProcess *m_process = nullptr;
QString m_selectedId; QString m_selectedId;
@@ -1176,7 +1187,7 @@ public:
// Factory // Factory
DockerDeviceFactory::DockerDeviceFactory(QSharedPointer<DockerSettings> settings) DockerDeviceFactory::DockerDeviceFactory(DockerSettings *settings)
: IDeviceFactory(Constants::DOCKER_DEVICE_TYPE) : IDeviceFactory(Constants::DOCKER_DEVICE_TYPE)
{ {
setDisplayName(DockerDevice::tr("Docker Device")); setDisplayName(DockerDevice::tr("Docker Device"));
@@ -1187,7 +1198,21 @@ DockerDeviceFactory::DockerDeviceFactory(QSharedPointer<DockerSettings> settings
return IDevice::Ptr(); return IDevice::Ptr();
return wizard.device(); return wizard.device();
}); });
setConstructionFunction([settings] { return DockerDevice::create(settings, {}); }); setConstructionFunction([settings, this] {
auto device = DockerDevice::create(settings, {});
QMutexLocker lk(&m_deviceListMutex);
m_existingDevices.push_back(device);
return device;
});
}
void DockerDeviceFactory::shutdownExistingDevices()
{
QMutexLocker lk(&m_deviceListMutex);
for (const auto &weakDevice : m_existingDevices) {
if (QSharedPointer<DockerDevice> device = weakDevice.lock())
device->shutdown();
}
} }
} // Internal } // Internal

View File

@@ -33,6 +33,8 @@
#include <utils/aspects.h> #include <utils/aspects.h>
#include <QMutex>
namespace Docker { namespace Docker {
namespace Internal { namespace Internal {
@@ -58,10 +60,12 @@ public:
using Ptr = QSharedPointer<DockerDevice>; using Ptr = QSharedPointer<DockerDevice>;
using ConstPtr = QSharedPointer<const DockerDevice>; using ConstPtr = QSharedPointer<const DockerDevice>;
explicit DockerDevice(QSharedPointer<DockerSettings> settings, const DockerDeviceData &data); explicit DockerDevice(DockerSettings *settings, const DockerDeviceData &data);
~DockerDevice(); ~DockerDevice();
static Ptr create(QSharedPointer<DockerSettings> settings, const DockerDeviceData &data) { return Ptr(new DockerDevice(settings, data)); } void shutdown();
static Ptr create(DockerSettings *settings, const DockerDeviceData &data) { return Ptr(new DockerDevice(settings, data)); }
ProjectExplorer::IDeviceWidget *createWidget() override; ProjectExplorer::IDeviceWidget *createWidget() override;
QList<ProjectExplorer::Task> validate() const override; QList<ProjectExplorer::Task> validate() const override;
@@ -135,7 +139,13 @@ private:
class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory class DockerDeviceFactory final : public ProjectExplorer::IDeviceFactory
{ {
public: public:
DockerDeviceFactory(QSharedPointer<DockerSettings> settings); DockerDeviceFactory(DockerSettings *settings);
void shutdownExistingDevices();
private:
QMutex m_deviceListMutex;
std::vector<QWeakPointer<DockerDevice> > m_existingDevices;
}; };
} // Internal } // Internal

View File

@@ -43,14 +43,14 @@ namespace Internal {
class DockerPluginPrivate class DockerPluginPrivate
{ {
public: public:
QSharedPointer<DockerSettings> m_settings{new DockerSettings}; ~DockerPluginPrivate() {
DockerDeviceFactory deviceFactory{m_settings}; m_deviceFactory.shutdownExistingDevices();
DockerSettingsPage m_settingPage{m_settings}; }
// DockerBuildStepFactory buildStepFactory; DockerSettings m_settings;
Utils::optional<bool> daemonRunning; DockerDeviceFactory m_deviceFactory{&m_settings};
DockerSettingsPage m_settingPage{&m_settings};
DockerApi dockerApi{m_settings}; DockerApi m_dockerApi{&m_settings};
}; };
static DockerPlugin *s_instance = nullptr; static DockerPlugin *s_instance = nullptr;
@@ -63,7 +63,7 @@ DockerPlugin::DockerPlugin()
DockerApi *DockerPlugin::dockerApi() DockerApi *DockerPlugin::dockerApi()
{ {
QTC_ASSERT(s_instance, return nullptr); QTC_ASSERT(s_instance, return nullptr);
return &s_instance->d->dockerApi; return &s_instance->d->m_dockerApi;
} }
DockerPlugin::~DockerPlugin() DockerPlugin::~DockerPlugin()

View File

@@ -47,7 +47,7 @@ DockerSettings::DockerSettings()
registerAspect(&dockerBinaryPath); registerAspect(&dockerBinaryPath);
dockerBinaryPath.setDisplayStyle(StringAspect::PathChooserDisplay); dockerBinaryPath.setDisplayStyle(StringAspect::PathChooserDisplay);
dockerBinaryPath.setExpectedKind(PathChooser::ExistingCommand); dockerBinaryPath.setExpectedKind(PathChooser::ExistingCommand);
dockerBinaryPath.setDefaultValue(FilePath::fromString("docker").searchInPath().toString()); dockerBinaryPath.setDefaultValue(FilePath::fromString("docker").searchInPath({"/usr/local/bin"}).toString());
dockerBinaryPath.setDisplayName(tr("Docker CLI")); dockerBinaryPath.setDisplayName(tr("Docker CLI"));
dockerBinaryPath.setHistoryCompleter("Docker.Command.History"); dockerBinaryPath.setHistoryCompleter("Docker.Command.History");
dockerBinaryPath.setLabelText(tr("Command:")); dockerBinaryPath.setLabelText(tr("Command:"));
@@ -58,14 +58,14 @@ DockerSettings::DockerSettings()
// DockerSettingsPage // DockerSettingsPage
DockerSettingsPage::DockerSettingsPage(QSharedPointer<DockerSettings> settings) DockerSettingsPage::DockerSettingsPage(DockerSettings *settings)
{ {
setId(Docker::Constants::DOCKER_SETTINGS_ID); setId(Docker::Constants::DOCKER_SETTINGS_ID);
setDisplayName(DockerSettings::tr("Docker")); setDisplayName(DockerSettings::tr("Docker"));
setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY);
setSettings(settings.get()); setSettings(settings);
setLayouter([settings = settings.get()](QWidget *widget) { setLayouter([settings](QWidget *widget) {
DockerSettings &s = *settings; DockerSettings &s = *settings;
using namespace Layouting; using namespace Layouting;

View File

@@ -44,7 +44,7 @@ public:
class DockerSettingsPage final : public Core::IOptionsPage class DockerSettingsPage final : public Core::IOptionsPage
{ {
public: public:
explicit DockerSettingsPage(QSharedPointer<DockerSettings> settings); explicit DockerSettingsPage(DockerSettings *settings);
}; };
} // namespace Internal } // namespace Internal