Simon Jakobi pushed to branch wip/sjakobi/T16720 at Glasgow Haskell Compiler / GHC

Commits:

3 changed files:

Changes:

  • .gitlab/ci.sh
    ... ... @@ -644,6 +644,10 @@ function test_hadrian() {
    644 644
       check_msys2_deps _build/stage1/bin/ghc --version
    
    645 645
       check_release_build
    
    646 646
     
    
    647
    +  # GitLab's log viewer renders ANSI colors, but stdout here is not a tty,
    
    648
    +  # so the driver must be told to emit them.
    
    649
    +  RUNTEST_ARGS="${RUNTEST_ARGS:-} --force-colors"
    
    650
    +
    
    647 651
       # Ensure that statically-linked builds are actually static
    
    648 652
       if [[ "${BUILD_FLAVOUR}" = *static* ]]; then
    
    649 653
         bad_execs=""
    

  • testsuite/driver/runtests.py
    ... ... @@ -94,6 +94,8 @@ parser.add_argument("--ignore-perf-failures", choices=['increases','decreases','
    94 94
                             help="Do not fail due to out-of-tolerance perf tests")
    
    95 95
     parser.add_argument("--only-report-hadrian-deps", type=Path,
    
    96 96
                             help="Dry run the testsuite and report all extra hadrian dependencies needed on the given file")
    
    97
    +parser.add_argument("--force-colors", action="store_true",
    
    98
    +                        help="emit ANSI colors even when stdout is not a tty (e.g. for CI logs)")
    
    97 99
     
    
    98 100
     args = parser.parse_args()
    
    99 101
     
    
    ... ... @@ -259,7 +261,9 @@ def supports_colors():
    259 261
         return True
    
    260 262
     
    
    261 263
     config.supports_colors = supports_colors()
    
    262
    -term_color.enable_color = config.supports_colors
    
    264
    +# config.supports_colors deliberately stays tty-based: it also guards
    
    265
    +# terminal-title updates, which must not end up in a CI log.
    
    266
    +term_color.enable_color = config.supports_colors or args.force_colors
    
    263 267
     
    
    264 268
     # This has to come after arg parsing as the args can change the compiler
    
    265 269
     get_compiler_info()
    
    ... ... @@ -587,7 +591,7 @@ else:
    587 591
             print(Perf.allow_changes_string([(m.change, m.stat) for m in t.metrics]))
    
    588 592
             print('-' * 25)
    
    589 593
     
    
    590
    -    summary(t, sys.stdout, color=config.supports_colors)
    
    594
    +    summary(t, sys.stdout, color=term_color.enable_color)
    
    591 595
     
    
    592 596
         # Write perf stats if any exist or if a metrics file is specified.
    
    593 597
         stats_metrics = [stat for (_, stat, __) in t.metrics] # type: List[PerfStat]
    

  • testsuite/driver/testlib.py
    ... ... @@ -3543,7 +3543,8 @@ def summary(t: TestRun, file: TextIO, color=False) -> None:
    3543 3543
             summary_color = Color.GREEN
    
    3544 3544
     
    
    3545 3545
         assert t.start_time is not None
    
    3546
    -    file.write(colored(summary_color, 'SUMMARY') + ' for test run started at '
    
    3546
    +    summary_header = colored(summary_color, 'SUMMARY') if color else 'SUMMARY'
    
    3547
    +    file.write(summary_header + ' for test run started at '
    
    3547 3548
                    + t.start_time.strftime("%c %Z") + '\n'
    
    3548 3549
                    + str(datetime.datetime.now() - t.start_time).rjust(8)
    
    3549 3550
                    + ' spent to go through\n'
    
    ... ... @@ -3597,7 +3598,7 @@ def summary(t: TestRun, file: TextIO, color=False) -> None:
    3597 3598
     
    
    3598 3599
         if t.unexpected_failures:
    
    3599 3600
             file.write('Output of unexpected failures:\n\n')
    
    3600
    -        printTestOutputSummary(file, t.unexpected_failures)
    
    3601
    +        printTestOutputSummary(file, t.unexpected_failures, color)
    
    3601 3602
     
    
    3602 3603
         if stopping():
    
    3603 3604
             file.write('WARNING: Testsuite run was terminated early\n')
    
    ... ... @@ -3615,26 +3616,34 @@ def printUnexpectedTests(file: TextIO, testInfoss):
    3615 3616
     # Per-stream cap on a failing test's output repeated in the final summary.
    
    3616 3617
     MAX_SUMMARY_OUTPUT_LINES = 100
    
    3617 3618
     
    
    3618
    -def printTestOutputSummary(file: TextIO, testInfos) -> None:
    
    3619
    +def printTestOutputSummary(file: TextIO, testInfos, color: bool=False) -> None:
    
    3619 3620
         # Repeat failing tests' captured output in the summary, so one needn't
    
    3620 3621
         # hunt for it earlier in a possibly very long log; see #16720.
    
    3621 3622
         for result in sorted(testInfos, key=lambda r: (r.testname.lower(), r.way, r.directory)):
    
    3622
    -        file.write(colored(Color.RED,
    
    3623
    -                           '=====> {}({}) [{}]'.format(result.testname, result.way, result.reason))
    
    3624
    -                   + '\n')
    
    3623
    +        header = '=====> {}({}) [{}]'.format(result.testname, result.way, result.reason)
    
    3624
    +        if color:
    
    3625
    +            header = colored(Color.RED, header)
    
    3626
    +        file.write(header + '\n')
    
    3625 3627
             for stream_name, contents in [('stdout', result.stdout), ('stderr', result.stderr)]:
    
    3626 3628
                 if contents and contents.strip():
    
    3629
    +                label = 'Captured {}:'.format(stream_name)
    
    3630
    +                if color:
    
    3631
    +                    label = colored(Color.CYAN, label)
    
    3627 3632
                     lines = contents.rstrip('\n').split('\n')
    
    3628 3633
                     if len(lines) > MAX_SUMMARY_OUTPUT_LINES:
    
    3629 3634
                         omitted = len(lines) - MAX_SUMMARY_OUTPUT_LINES
    
    3630 3635
                         lines = lines[:MAX_SUMMARY_OUTPUT_LINES] \
    
    3631 3636
                             + ['... ({} more lines omitted, see junit.xml)'.format(omitted)]
    
    3632
    -                s = 'Captured {}:\n{}\n'.format(stream_name, '\n'.join(lines))
    
    3637
    +                s = label + '\n' + ''.join(l + '\n' for l in lines)
    
    3633 3638
                     # Test output can contain characters that file's encoding
    
    3634 3639
                     # cannot represent; replace rather than crash (cf safe_print).
    
    3635 3640
                     enc = getattr(file, 'encoding', None) or 'utf-8'
    
    3636 3641
                     file.write(s.encode(enc, errors='replace').decode(enc))
    
    3637 3642
             file.write('\n')
    
    3643
    +    footer = '<===== end of output of unexpected failures'
    
    3644
    +    if color:
    
    3645
    +        footer = colored(Color.RED, footer)
    
    3646
    +    file.write(footer + '\n\n')
    
    3638 3647
     
    
    3639 3648
     def printTestInfosSummary(file: TextIO, testInfos):
    
    3640 3649
         maxDirLen = max(len(tr.directory) for tr in testInfos)