91e75e620b
CI: cua-driver distro-compat matrix / Resolve release version (push) Waiting to run
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / Distro compat summary (push) Blocked by required conditions
CI: Nix Linux Rust source / Nix / compositor build (push) Waiting to run
CI: Nix Linux Rust source / Nix / driver package (push) Waiting to run
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Waiting to run
CI: Rust Linux unit / Rust Linux unit and compile (push) Waiting to run
CI: Rust Windows unit / Rust Windows unit and compile (push) Waiting to run
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Waiting to run
CD: Docs MCP Server / build (linux/amd64) (push) Waiting to run
CD: Docs MCP Server / build (linux/arm64) (push) Waiting to run
CD: Docs MCP Server / merge (push) Blocked by required conditions
54 lines
1.4 KiB
Python
54 lines
1.4 KiB
Python
"""Shell command execution."""
|
|
|
|
import subprocess
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass
|
|
class CommandResult:
|
|
stdout: str
|
|
stderr: str
|
|
returncode: int
|
|
|
|
@property
|
|
def success(self) -> bool:
|
|
return self.returncode == 0
|
|
|
|
|
|
def run(command: str, timeout: int = 30) -> CommandResult:
|
|
"""Run a shell command and return stdout, stderr, and returncode.
|
|
|
|
The command is passed to the system shell (``shell=True``) so that
|
|
shell built-ins, pipes, and redirections work as expected.
|
|
"""
|
|
|
|
def _decode(data: bytes) -> str:
|
|
if not data:
|
|
return ""
|
|
for enc in ("utf-8", "gbk", "gb2312", "cp936", "latin1"):
|
|
try:
|
|
return data.decode(enc)
|
|
except (UnicodeDecodeError, LookupError):
|
|
continue
|
|
return data.decode("utf-8", errors="replace")
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
command,
|
|
shell=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
timeout=timeout,
|
|
)
|
|
return CommandResult(
|
|
stdout=_decode(result.stdout),
|
|
stderr=_decode(result.stderr),
|
|
returncode=result.returncode,
|
|
)
|
|
except subprocess.TimeoutExpired as e:
|
|
return CommandResult(
|
|
stdout=_decode(e.stdout or b""),
|
|
stderr=_decode(e.stderr or b""),
|
|
returncode=-1,
|
|
)
|