Files
project-manager/project_manager/command.py
T

69 lines
1.6 KiB
Python

__all__ = (
"CommandError",
"CommandLogger",
"CommandExecutor",
)
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.fdRead, self.fdWrite = os.pipe()
self.pipeReader = os.fdopen(self.fdRead)
self.lines = []
self.start()
def fileno(self):
return self.fdWrite
def run(self):
for line in iter(self.pipeReader.readline, ""):
logger.log(self.level, line.strip("\n"))
self.lines.append(line)
self.pipeReader.close()
def close(self):
os.close(self.fdWrite)
class CommandExecutor:
_logger = logger
def __init__(self, command: str) -> None:
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.split(" "),
cwd=basepath,
stdout=out_logger,
stderr=err_logger,
)
finally:
out_logger.close()
err_logger.close()
if result.returncode != 0:
raise CommandError("".join(err_logger.lines or out_logger.lines))