Source code for ralph.git.subprocess_runner

"""Synchronous git helper backed by ProcessManager."""

from __future__ import annotations

import subprocess
from dataclasses import dataclass
from typing import TYPE_CHECKING

from ralph.git.git_run_result import GitRunResult
from ralph.process.manager import SpawnOptions, get_process_manager

if TYPE_CHECKING:
    from collections.abc import Mapping, Sequence
    from pathlib import Path


[docs] @dataclass(frozen=True) class GitRunOptions: """Options for run_git beyond the required args, cwd, and label.""" phase: str | None = None timeout: float | None = None env: Mapping[str, str] | None = None check: bool = False capture_output: bool = True text: bool = True
[docs] def run_git( args: Sequence[str], *, cwd: Path | None, label: str, options: GitRunOptions | None = None, ) -> GitRunResult: """Spawn a git subprocess through ProcessManager and return the result. When ``options.phase`` is provided the process label becomes ``phase:<phase>:git:<label>`` so process_phase_scope can terminate it. Raises subprocess.TimeoutExpired if timeout is exceeded. Raises subprocess.CalledProcessError if options.check is True and returncode != 0. """ effective_options = options or GitRunOptions() phase = effective_options.phase effective_label = f"phase:{phase}:git:{label}" if phase is not None else label cmd = ("git", *args) proc = get_process_manager().spawn( cmd, SpawnOptions( cwd=str(cwd) if cwd else None, env=dict(effective_options.env) if effective_options.env is not None else None, stdout=subprocess.PIPE if effective_options.capture_output else None, stderr=subprocess.PIPE if effective_options.capture_output else None, label=effective_label, text=effective_options.text, ), ) try: raw_stdout, raw_stderr = proc.communicate(timeout=effective_options.timeout) except subprocess.TimeoutExpired: raise def _str(v: bytes | str | None) -> str: if v is None: return "" return v.decode() if isinstance(v, bytes) else v stdout = _str(raw_stdout) stderr = _str(raw_stderr) returncode = proc.returncode if proc.returncode is not None else 0 if effective_options.check and returncode != 0: raise subprocess.CalledProcessError(returncode, list(cmd), stdout, stderr) return GitRunResult(args=cmd, returncode=returncode, stdout=stdout, stderr=stderr)
__all__ = ["GitRunOptions", "run_git"]