Skip to content

Commit

Permalink
✨ Allow the streaming of the docker.compose.build logs (#494)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrieldemarmiesse committed Nov 11, 2023
1 parent 9d1f144 commit 0a14f90
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
50 changes: 47 additions & 3 deletions python_on_whales/components/compose/cli_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json
from datetime import timedelta
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union, overload

from typing_extensions import Literal

Expand All @@ -21,6 +21,34 @@


class ComposeCLI(DockerCLICaller):
@overload
def build(
self,
services: Optional[List[str]] = ...,
build_args: Dict[str, str] = ...,
cache: bool = ...,
progress: Optional[str] = ...,
pull: bool = ...,
quiet: bool = ...,
ssh: Optional[str] = ...,
stream_logs: Literal[True] = ...,
) -> Iterable[Tuple[str, bytes]]:
...

@overload
def build(
self,
services: Optional[List[str]] = ...,
build_args: Dict[str, str] = ...,
cache: bool = ...,
progress: Optional[str] = ...,
pull: bool = ...,
quiet: bool = ...,
ssh: Optional[str] = ...,
stream_logs: Literal[False] = ...,
) -> None:
...

def build(
self,
services: Optional[List[str]] = None,
Expand All @@ -30,7 +58,8 @@ def build(
pull: bool = False,
quiet: bool = False,
ssh: Optional[str] = None,
):
stream_logs: bool = False,
) -> Union[Iterable[Tuple[str, bytes]], None]:
"""Build services declared in a yaml compose file.
Parameters:
Expand All @@ -46,7 +75,19 @@ def build(
quiet: Don't print anything
ssh: Set SSH authentications used when building service images.
(use `'default'` for using your default SSH Agent)
stream_logs: If `False` this function returns None. If `True`, this
function returns an Iterable of `Tuple[str, bytes]` where the first element
is the type of log (`"stdin"` or `"stdout"`). The second element is the log itself,
as bytes, you'll need to call `.decode()` if you want the logs as `str`.
See [the streaming guide](https://gabrieldemarmiesse.github.io/python-on-whales/user_guide/docker_run/#stream-the-output) if you are
not familiar with the streaming of logs in Python-on-whales.
"""
if quiet and stream_logs:
raise ValueError(
"It's not possible to have stream_logs=True and quiet=True at the same time. "
"Only one can be activated at a time."
)

full_cmd = self.docker_compose_cmd + ["build"]
full_cmd.add_args_list("--build-arg", format_dict_for_cli(build_args))
full_cmd.add_flag("--no-cache", not cache)
Expand All @@ -59,7 +100,10 @@ def build(
return
elif services is not None:
full_cmd += services
run(full_cmd, capture_stdout=False)
if stream_logs:
return stream_stdout_and_stderr(full_cmd)
else:
run(full_cmd, capture_stdout=False)

def config(self, return_json: bool = False) -> Union[ComposeConfig, Dict[str, Any]]:
"""Returns the configuration of the compose stack for further inspection.
Expand Down
14 changes: 14 additions & 0 deletions tests/python_on_whales/components/test_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,20 @@ def test_docker_compose_build():
docker.image.remove("some_random_image")


def test_docker_compose_build_stream():
logs = list(docker.compose.build(["my_service"], stream_logs=True))
assert len(logs) >= 3
logs_as_big_binary = b""
for log_type, log_value in logs:
assert log_type in ("stdout", "stderr")
logs_as_big_binary += log_value

assert b"load .dockerignore" in logs_as_big_binary
assert b"DONE" in logs_as_big_binary

docker.image.remove("some_random_image")


def test_docker_compose_build_with_arguments():
docker.compose.build(
build_args={"PYTHON_VERSION": "3.7"},
Expand Down

0 comments on commit 0a14f90

Please sign in to comment.