#!/usr/bin/env python3 """Generate test body using split-file and a custom script. The script will prepare extra files with `split-file`, invoke `gen`, and then rewrite the part after `gen` with its stdout. https://llvm.org/docs/TestingGuide.html#elaborated-tests Example: PATH=/path/to/clang_build/bin:$PATH llvm/utils/update_test_body.py path/to/test.s """ import argparse import contextlib import os import re import subprocess import sys import tempfile @contextlib.contextmanager def cd(directory): cwd = os.getcwd() os.chdir(directory) try: yield finally: os.chdir(cwd) def process(args, path): prolog = [] seen_gen = False with open(path) as f: for line in f.readlines(): line = line.rstrip() prolog.append(line) if (seen_gen and re.match(r"(.|//)---", line)) or line.startswith(".endif"): break if re.match(r"(.|//)--- gen", line): seen_gen = True else: print( "'gen' should be followed by another part (---) or .endif", file=sys.stderr, ) return 1 if not seen_gen: print("'gen' does not exist", file=sys.stderr) return 1 with tempfile.TemporaryDirectory(prefix="update_test_body_") as dir: try: # If the last line starts with ".endif", remove it. sub = subprocess.run( ["split-file", "-", dir], input="\n".join( prolog[:-1] if prolog[-1].startswith(".endif") else prolog ).encode(), capture_output=True, check=True, ) except subprocess.CalledProcessError as ex: sys.stderr.write(ex.stderr.decode()) return 1 with cd(dir): if args.shell: print(f"invoke shell in the temporary directory '{dir}'") subprocess.run([os.environ.get("SHELL", "sh")]) return 0 sub = subprocess.run( ["sh", "-eu", "gen"], capture_output=True, # Don't encode the directory information to the Clang output. # Remove unneeded details (.ident) as well. env=dict( os.environ, CCC_OVERRIDE_OPTIONS="#^-fno-ident", PWD="/proc/self/cwd", ), ) sys.stderr.write(sub.stderr.decode()) if sub.returncode != 0: print("'gen' failed", file=sys.stderr) return sub.returncode if not sub.stdout: print("stdout is empty; forgot -o - ?", file=sys.stderr) return 1 content = sub.stdout.decode() with open(path, "w") as f: # Print lines up to '.endif'. print("\n".join(prolog), file=f) # Then print the stdout of 'gen'. f.write(content) parser = argparse.ArgumentParser( description="Generate test body using split-file and a custom script" ) parser.add_argument("files", nargs="+") parser.add_argument( "--shell", action="store_true", help="invoke shell instead of 'gen'" ) args = parser.parse_args() for path in args.files: retcode = process(args, path) if retcode != 0: sys.exit(retcode)