70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from subprocess import Popen, call, check_output, PIPE
|
|
|
|
from misc import assert_type
|
|
|
|
|
|
class CommandInterface:
|
|
_BINARY: Path
|
|
|
|
@classmethod
|
|
def _run_command(cls, *args: str) -> None:
|
|
CommandRunner.run([str(cls._BINARY), *args])
|
|
|
|
@classmethod
|
|
def _get_output(cls, *args: str) -> str:
|
|
return CommandRunner.get_output([str(cls._BINARY), *args])
|
|
|
|
@classmethod
|
|
def _open_stream(cls, *args: str) -> Popen:
|
|
return CommandRunner.send_stream([str(cls._BINARY), *args])
|
|
|
|
@classmethod
|
|
def _receive_stream(cls, *args: str, stream: Popen) -> None:
|
|
CommandRunner.receive_from_stream([str(cls._BINARY), *args], stream=stream)
|
|
|
|
|
|
class CommandRunner:
|
|
@staticmethod
|
|
def _sanity_check(cmdline: list[str]) -> None:
|
|
assert_type(cmdline, list, "Command line must be a list")
|
|
for item in cmdline:
|
|
assert_type(item, str, "Only strings allowed in command line")
|
|
|
|
@staticmethod
|
|
def _to_list(command: str | list[str]) -> list[str]:
|
|
"""If the command is a str, return it as list. Otherwise, return the command."""
|
|
if isinstance(command, str):
|
|
return [command]
|
|
return command
|
|
|
|
@classmethod
|
|
def run(cls, cmdline: str | list[str]) -> None:
|
|
"""Run the command, wait for it to return."""
|
|
cmdline = cls._to_list(cmdline)
|
|
cls._sanity_check(cmdline)
|
|
call(cmdline)
|
|
|
|
@classmethod
|
|
def get_output(cls, cmdline: str | list[str]) -> str:
|
|
"""Run the command, return the output of the command."""
|
|
cmdline = cls._to_list(cmdline)
|
|
cls._sanity_check(cmdline)
|
|
return check_output(cmdline).strip().decode()
|
|
|
|
@classmethod
|
|
def receive_from_stream(cls, cmdline: str | list[str], stream: Popen) -> None:
|
|
"""Run the command, receive data from a pipe to stdin."""
|
|
cmdline = cls._to_list(cmdline)
|
|
cls._sanity_check(cmdline)
|
|
check_output(cmdline, stdin=stream.stdout)
|
|
|
|
@classmethod
|
|
def send_stream(cls, cmdline: str | list[str]) -> Popen:
|
|
"""Run the command, redirect stdout to a pipe."""
|
|
cmdline = cls._to_list(cmdline)
|
|
cls._sanity_check(cmdline)
|
|
return Popen(cmdline, stdout=PIPE)
|