summaryrefslogtreecommitdiff
path: root/src/plugins/docker/dockerdevice.cpp
diff options
context:
space:
mode:
authorMarcus Tillmanns <marcus.tillmanns@qt.io>2022-10-06 13:03:23 +0200
committerMarcus Tillmanns <marcus.tillmanns@qt.io>2022-10-11 12:24:29 +0000
commitbcadbe666b719581814291ab28d7c490d06a85cc (patch)
treea17ee54c2440c4e0f96640c7937c2121ea96599b /src/plugins/docker/dockerdevice.cpp
parent4b42f05439417f76619c0d667cf691592d0fe388 (diff)
downloadqt-creator-bcadbe666b719581814291ab28d7c490d06a85cc.tar.gz
Docker: Fix mount arguments
Previously when trying to mount paths that contained spaces or colons docker create would fail as the -v/--volume syntax does not support these. Switching to "--mount" and using the "type=bind" syntax allows to escape the necessary characters. Change-Id: If969173505dbf1b36a67dc8b398c58b78941519a Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins/docker/dockerdevice.cpp')
-rw-r--r--src/plugins/docker/dockerdevice.cpp94
1 files changed, 74 insertions, 20 deletions
diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp
index 401e98d59c..87815a7b3f 100644
--- a/src/plugins/docker/dockerdevice.cpp
+++ b/src/plugins/docker/dockerdevice.cpp
@@ -149,6 +149,7 @@ public:
CommandLine withDockerExecCmd(const CommandLine &cmd, bool interactive = false);
bool prepareForBuild(const Target *target);
+ Tasks validateMounts() const;
bool createContainer();
void startContainer();
@@ -157,6 +158,8 @@ public:
bool addTemporaryMount(const FilePath &path, const FilePath &containerPath);
+ QStringList createMountArgs() const;
+
DockerDevice *const q;
DockerDeviceData m_data;
DockerSettings *m_settings;
@@ -315,14 +318,21 @@ IDeviceWidget *DockerDevice::createWidget()
Tasks DockerDevice::validate() const
{
+ return d->validateMounts();
+}
+
+Tasks DockerDevicePrivate::validateMounts() const
+{
Tasks result;
- if (d->data().mounts.isEmpty()) {
- result << Task(Task::Error,
- Tr::tr("The docker device has not set up shared directories."
- "This will not work for building."),
- {},
- -1,
- {});
+
+ for (const QString &mount : m_data.mounts) {
+ const FilePath path = FilePath::fromUserInput(mount);
+ if (!path.isDir()) {
+ const QString message = Tr::tr("Path \"%1\" is not a directory or does not exist.")
+ .arg(mount);
+
+ result.append(Task(Task::Error, message, {}, -1, {}));
+ }
}
return result;
}
@@ -460,6 +470,60 @@ bool DockerDevicePrivate::prepareForBuild(const Target *target)
&& ensureReachable(target->activeBuildConfiguration()->buildDirectory());
}
+QString escapeMountPathUnix(const FilePath &fp)
+{
+ return fp.nativePath().replace('\"', "\"\"");
+}
+
+QString escapeMountPathWin(const FilePath &fp)
+{
+ QString result = fp.nativePath().replace('\"', "\"\"").replace('\\', '/');
+ if (result.size() >= 2 && result[1] == ':')
+ result = "/" + result[0] + "/" + result.mid(3);
+ return result;
+}
+
+QStringList toMountArg(const DockerDevicePrivate::TemporaryMountInfo &mi)
+{
+ QString escapedPath;
+ QString escapedContainerPath;
+
+ if (HostOsInfo::isWindowsHost()) {
+ escapedPath = escapeMountPathWin(mi.path);
+ escapedContainerPath = escapeMountPathWin(mi.containerPath);
+ } else {
+ escapedPath = escapeMountPathUnix(mi.path);
+ escapedContainerPath = escapeMountPathUnix(mi.containerPath);
+ }
+
+ const QString mountArg = QString(R"(type=bind,"source=%1","destination=%2")")
+ .arg(escapedPath)
+ .arg(escapedContainerPath);
+
+ return QStringList{"--mount", mountArg};
+}
+
+bool isValidMountInfo(const DockerDevicePrivate::TemporaryMountInfo &mi)
+{
+ return !mi.path.isEmpty() && !mi.containerPath.isEmpty() && mi.path.isAbsolutePath()
+ && mi.containerPath.isAbsolutePath();
+}
+
+QStringList DockerDevicePrivate::createMountArgs() const
+{
+ QStringList cmds;
+ QList<TemporaryMountInfo> mounts = m_temporaryMounts;
+ for (const QString &m : m_data.mounts)
+ mounts.append({FilePath::fromUserInput(m), FilePath::fromUserInput(m)});
+
+ for (const TemporaryMountInfo &mi : mounts) {
+ if (isValidMountInfo(mi))
+ cmds += toMountArg(mi);
+ }
+
+ return cmds;
+}
+
bool DockerDevicePrivate::createContainer()
{
if (!m_settings)
@@ -483,28 +547,18 @@ bool DockerDevicePrivate::createContainer()
if (m_data.useLocalUidGid)
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
#endif
-
- for (QString mount : std::as_const(m_data.mounts)) {
- if (mount.isEmpty())
- continue;
- mount = q->mapToDevicePath(FilePath::fromUserInput(mount));
- dockerCreate.addArgs({"-v", mount + ':' + mount});
- }
FilePath dumperPath = FilePath::fromString("/tmp/qtcreator/debugger");
addTemporaryMount(Core::ICore::resourcePath("debugger/"), dumperPath);
q->setDebugDumperPath(dumperPath);
- for (const auto &[path, containerPath] : std::as_const(m_temporaryMounts)) {
- if (path.isEmpty())
- continue;
- dockerCreate.addArgs({"-v", path.nativePath() + ':' + containerPath.nativePath()});
- }
+ dockerCreate.addArgs(createMountArgs());
+
if (!m_data.keepEntryPoint)
dockerCreate.addArgs({"--entrypoint", "/bin/sh"});
dockerCreate.addArg(m_data.repoAndTag());
- qCDebug(dockerDeviceLog) << "RUNNING: " << dockerCreate.toUserOutput();
+ qCDebug(dockerDeviceLog).noquote() << "RUNNING: " << dockerCreate.toUserOutput();
QtcProcess createProcess;
createProcess.setCommand(dockerCreate);
createProcess.runBlocking();