X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=exec_utils.py;h=ae406ef41e925ddbd9ba5483ca1312b5686449e3;hb=532df2c5b57c7517dfb3dddd8c1358fbadf8baf3;hp=282a325a461e289144b5a58b5a88ce4a90098c83;hpb=e6f32fdd9b373dfcd100c7accb41f57d83c2f0a1;p=python_utils.git diff --git a/exec_utils.py b/exec_utils.py index 282a325..ae406ef 100644 --- a/exec_utils.py +++ b/exec_utils.py @@ -1,14 +1,18 @@ #!/usr/bin/env python3 +# © Copyright 2021-2022, Scott Gasch + +"""Helper methods concerned with executing subprocesses.""" + 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 +25,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: @@ -133,7 +141,7 @@ def cmd_in_background(command: str, *, silent: bool = False) -> subprocess.Popen def kill_subproc() -> None: try: if subproc.poll() is None: - logger.info("At exit handler: killing {}: {}".format(subproc, command)) + logger.info('At exit handler: killing %s (%s)', subproc, command) subproc.terminate() subproc.wait(timeout=10.0) except BaseException as be: