X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=exec_utils.py;h=df273352bb793d59f19717c9cb6806134dd5a628;hb=31c81f6539969a5eba864d3305f9fb7bf716a367;hp=016310793152ddeb8872f5ec279c26ae1994655e;hpb=36fea7f15ed17150691b5b3ead75450e575229ef;p=python_utils.git diff --git a/exec_utils.py b/exec_utils.py index 0163107..df27335 100644 --- a/exec_utils.py +++ b/exec_utils.py @@ -2,13 +2,13 @@ import atexit import logging +import os import selectors import shlex import subprocess import sys from typing import List, Optional - logger = logging.getLogger(__file__) @@ -21,36 +21,40 @@ def cmd_showing_output( """ line_enders = set([b'\n', b'\r']) - p = subprocess.Popen( + sel = selectors.DefaultSelector() + with subprocess.Popen( command, shell=True, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False, - ) - sel = selectors.DefaultSelector() - sel.register(p.stdout, selectors.EVENT_READ) - sel.register(p.stderr, selectors.EVENT_READ) - stream_ends = 0 - while stream_ends < 2: - for key, _ in sel.select(): - char = key.fileobj.read(1) - if not char: - stream_ends += 1 - continue - if key.fileobj is p.stdout: - sys.stdout.buffer.write(char) - if char in line_enders: - sys.stdout.flush() - else: - sys.stderr.buffer.write(char) - if char in line_enders: - sys.stderr.flush() - p.wait() - sys.stdout.flush() - sys.stderr.flush() - return p.returncode + ) as p: + sel.register(p.stdout, selectors.EVENT_READ) # type: ignore + sel.register(p.stderr, selectors.EVENT_READ) # type: ignore + done = False + while not done: + for key, _ in sel.select(): + char = key.fileobj.read(1) # type: ignore + if not char: + sel.unregister(key.fileobj) + if len(sel.get_map()) == 0: + sys.stdout.flush() + sys.stderr.flush() + sel.close() + done = True + if key.fileobj is p.stdout: + # sys.stdout.buffer.write(char) + os.write(sys.stdout.fileno(), char) + if char in line_enders: + sys.stdout.flush() + else: + # sys.stderr.buffer.write(char) + os.write(sys.stderr.fileno(), char) + if char in line_enders: + sys.stderr.flush() + p.wait() + return p.returncode def cmd_with_timeout(command: str, timeout_seconds: Optional[float]) -> int: @@ -68,9 +72,7 @@ def cmd_with_timeout(command: str, timeout_seconds: Optional[float]) -> int: subprocess.TimeoutExpired: Command '['/bin/bash', '-c', '/bin/sleep 2']' timed out after 0.1 seconds """ - return subprocess.check_call( - ["/bin/bash", "-c", command], timeout=timeout_seconds - ) + return subprocess.check_call(["/bin/bash", "-c", command], timeout=timeout_seconds) def cmd(command: str, timeout_seconds: Optional[float] = None) -> str: @@ -120,9 +122,7 @@ def run_silently(command: str, timeout_seconds: Optional[float] = None) -> None: ) -def cmd_in_background( - command: str, *, silent: bool = False -) -> subprocess.Popen: +def cmd_in_background(command: str, *, silent: bool = False) -> subprocess.Popen: args = shlex.split(command) if silent: subproc = subprocess.Popen( @@ -137,9 +137,7 @@ def cmd_in_background( def kill_subproc() -> None: try: if subproc.poll() is None: - logger.info( - "At exit handler: killing {}: {}".format(subproc, command) - ) + logger.info(f'At exit handler: killing {subproc} ({command})') subproc.terminate() subproc.wait(timeout=10.0) except BaseException as be: