#!/usr/bin/env python3 # Copyright © 2024 Valve Corporation # SPDX-License-Identifier: MIT import argparse import collections import subprocess import os import re import sys import tempfile import textwrap from pathlib import Path class TestFileChange: def __init__(self, line, result): self.line = line self.result = result class TestFileChanges: def __init__(self, name): self.name = name self.changes = [] if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--build-dir', '-B', required=False) parser.add_argument('--test-filter', '-f', required=False) parser.add_argument('--update-all', '-u', action='store_true') args = parser.parse_args() bin_path = 'src/compiler/nir/nir_tests' if args.build_dir: bin_path = args.build_dir + '/' + bin_path if not os.path.isfile(bin_path): print(f'{bin_path} \033[91m does not exist!\033[0m') exit(1) build_args = ['meson', 'compile'] if args.build_dir: build_args.append(f'-C{args.build_dir}') subprocess.run(build_args) test_args = [bin_path] if args.test_filter: test_args.append(f'--gtest_filter={args.test_filter}') env = os.environ.copy() if args.update_all: env['NIR_TEST_DUMP_SHADERS'] = 'true' output = subprocess.run(test_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, env=env) expected_pattern = re.compile(r'Expected \(([\d\w\W/.-_]+):(\d+)\):') test_result = None expectations = collections.defaultdict(list) # Parse the output of the test binary and gather the changed shaders. for output_line in output.stdout.split('\n'): if output_line.startswith('Got:'): test_result = '' continue if output_line.startswith('Expected ('): match = expected_pattern.match(output_line) file = match.group(1).removeprefix('../') line = int(match.group(2)) expectations[file].append(TestFileChange(line, test_result.strip())) test_result = None continue if test_result is not None: test_result += output_line + '\n' patches = [] # Generate patches for the changed shaders. for file in expectations: changes = expectations[file] updated_test_file = '' change_index = 0 line_index = 1 inside_expectation = False with open(file) as test_file: for test_line in test_file: if test_line.strip().startswith(')\"'): inside_expectation = False if not inside_expectation: updated_test_file += test_line if change_index < len(changes) and line_index == changes[change_index].line: inside_expectation = True indentation = len(test_line) - len(test_line.lstrip()) + 3 updated_test_file += textwrap.indent(changes[change_index].result, " " * indentation) + '\n' change_index += 1 line_index += 1 with tempfile.NamedTemporaryFile(delete_on_close=False) as tmp: tmp.write(bytes(updated_test_file, encoding="utf-8")) tmp.close() diff = subprocess.run( ['git', 'diff', '--no-index', file, tmp.name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ) patch = diff.stdout.replace(tmp.name, '/' + file) print(patch) patches.append(patch) if len(patches) != 0: sys.stdout.write('\033[96mApply the changes listed above?\033[0m [Y/n]') response = None try: response = input() except KeyboardInterrupt: print() sys.exit(1) if response in ['', 'y', 'Y']: for patch in patches: apply = subprocess.Popen( ['git', 'apply', '--allow-empty'], stdin=subprocess.PIPE, ) apply.communicate(input=bytes(patch, encoding="utf-8"))