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.
This commit is contained in:
Pierre-Marie de Rodat
2020-10-20 13:21:55 +02:00
committed by Pierre-Marie de Rodat
parent 6ae6d9923a
commit eb01f28b04

View File

@@ -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)