aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mtest.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/mtest.py')
-rw-r--r--mesonbuild/mtest.py111
1 files changed, 74 insertions, 37 deletions
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 2dcc27d..dd03515 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -154,6 +154,15 @@ def join_lines(a: str, b: str) -> str:
return a
return a + '\n' + b
+def dashes(s: str, dash: str, cols: int) -> str:
+ if not s:
+ return dash * cols
+ s = ' ' + s + ' '
+ width = uniwidth(s)
+ first = (cols - width) // 2
+ s = dash * first + s
+ return s + dash * (cols - first - width)
+
def returncode_to_status(retcode: int) -> str:
# Note: We can't use `os.WIFSIGNALED(result.returncode)` and the related
# functions here because the status returned by subprocess is munged. It
@@ -241,6 +250,9 @@ class TestResult(enum.Enum):
result_str = '{res:{reslen}}'.format(res=self.value, reslen=self.maxlen())
return self.colorize(result_str).get_text(colorize)
+ def get_command_marker(self) -> str:
+ return str(self.colorize('>>> '))
+
TYPE_TAPResult = T.Union['TAPParser.Test', 'TAPParser.Error', 'TAPParser.Version', 'TAPParser.Plan', 'TAPParser.Bailout']
@@ -452,6 +464,9 @@ class ConsoleLogger(TestLogger):
SPINNER = "\U0001f311\U0001f312\U0001f313\U0001f314" + \
"\U0001f315\U0001f316\U0001f317\U0001f318"
+ SCISSORS = "\u2700 "
+ HLINE = "\u2015"
+
def __init__(self) -> None:
self.update = asyncio.Event()
self.running_tests = OrderedSet() # type: OrderedSet['TestRun']
@@ -464,6 +479,20 @@ class ConsoleLogger(TestLogger):
self.test_count = 0
self.started_tests = 0
self.spinner_index = 0
+ try:
+ self.cols, _ = os.get_terminal_size(1)
+ self.is_tty = True
+ except OSError:
+ self.cols = 80
+ self.is_tty = False
+
+ self.output_start = dashes(self.SCISSORS, self.HLINE, self.cols - 2)
+ self.output_end = dashes('', self.HLINE, self.cols - 2)
+ try:
+ self.output_start.encode(sys.stdout.encoding or 'ascii')
+ except UnicodeEncodeError:
+ self.output_start = dashes('8<', '-', self.cols - 2)
+ self.output_end = dashes('', '-', self.cols - 2)
def flush(self) -> None:
if self.should_erase_line:
@@ -504,14 +533,6 @@ class ConsoleLogger(TestLogger):
left=left, right=right)
self.print_progress(line)
- @staticmethod
- def is_tty() -> bool:
- try:
- _, _ = os.get_terminal_size(1)
- return True
- except OSError:
- return False
-
def start(self, harness: 'TestHarness') -> None:
async def report_progress() -> None:
loop = asyncio.get_event_loop()
@@ -544,8 +565,9 @@ class ConsoleLogger(TestLogger):
self.flush()
self.test_count = harness.test_count
+ self.cols = max(self.cols, harness.max_left_width + 30)
- if self.is_tty() and not harness.need_console:
+ if self.is_tty and not harness.need_console:
# Account for "[aa-bb/cc] OO " in the progress report
self.max_left_width = 3 * len(str(self.test_count)) + 8
self.progress_task = asyncio.ensure_future(report_progress())
@@ -557,19 +579,23 @@ class ConsoleLogger(TestLogger):
self.request_update()
def shorten_log(self, result: 'TestRun') -> str:
- log = result.get_log()
+ log = result.get_log(mlog.colorize_console())
lines = log.splitlines()
- if len(lines) < 103:
+ if len(lines) < 100:
return log
else:
- log = '\n'.join(lines[:2])
- log += '\n--- Listing only the last 100 lines from a long log. ---\n'
- log += lines[2] + '\n'
- log += '\n'.join(lines[-100:])
- return log
+ return str(mlog.bold('Listing only the last 100 lines from a long log.\n')) + '\n'.join(lines[-100:])
def print_log(self, result: 'TestRun', log: str) -> None:
- print_safe(log, end='')
+ cmdline = result.cmdline
+ if not cmdline:
+ print(result.res.get_command_marker() + result.stdo)
+ return
+ print(result.res.get_command_marker() + cmdline)
+ if log:
+ print(self.output_start)
+ print_safe(log, end='')
+ print(self.output_end)
print(flush=True)
def log(self, harness: 'TestHarness', result: 'TestRun') -> None:
@@ -582,6 +608,8 @@ class ConsoleLogger(TestLogger):
self.flush()
print(harness.format(result, mlog.colorize_console(), max_left_width=self.max_left_width),
flush=True)
+ if result.res.is_bad():
+ self.print_log(result, '')
self.request_update()
async def finish(self, harness: 'TestHarness') -> None:
@@ -616,8 +644,14 @@ class TextLogfileBuilder(TestFileLogger):
self.file.write('Inherited environment: {}\n\n'.format(inherit_env))
def log(self, harness: 'TestHarness', result: 'TestRun') -> None:
- self.file.write(harness.format(result, False))
- self.file.write("\n\n" + result.get_log() + "\n")
+ self.file.write(harness.format(result, False) + '\n')
+ cmdline = result.cmdline
+ if cmdline:
+ starttime_str = time.strftime("%H:%M:%S", time.gmtime(result.starttime))
+ self.file.write(starttime_str + ' ' + cmdline + '\n')
+ self.file.write(dashes('output', '-', 78) + '\n')
+ self.file.write(result.get_log())
+ self.file.write(dashes('', '-', 78) + '\n\n')
async def finish(self, harness: 'TestHarness') -> None:
if harness.collected_failures:
@@ -847,24 +881,20 @@ class TestRun:
stdo: T.Optional[str], stde: T.Optional[str]) -> None:
self._complete(returncode, res, stdo, stde)
- def get_log(self) -> str:
- res = '--- command ---\n'
- if self.cmd is None:
- res += 'NONE\n'
- else:
- starttime_str = time.strftime("%H:%M:%S", time.gmtime(self.starttime))
- res += '{} {}\n'.format(starttime_str, self.cmdline)
- if self.stdo:
- res += '--- stdout ---\n'
- res += self.stdo
+ def get_log(self, colorize: bool = False) -> str:
if self.stde:
- if res[-1:] != '\n':
- res += '\n'
- res += '--- stderr ---\n'
+ res = ''
+ if self.stdo:
+ res += mlog.cyan('stdout:').get_text(colorize) + '\n'
+ res += self.stdo
+ if res[-1:] != '\n':
+ res += '\n'
+ res += mlog.cyan('stderr:').get_text(colorize) + '\n'
res += self.stde
- if res[-1:] != '\n':
+ else:
+ res = self.stdo
+ if res and res[-1:] != '\n':
res += '\n'
- res += '-------\n'
return res
@property
@@ -1418,21 +1448,28 @@ class TestHarness:
for l in self.loggers:
l.log(self, result)
+ @property
+ def numlen(self) -> int:
+ return len(str(self.test_count))
+
+ @property
+ def max_left_width(self) -> int:
+ return 2 * self.numlen + 2
+
def format(self, result: TestRun, colorize: bool,
max_left_width: int = 0,
left: T.Optional[str] = None,
right: T.Optional[str] = None) -> str:
- numlen = len(str(self.test_count))
if left is None:
left = '{num:{numlen}}/{testcount} '.format(
- numlen=numlen,
+ numlen=self.numlen,
num=result.num,
testcount=self.test_count)
# A non-default max_left_width lets the logger print more stuff before the
# name, while ensuring that the rightmost columns remain aligned.
- max_left_width = max(max_left_width, 2 * numlen + 2)
+ max_left_width = max(max_left_width, self.max_left_width)
extra_name_width = max_left_width + self.name_max_len + 1 - uniwidth(result.name) - uniwidth(left)
middle = result.name + (' ' * max(1, extra_name_width))