Files
2026-09-14 22:53:35 +03:00

63 lines
1.5 KiB
Python

import logging
import os
import subprocess
import threading
from pathlib import Path
logger = logging.getLogger("command")
class CommandError(RuntimeError):
@property
def output(self):
return self.args[0]
class CommandLogger(threading.Thread):
def __init__(self, level: int):
super().__init__()
self.daemon = False
self.level = level
self._read_fd, self._write_fd = os.pipe()
self._reader_pipe = os.fdopen(self._read_fd)
self.lines = []
self.start()
def fileno(self):
return self._write_fd
def run(self):
for line in iter(self._reader_pipe.readline, ""):
logger.log(self.level, line.strip("\n"))
self.lines.append(line)
self._reader_pipe.close()
def close(self):
os.close(self._write_fd)
class CommandExecutor:
_logger = logger
def __init__(self, command: str):
self._command = command
def run(self, basepath: Path):
self._logger.debug(self._command)
out_logger = CommandLogger(logging.TRACE)
err_logger = CommandLogger(logging.TRACE)
try:
result = subprocess.run(
self._command,
cwd=basepath,
stdout=out_logger, # type: ignore
stderr=err_logger, # type: ignore
shell=True,
)
finally:
out_logger.close()
err_logger.close()
if result.returncode != 0:
raise CommandError("".join(err_logger.lines or out_logger.lines))