Docker: Cleanup docker process interface

Instead of creating the actual command in two places
this change moves everything into one function.

Instead of sending the environment and working directory
into the shell as arguments, we send it via the correct
docker exec cli arguments.

Instead of creating QStringLists and adding them
to a CommandLine we directly add them to the
CommandLine instead.

This also fixes an issue when the working directory
contains spaces.

Fixes: QTCREATORBUG-28476
Change-Id: I4f5b39a2dd4c86d20717dbb53003f1eb60f6c089
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2022-11-21 15:24:33 +01:00
parent 3e6c3d9fe7
commit 75b43de14a

View File

@@ -82,8 +82,6 @@ Q_LOGGING_CATEGORY(dockerDeviceLog, "qtc.docker.device", QtWarningMsg);
namespace Docker::Internal { namespace Docker::Internal {
const QString s_pidMarker = "__qtc$$qtc__";
class ContainerShell : public Utils::DeviceShell class ContainerShell : public Utils::DeviceShell
{ {
public: public:
@@ -156,7 +154,10 @@ public:
Environment environment(); Environment environment();
CommandLine withDockerExecCmd(const CommandLine &cmd, bool interactive = false); CommandLine withDockerExecCmd(const CommandLine &cmd,
Environment *env = nullptr,
FilePath *workDir = nullptr,
bool interactive = false);
bool prepareForBuild(const Target *target); bool prepareForBuild(const Target *target);
Tasks validateMounts() const; Tasks validateMounts() const;
@@ -202,9 +203,6 @@ private:
qint64 write(const QByteArray &data) override; qint64 write(const QByteArray &data) override;
void sendControlSignal(ControlSignal controlSignal) override; void sendControlSignal(ControlSignal controlSignal) override;
private:
CommandLine fullLocalCommandLine(bool interactive);
private: private:
DockerDevicePrivate *m_devicePrivate = nullptr; DockerDevicePrivate *m_devicePrivate = nullptr;
// Store the IDevice::ConstPtr in order to extend the lifetime of device for as long // Store the IDevice::ConstPtr in order to extend the lifetime of device for as long
@@ -216,29 +214,6 @@ private:
bool m_hasReceivedFirstOutput = false; bool m_hasReceivedFirstOutput = false;
}; };
CommandLine DockerProcessImpl::fullLocalCommandLine(bool interactive)
{
QStringList args;
if (!m_setup.m_workingDirectory.isEmpty()) {
QTC_CHECK(DeviceManager::deviceForPath(m_setup.m_workingDirectory) == m_device);
args.append({"cd", m_setup.m_workingDirectory.path()});
args.append("&&");
}
args.append({"echo", s_pidMarker, "&&"});
const Environment &env = m_setup.m_environment;
for (auto it = env.constBegin(); it != env.constEnd(); ++it)
args.append(env.key(it) + "='" + env.expandedValueForKey(env.key(it)) + '\'');
args.append("exec");
args.append({m_setup.m_commandLine.executable().path(), m_setup.m_commandLine.arguments()});
CommandLine shCmd("/bin/sh", {"-c", args.join(" ")});
return m_devicePrivate->withDockerExecCmd(shCmd, interactive);
}
DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePrivate *devicePrivate) DockerProcessImpl::DockerProcessImpl(IDevice::ConstPtr device, DockerDevicePrivate *devicePrivate)
: m_devicePrivate(devicePrivate) : m_devicePrivate(devicePrivate)
, m_device(std::move(device)) , m_device(std::move(device))
@@ -304,7 +279,14 @@ void DockerProcessImpl::start()
if (m_setup.m_lowPriority) if (m_setup.m_lowPriority)
m_process.setLowPriority(); m_process.setLowPriority();
m_process.setCommand(fullLocalCommandLine(m_setup.m_processMode == ProcessMode::Writer)); const bool interactive = m_setup.m_processMode == ProcessMode::Writer;
const CommandLine fullCommandLine = m_devicePrivate
->withDockerExecCmd(m_setup.m_commandLine,
&m_setup.m_environment,
&m_setup.m_workingDirectory,
interactive);
m_process.setCommand(fullCommandLine);
m_process.start(); m_process.start();
} }
@@ -445,23 +427,44 @@ void DockerDevice::updateContainerAccess() const
d->updateContainerAccess(); d->updateContainerAccess();
} }
CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, bool interactive) CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd,
Environment *env,
FilePath *workDir,
bool interactive)
{ {
if (!m_settings) if (!m_settings)
return {}; return {};
updateContainerAccess(); updateContainerAccess();
QStringList args; CommandLine dockerCmd{m_settings->dockerBinaryPath.filePath(), {"exec"}};
args << "exec";
if (interactive) if (interactive)
args << "-i"; dockerCmd.addArg("-i");
args << m_container;
CommandLine dcmd{m_settings->dockerBinaryPath.filePath(), args}; if (env) {
dcmd.addCommandLineAsArgs(cmd, CommandLine::Raw); for (auto it = env->constBegin(); it != env->constEnd(); ++it) {
return dcmd; dockerCmd.addArg("-e");
dockerCmd.addArg(env->key(it) + "=" + env->expandedValueForKey(env->key(it)));
}
}
if (workDir && !workDir->isEmpty())
dockerCmd.addArgs({"-w", workDir->path()});
dockerCmd.addArg(m_container);
dockerCmd.addArgs({"/bin/sh", "-c"});
CommandLine exec("exec");
exec.addCommandLineAsArgs(cmd);
CommandLine echo("echo");
echo.addArgs("__qtc$$qtc__", CommandLine::Raw);
echo.addCommandLineWithAnd(exec);
dockerCmd.addCommandLineAsSingleArg(echo);
return dockerCmd;
} }
void DockerDevicePrivate::stopCurrentContainer() void DockerDevicePrivate::stopCurrentContainer()