xref: /aosp_15_r20/external/cronet/testing/scripts/rust/exe_util.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker# Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker"""Utilities for invoking executables.
5*6777b538SAndroid Build Coastguard Worker"""
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Workerimport os
8*6777b538SAndroid Build Coastguard Workerimport subprocess
9*6777b538SAndroid Build Coastguard Workerimport re
10*6777b538SAndroid Build Coastguard Workerimport sys
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker# Regex for matching 7-bit and 8-bit C1 ANSI sequences.
13*6777b538SAndroid Build Coastguard Worker# Credit: https://stackoverflow.com/a/14693789/4692014
14*6777b538SAndroid Build Coastguard Worker_ANSI_ESCAPE_8BIT_REGEX = re.compile(
15*6777b538SAndroid Build Coastguard Worker    r"""
16*6777b538SAndroid Build Coastguard Worker    (?: # either 7-bit C1, two bytes, ESC Fe (omitting CSI)
17*6777b538SAndroid Build Coastguard Worker        \x1B
18*6777b538SAndroid Build Coastguard Worker        [@-Z\\-_]
19*6777b538SAndroid Build Coastguard Worker    |   # or a single 8-bit byte Fe (omitting CSI)
20*6777b538SAndroid Build Coastguard Worker        [\x80-\x9A\x9C-\x9F]
21*6777b538SAndroid Build Coastguard Worker    |   # or CSI + control codes
22*6777b538SAndroid Build Coastguard Worker        (?: # 7-bit CSI, ESC [
23*6777b538SAndroid Build Coastguard Worker            \x1B\[
24*6777b538SAndroid Build Coastguard Worker        |   # 8-bit CSI, 9B
25*6777b538SAndroid Build Coastguard Worker            \x9B
26*6777b538SAndroid Build Coastguard Worker        )
27*6777b538SAndroid Build Coastguard Worker        [0-?]*  # Parameter bytes
28*6777b538SAndroid Build Coastguard Worker        [ -/]*  # Intermediate bytes
29*6777b538SAndroid Build Coastguard Worker        [@-~]   # Final byte
30*6777b538SAndroid Build Coastguard Worker    )
31*6777b538SAndroid Build Coastguard Worker""", re.VERBOSE)
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Workerdef run_and_tee_output(args):
35*6777b538SAndroid Build Coastguard Worker    """Runs the test executable passing-thru its output to stdout (in a
36*6777b538SAndroid Build Coastguard Worker    terminal-colors-friendly way).  Waits for the executable to exit.
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker    Returns:
39*6777b538SAndroid Build Coastguard Worker        The full executable output as an UTF-8 string.
40*6777b538SAndroid Build Coastguard Worker    """
41*6777b538SAndroid Build Coastguard Worker    # Capture stdout (where test results are written), but inherit stderr. This
42*6777b538SAndroid Build Coastguard Worker    # way errors related to invalid arguments are printed normally.
43*6777b538SAndroid Build Coastguard Worker    proc = subprocess.Popen(args, stdout=subprocess.PIPE)
44*6777b538SAndroid Build Coastguard Worker    captured_output = b''
45*6777b538SAndroid Build Coastguard Worker    while proc.poll() is None:
46*6777b538SAndroid Build Coastguard Worker        buf = proc.stdout.read()
47*6777b538SAndroid Build Coastguard Worker        # Write captured output directly, so escape sequences are preserved.
48*6777b538SAndroid Build Coastguard Worker        sys.stdout.buffer.write(buf)
49*6777b538SAndroid Build Coastguard Worker        captured_output += buf
50*6777b538SAndroid Build Coastguard Worker
51*6777b538SAndroid Build Coastguard Worker    captured_output = _ANSI_ESCAPE_8BIT_REGEX.sub(
52*6777b538SAndroid Build Coastguard Worker        '', captured_output.decode('utf-8'))
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker    return captured_output
55