From 42a2d062cf6fe6fb533ef472d90cf49de218f00f Mon Sep 17 00:00:00 2001 From: Lennart Reiher Date: Tue, 2 Apr 2024 22:04:09 +0200 Subject: [PATCH 1/5] only add gpu flags if gpu is found fixes #17 --- docker-run-cli/pyproject.toml | 2 +- docker-run-cli/src/docker_run/plugins/core.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docker-run-cli/pyproject.toml b/docker-run-cli/pyproject.toml index d1db6b1..b1fafc2 100644 --- a/docker-run-cli/pyproject.toml +++ b/docker-run-cli/pyproject.toml @@ -23,7 +23,7 @@ classifiers = [ "Operating System :: POSIX :: Linux", ] keywords = ["docker", "container"] -dependencies = [] +dependencies = ["GPUtil~=1.4.0"] requires-python = ">=3.7" [project.optional-dependencies] diff --git a/docker-run-cli/src/docker_run/plugins/core.py b/docker-run-cli/src/docker_run/plugins/core.py index 38957b2..1dccfc6 100644 --- a/docker-run-cli/src/docker_run/plugins/core.py +++ b/docker-run-cli/src/docker_run/plugins/core.py @@ -4,6 +4,8 @@ import tempfile from typing import Any, Dict, List +import GPUtil + from docker_run.utils import log, runCommand from docker_run.plugins.plugin import Plugin @@ -78,12 +80,16 @@ def localeFlags(cls) -> List[str]: @classmethod def gpuSupportFlags(cls) -> List[str]: - if cls.ARCH == "x86_64": - return ["--gpus all"] - elif cls.ARCH == "aarch64" and cls.OS == "Linux": - return ["--runtime nvidia"] + if len(GPUtil.getGPUs()) > 0: + if cls.ARCH == "x86_64": + return ["--gpus all"] + elif cls.ARCH == "aarch64" and cls.OS == "Linux": + return ["--runtime nvidia"] + else: + log(f"GPU not supported by `docker-run` on {cls.OS} with {cls.ARCH} architecture") + return [] else: - log(f"GPU not supported by `docker-run` on {cls.OS} with {cls.ARCH} architecture") + log(f"No GPU detected") return [] @classmethod @@ -92,7 +98,7 @@ def x11GuiForwardingFlags(cls, docker_network: str = "bridge") -> List[str]: display = os.environ.get("DISPLAY") if display is None: return [] - + if cls.OS == "Darwin": runCommand(f"xhost +local:") From 74e0805bb985950813666f2d5b55453929926d14 Mon Sep 17 00:00:00 2001 From: Lennart Reiher Date: Wed, 3 Apr 2024 11:20:14 +0200 Subject: [PATCH 2/5] allow relative bind mounts closes #19 --- README.md | 3 ++- docker-run-cli/src/docker_run/core.py | 4 ++++ docker-run-cli/src/docker_run/plugins/core.py | 16 ++++++++++++++++ docker-run-cli/src/docker_run/plugins/plugin.py | 4 ++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 820861d..ed9d5dc 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,11 @@ In general, you can pass the same arguments to `docker-run` as you would pass to docker-run --volume $(pwd):/volume ubuntu ls /volume ``` -In addition to the arguments you are passing, `docker-run` however also enables the following features by default. Each of these default features can be disabled, see [Usage](#usage). +In addition to the arguments you are passing, `docker-run` however also enables the following features by default. Most of these default features can be disabled, see [Usage](#usage). - container removal after exit (`--rm`) - interactive tty (`--interactive --tty`) - current directory name as container name (`--name`) +- relative bind mounts (`--volume [./RELATIVE_PATH>]:[TARGET_PATH]`) - GPU support (`--gpus all` / `--runtime nvidia`) - X11 GUI forwarding diff --git a/docker-run-cli/src/docker_run/core.py b/docker-run-cli/src/docker_run/core.py index 6b51630..ced9acf 100644 --- a/docker-run-cli/src/docker_run/core.py +++ b/docker-run-cli/src/docker_run/core.py @@ -146,6 +146,10 @@ def buildDockerCommand(args: Dict[str, Any], unknown_args: List[str] = [], cmd_a else: docker_cmd += ["bash"] # default exec command + # plugin modifications + for plugin in PLUGINS: + docker_cmd = plugin.modifyFinalCommand(docker_cmd, args, unknown_args) + return " ".join(docker_cmd) diff --git a/docker-run-cli/src/docker_run/plugins/core.py b/docker-run-cli/src/docker_run/plugins/core.py index 1dccfc6..cf6efd1 100644 --- a/docker-run-cli/src/docker_run/plugins/core.py +++ b/docker-run-cli/src/docker_run/plugins/core.py @@ -57,6 +57,12 @@ def getExecFlags(cls, args: Dict[str, Any], unknown_args: List[str]) -> List[str flags += cls.interactiveFlags() return flags + @classmethod + def modifyFinalCommand(cls, cmd: List[str], args: Dict[str, Any], unknown_args: List[str]) -> List[str]: + if "-v" in cmd or "--volume" in cmd: + cmd = cls.resolveRelativeVolumeFlags(cmd) + return cmd + @classmethod def removeFlags(cls) -> List[str]: return ["--rm"] @@ -126,3 +132,13 @@ def x11GuiForwardingFlags(cls, docker_network: str = "bridge") -> List[str]: @classmethod def currentDirMountFlags(cls) -> List[str]: return [f"--volume {os.getcwd()}:{os.getcwd()}", f"--workdir {os.getcwd()}"] + + @classmethod + def resolveRelativeVolumeFlags(cls, cmd: List[str]) -> List[str]: + for i, arg in enumerate(cmd): + if arg in ["-v", "--volume"]: + mount_path = cmd[i + 1].split(":")[0] + if mount_path.startswith("."): + absolute_mount_path = os.path.abspath(mount_path) + cmd[i + 1] = absolute_mount_path + cmd[i + 1][len(mount_path):] + return cmd diff --git a/docker-run-cli/src/docker_run/plugins/plugin.py b/docker-run-cli/src/docker_run/plugins/plugin.py index 38c6c37..44430ea 100644 --- a/docker-run-cli/src/docker_run/plugins/plugin.py +++ b/docker-run-cli/src/docker_run/plugins/plugin.py @@ -18,3 +18,7 @@ def getRunFlags(cls, args: Dict[str, Any], unknown_args: List[str]) -> List[str] @abstractmethod def getExecFlags(cls, args: Dict[str, Any], unknown_args: List[str]) -> List[str]: raise NotImplementedError() + + @classmethod + def modifyFinalCommand(cls, cmd: List[str], args: Dict[str, Any], unknown_args: List[str]) -> List[str]: + return cmd From ac74928015f7dfefe1622d9c27a0d624ed452d97 Mon Sep 17 00:00:00 2001 From: Lennart Reiher Date: Thu, 4 Apr 2024 09:55:05 +0200 Subject: [PATCH 3/5] handle spaces in --mws or --mwd paths fixes github issue #8 --- docker-run-cli/scripts/docker-run | 15 ++++++++++++++- docker-run-cli/src/docker_run/plugins/core.py | 3 ++- .../src/docker_run/plugins/docker_ros.py | 3 ++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docker-run-cli/scripts/docker-run b/docker-run-cli/scripts/docker-run index ca238de..ccb0b9a 100755 --- a/docker-run-cli/scripts/docker-run +++ b/docker-run-cli/scripts/docker-run @@ -26,8 +26,21 @@ python3 -m docker_run "${@}" 2>&1 >$CMD_FILE CMD=$(cat $CMD_FILE) rm $CMD_FILE +# convert command string to array to allow for escaped characters, e.g. "docker run -v /path\ with\ spaces:/path\ with\ spaces ..." +CMD_ARRAY=() + while IFS= read -r -d ' ' part; do + while [[ $part == *"\\" ]]; do + part+=" " + part="${part//\\/}" + IFS= read -r -d ' ' next_part + part+=$next_part + done + CMD_ARRAY+=("$part") + done <<< "$CMD" + CMD_ARRAY+=("${part%$'\n'}") + # execute command if [[ ! -z "$CMD" ]]; then echo -e "================================================================================\n" - exec $CMD + exec "${CMD_ARRAY[@]}" fi diff --git a/docker-run-cli/src/docker_run/plugins/core.py b/docker-run-cli/src/docker_run/plugins/core.py index cf6efd1..c395172 100644 --- a/docker-run-cli/src/docker_run/plugins/core.py +++ b/docker-run-cli/src/docker_run/plugins/core.py @@ -131,7 +131,8 @@ def x11GuiForwardingFlags(cls, docker_network: str = "bridge") -> List[str]: @classmethod def currentDirMountFlags(cls) -> List[str]: - return [f"--volume {os.getcwd()}:{os.getcwd()}", f"--workdir {os.getcwd()}"] + cwd = os.getcwd().replace(" ", "\\ ") + return [f"--volume {cwd}:{cwd}", f"--workdir {cwd}"] @classmethod def resolveRelativeVolumeFlags(cls, cmd: List[str]) -> List[str]: diff --git a/docker-run-docker-ros/src/docker_run/plugins/docker_ros.py b/docker-run-docker-ros/src/docker_run/plugins/docker_ros.py index 0b4e28d..484d2bf 100644 --- a/docker-run-docker-ros/src/docker_run/plugins/docker_ros.py +++ b/docker-run-docker-ros/src/docker_run/plugins/docker_ros.py @@ -52,4 +52,5 @@ def userExecFlags(cls, user: str) -> List[str]: @classmethod def currentDirMountWorkspaceFlags(cls) -> List[str]: - return [f"--volume {os.getcwd()}:{cls.TARGET_MOUNT}", f"--workdir {cls.WORKSPACE}"] + cwd = os.getcwd().replace(" ", "\\ ") + return [f"--volume {cwd}:{cls.TARGET_MOUNT}", f"--workdir {cls.WORKSPACE}"] From 3564c645f8576459eaeed5398440d887eb9a8031 Mon Sep 17 00:00:00 2001 From: Lennart Reiher Date: Thu, 4 Apr 2024 09:57:21 +0200 Subject: [PATCH 4/5] bump to v0.9.7 and v1.0.5 --- docker-run-cli/pyproject.toml | 8 ++++---- docker-run-cli/src/docker_run/__init__.py | 2 +- docker-run-docker-ros/pyproject.toml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docker-run-cli/pyproject.toml b/docker-run-cli/pyproject.toml index b1fafc2..73c79d4 100644 --- a/docker-run-cli/pyproject.toml +++ b/docker-run-cli/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "docker-run-cli" -version = "0.9.6" +version = "0.9.7" description = "'docker run' and 'docker exec' with useful defaults" license = {file = "LICENSE"} readme = "README.md" @@ -28,9 +28,9 @@ requires-python = ">=3.7" [project.optional-dependencies] dev = ["build", "twine"] -docker-ros = ["docker-run-docker-ros>=1.0.4"] -plugins = ["docker-run-docker-ros>=1.0.4"] -all = ["docker-run-docker-ros>=1.0.4", "build", "twine"] +docker-ros = ["docker-run-docker-ros>=1.0.5"] +plugins = ["docker-run-docker-ros>=1.0.5"] +all = ["docker-run-docker-ros>=1.0.5", "build", "twine"] [project.urls] "Repository" = "https://github.com/ika-rwth-aachen/docker-run" diff --git a/docker-run-cli/src/docker_run/__init__.py b/docker-run-cli/src/docker_run/__init__.py index 8c336c3..ed32f3f 100644 --- a/docker-run-cli/src/docker_run/__init__.py +++ b/docker-run-cli/src/docker_run/__init__.py @@ -1,2 +1,2 @@ __name__ = "docker-run" -__version__ = "0.9.6" \ No newline at end of file +__version__ = "0.9.7" \ No newline at end of file diff --git a/docker-run-docker-ros/pyproject.toml b/docker-run-docker-ros/pyproject.toml index 48d58a4..a9e8ac4 100644 --- a/docker-run-docker-ros/pyproject.toml +++ b/docker-run-docker-ros/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "docker-run-docker-ros" -version = "1.0.4" +version = "1.0.5" description = "docker-run plugin for Docker images built by docker-ros" license = {file = "LICENSE"} readme = "README.md" @@ -23,7 +23,7 @@ classifiers = [ "Operating System :: POSIX :: Linux", ] keywords = ["docker", "container", "ros"] -dependencies = ["docker-run-cli>=0.9.4"] +dependencies = ["docker-run-cli>=0.9.7"] requires-python = ">=3.7" [project.urls] From 3c98e689529203050947772148e94631538a71cd Mon Sep 17 00:00:00 2001 From: Jean-Pierre Busch Date: Tue, 9 Apr 2024 11:46:55 +0200 Subject: [PATCH 5/5] fix spaces in volume flags --- docker-run-cli/src/docker_run/plugins/core.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docker-run-cli/src/docker_run/plugins/core.py b/docker-run-cli/src/docker_run/plugins/core.py index c395172..dc8dd99 100644 --- a/docker-run-cli/src/docker_run/plugins/core.py +++ b/docker-run-cli/src/docker_run/plugins/core.py @@ -61,6 +61,7 @@ def getExecFlags(cls, args: Dict[str, Any], unknown_args: List[str]) -> List[str def modifyFinalCommand(cls, cmd: List[str], args: Dict[str, Any], unknown_args: List[str]) -> List[str]: if "-v" in cmd or "--volume" in cmd: cmd = cls.resolveRelativeVolumeFlags(cmd) + cmd = cls.fixSpacesInVolumeFlags(cmd) return cmd @classmethod @@ -143,3 +144,10 @@ def resolveRelativeVolumeFlags(cls, cmd: List[str]) -> List[str]: absolute_mount_path = os.path.abspath(mount_path) cmd[i + 1] = absolute_mount_path + cmd[i + 1][len(mount_path):] return cmd + + @classmethod + def fixSpacesInVolumeFlags(cls, cmd: List[str]) -> List[str]: + for i, arg in enumerate(cmd): + if arg in ["-v", "--volume"]: + cmd[i + 1] = cmd[i + 1].replace(" ", "\\ ") + return cmd \ No newline at end of file