diff --git a/README.md b/README.md index f78dba2..0fd2f02 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,11 @@ NOTE: service-name is an optional parameter. If not provided, devservices will a - `devservices list-dependencies `: List all dependencies for a service and whether they are enabled/disabled. - `devservices update` Update devservices to the latest version. - `devservices purge`: Purge the local devservices cache. + +## Debug Mode + +To enable debug mode, set the `DEBUG` environment variable to `true`: + +``` +export DEBUG=true +``` diff --git a/devservices/constants.py b/devservices/constants.py index 027147e..d8cbdc8 100644 --- a/devservices/constants.py +++ b/devservices/constants.py @@ -19,6 +19,7 @@ "extensions.partialClone": "true", "core.sparseCheckout": "true", } +DEBUG = os.getenv("DEBUG", "false").lower() == "true" DOCKER_COMPOSE_DOWNLOAD_URL = "https://github.com/docker/compose/releases/download" DEVSERVICES_DOWNLOAD_URL = "https://github.com/getsentry/devservices/releases/download" diff --git a/devservices/utils/dependencies.py b/devservices/utils/dependencies.py index 5d9cf8e..80c2e8a 100644 --- a/devservices/utils/dependencies.py +++ b/devservices/utils/dependencies.py @@ -14,6 +14,7 @@ from devservices.configs.service_config import load_service_config_from_file from devservices.configs.service_config import RemoteConfig from devservices.constants import CONFIG_FILE_NAME +from devservices.constants import DEBUG from devservices.constants import DEPENDENCY_CONFIG_VERSION from devservices.constants import DEPENDENCY_GIT_PARTIAL_CLONE_CONFIG_OPTIONS from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR @@ -436,4 +437,9 @@ def _has_remote_config(remote_config: RemoteConfig | None) -> TypeGuard[RemoteCo def _run_command( cmd: list[str], cwd: str, stdout: int | TextIO | None = subprocess.DEVNULL ) -> None: - subprocess.run(cmd, cwd=cwd, check=True, stdout=stdout, stderr=subprocess.DEVNULL) + if DEBUG: + subprocess.run(cmd, cwd=cwd, check=True) + else: + subprocess.run( + cmd, cwd=cwd, check=True, stdout=stdout, stderr=subprocess.DEVNULL + ) diff --git a/devservices/utils/docker_compose.py b/devservices/utils/docker_compose.py index 6943202..ec23580 100644 --- a/devservices/utils/docker_compose.py +++ b/devservices/utils/docker_compose.py @@ -4,6 +4,7 @@ import platform import re import subprocess +import sys from collections.abc import Callable from typing import cast @@ -11,6 +12,7 @@ from devservices.configs.service_config import load_service_config_from_file from devservices.constants import CONFIG_FILE_NAME +from devservices.constants import DEBUG from devservices.constants import DEPENDENCY_CONFIG_VERSION from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY @@ -269,11 +271,62 @@ def run_docker_compose_command( cmd_outputs = [] for cmd in docker_compose_commands: try: - cmd_outputs.append( - subprocess.run( - cmd, check=True, capture_output=True, text=True, env=current_env + if DEBUG: + # Use Popen for real-time output streaming when debug is True + process = subprocess.Popen( + cmd, + env=current_env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1, + universal_newlines=True, + ) + + stdout_data = [] + stderr_data = [] + + # Read stdout and stderr in real-time + while True: + stdout_line = process.stdout.readline() if process.stdout else "" + stderr_line = process.stderr.readline() if process.stderr else "" + + if stdout_line: + print(stdout_line.rstrip()) + stdout_data.append(stdout_line) + if stderr_line: + print(stderr_line.rstrip(), file=sys.stderr) + stderr_data.append(stderr_line) + + if ( + not stdout_line + and not stderr_line + and process.poll() is not None + ): + break + + if process.returncode != 0: + raise subprocess.CalledProcessError( + process.returncode, + cmd, + "".join(stdout_data), + "".join(stderr_data), + ) + + cmd_outputs.append( + subprocess.CompletedProcess( + args=cmd, + returncode=process.returncode, + stdout="".join(stdout_data), + stderr="".join(stderr_data), + ) + ) + else: + cmd_outputs.append( + subprocess.run( + cmd, check=True, capture_output=True, text=True, env=current_env + ) ) - ) except subprocess.CalledProcessError as e: raise DockerComposeError( command=command,