From 406eea4c7dfa457d608bed7cf0d4758f16c530ba Mon Sep 17 00:00:00 2001 From: www84 <49484956+www84@users.noreply.github.com> Date: Wed, 25 Dec 2024 17:42:51 +0100 Subject: [PATCH] Add volumes option to docker.compose.run() (#663) --- .../components/compose/cli_wrapper.py | 10 ++++- .../components/test_compose.py | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/python_on_whales/components/compose/cli_wrapper.py b/python_on_whales/components/compose/cli_wrapper.py index 82bac33f..857395ff 100644 --- a/python_on_whales/components/compose/cli_wrapper.py +++ b/python_on_whales/components/compose/cli_wrapper.py @@ -8,6 +8,7 @@ from typing_extensions import Literal import python_on_whales.components.container.cli_wrapper +import python_on_whales.components.volume.cli_wrapper from python_on_whales.client_config import DockerCLICaller from python_on_whales.components.compose.models import ComposeConfig, ComposeProject from python_on_whales.utils import ( @@ -677,7 +678,9 @@ def run( service_ports: bool = False, use_aliases: bool = False, user: Optional[str] = None, - # volumes: bool = "todo", + volumes: Iterable[ + python_on_whales.components.volume.cli_wrapper.VolumeDefinition + ] = (), workdir: Union[None, str, Path] = None, ) -> Union[ str, @@ -703,6 +706,8 @@ def run( to write on it. stream: Similar to `docker.run(..., stream=True)`. user: Username or UID, format: `"[:]"` + volumes: Bind mount a volume. Some examples: + `[("/", "/host"), ("/etc/hosts", "/etc/hosts", "rw")]`. workdir: Working directory inside the container Returns: @@ -746,6 +751,9 @@ def run( full_cmd.add_flag("--service-ports", service_ports) full_cmd.add_flag("--use-aliases", use_aliases) full_cmd.add_simple_arg("--user", user) + for volume_definition in volumes: + volume_definition = tuple(str(x) for x in volume_definition) + full_cmd += ["--volume", ":".join(volume_definition)] full_cmd.add_simple_arg("--workdir", workdir) full_cmd.add_args_iterable_or_single("--label", format_mapping_for_cli(labels)) full_cmd.append(service) diff --git a/tests/python_on_whales/components/test_compose.py b/tests/python_on_whales/components/test_compose.py index c1029f0c..cf2cb485 100644 --- a/tests/python_on_whales/components/test_compose.py +++ b/tests/python_on_whales/components/test_compose.py @@ -765,6 +765,45 @@ def test_compose_run_entrypoint(): assert result == "cmd-is-argument-for-echo" +def test_compose_run_volume(): + with tempfile.NamedTemporaryFile() as fst, tempfile.NamedTemporaryFile() as snd: + fst.write(b"Hello ") + snd.write(b" Year") + fst.flush() + snd.flush() + + result = docker.compose.run( + "dodo", + [ + "-c", + "echo New >> /mounted/fst.txt" + "&& echo $(cat /mounted/fst.txt)$(cat /mounted/snd.txt)", + ], + volumes=[ + (f"{fst.name}", "/mounted/fst.txt"), + (f"{snd.name}", "/mounted/snd.txt", "ro"), + ], + remove=True, + tty=False, + ) + + assert result == "Hello New Year" + + +def test_compose_run_volume_with_parameter(): + with tempfile.NamedTemporaryFile() as read_only_file, pytest.raises( + DockerException, + match=".*can't create /mounted/read_only_file.txt: Read-only file system.*", + ): + docker.compose.run( + "dodo", + ["-c", "echo test > /mounted/read_only_file.txt"], + volumes=[(f"{read_only_file.name}", "/mounted/read_only_file.txt", "ro")], + remove=True, + tty=False, + ) + + def test_compose_version(): assert "Docker Compose version v2" in docker.compose.version()