From eb01f28b04cccd2dd5e356c65fc71ba61b7a2129 Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat Date: Tue, 20 Oct 2020 13:21:55 +0200 Subject: [PATCH] gh_wrap_errors.py: make sure all output is processed The current select-based code to consume subprocess output on the fly sometimes misses the end of the output. Rework it to consume mixed stdout+stderr until the end of output instead. --- utils/gh_wrap_errors.py | 55 ++++++++--------------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/utils/gh_wrap_errors.py b/utils/gh_wrap_errors.py index 31ed65957..c3d9f14c9 100755 --- a/utils/gh_wrap_errors.py +++ b/utils/gh_wrap_errors.py @@ -8,7 +8,6 @@ GitHub workflow commands. import argparse from os import path as P import re -import select import subprocess import sys @@ -21,56 +20,22 @@ msg_re = re.compile(r"(.*?):(\d+):(?:(d+)\:)?(.*)?$") p = subprocess.Popen( extra_args, universal_newlines=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE + stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) +# If a line is a GNU style error message, emit a corresponding workflow +# command and trigger an error status. exit_status = 0 - - -def emit_workflow_command_for_line(line): - """ - If line is a GNU style error message, emit a corresponding workflow - command. - """ - global exit_status - m = msg_re.match(line) +for line in p.stdout: + m = msg_re.match(line.rstrip()) if m: exit_status = 1 file, line, _, msg = m.groups() - if file.startswith('/'): + if file.startswith("/"): file = P.relpath(file) print(f"::error file={file},line={line}::{msg}") + sys.stdout.write(line) + sys.stdout.flush() - -stdout = [] -stderr = [] - -# Record the subprocess's stdout & stderr while still feeding them to this -# process' out & err. -while True: - descs, _, _ = select.select((p.stdout.fileno(), p.stderr.fileno()), [], []) - - # Record stdout and stderr, while still forwarding them to this process' - # stdout and stderr. - for fd in descs: - if fd == p.stdout.fileno(): - read = p.stdout.read() - sys.stdout.write(read) - stdout.append(read) - elif fd == p.stderr.fileno(): - read = p.stderr.read() - sys.stderr.write(read) - stderr.append(read) - - returncode = p.poll() - if returncode is not None: - # Process has terminated, check if the return code is non zero, and if - # it is, propagate to exit_status. - if returncode != 0: - exit_status = returncode - break - -for line in "".join(stdout + stderr).splitlines(): - emit_workflow_command_for_line(line) - -sys.exit(exit_status) +p.wait() +sys.exit(p.returncode if exit_status == 0 else exit_status)