1*aacea0d0SFangrui Song#!/usr/bin/env python3 2*aacea0d0SFangrui Song"""Generate test body using split-file and a custom script. 3*aacea0d0SFangrui Song 4*aacea0d0SFangrui SongThe script will prepare extra files with `split-file`, invoke `gen`, and then 5*aacea0d0SFangrui Songrewrite the part after `gen` with its stdout. 6*aacea0d0SFangrui Song 7*aacea0d0SFangrui Songhttps://llvm.org/docs/TestingGuide.html#elaborated-tests 8*aacea0d0SFangrui Song 9*aacea0d0SFangrui SongExample: 10*aacea0d0SFangrui SongPATH=/path/to/clang_build/bin:$PATH llvm/utils/update_test_body.py path/to/test.s 11*aacea0d0SFangrui Song""" 12*aacea0d0SFangrui Songimport argparse 13*aacea0d0SFangrui Songimport contextlib 14*aacea0d0SFangrui Songimport os 15*aacea0d0SFangrui Songimport re 16*aacea0d0SFangrui Songimport subprocess 17*aacea0d0SFangrui Songimport sys 18*aacea0d0SFangrui Songimport tempfile 19*aacea0d0SFangrui Song 20*aacea0d0SFangrui Song 21*aacea0d0SFangrui Song@contextlib.contextmanager 22*aacea0d0SFangrui Songdef cd(directory): 23*aacea0d0SFangrui Song cwd = os.getcwd() 24*aacea0d0SFangrui Song os.chdir(directory) 25*aacea0d0SFangrui Song try: 26*aacea0d0SFangrui Song yield 27*aacea0d0SFangrui Song finally: 28*aacea0d0SFangrui Song os.chdir(cwd) 29*aacea0d0SFangrui Song 30*aacea0d0SFangrui Song 31*aacea0d0SFangrui Songdef process(args, path): 32*aacea0d0SFangrui Song prolog = [] 33*aacea0d0SFangrui Song seen_gen = False 34*aacea0d0SFangrui Song with open(path) as f: 35*aacea0d0SFangrui Song for line in f.readlines(): 36*aacea0d0SFangrui Song line = line.rstrip() 37*aacea0d0SFangrui Song prolog.append(line) 38*aacea0d0SFangrui Song if (seen_gen and re.match(r"(.|//)---", line)) or line.startswith(".endif"): 39*aacea0d0SFangrui Song break 40*aacea0d0SFangrui Song if re.match(r"(.|//)--- gen", line): 41*aacea0d0SFangrui Song seen_gen = True 42*aacea0d0SFangrui Song else: 43*aacea0d0SFangrui Song print( 44*aacea0d0SFangrui Song "'gen' should be followed by another part (---) or .endif", 45*aacea0d0SFangrui Song file=sys.stderr, 46*aacea0d0SFangrui Song ) 47*aacea0d0SFangrui Song return 1 48*aacea0d0SFangrui Song 49*aacea0d0SFangrui Song if not seen_gen: 50*aacea0d0SFangrui Song print("'gen' does not exist", file=sys.stderr) 51*aacea0d0SFangrui Song return 1 52*aacea0d0SFangrui Song with tempfile.TemporaryDirectory(prefix="update_test_body_") as dir: 53*aacea0d0SFangrui Song try: 54*aacea0d0SFangrui Song # If the last line starts with ".endif", remove it. 55*aacea0d0SFangrui Song sub = subprocess.run( 56*aacea0d0SFangrui Song ["split-file", "-", dir], 57*aacea0d0SFangrui Song input="\n".join( 58*aacea0d0SFangrui Song prolog[:-1] if prolog[-1].startswith(".endif") else prolog 59*aacea0d0SFangrui Song ).encode(), 60*aacea0d0SFangrui Song capture_output=True, 61*aacea0d0SFangrui Song check=True, 62*aacea0d0SFangrui Song ) 63*aacea0d0SFangrui Song except subprocess.CalledProcessError as ex: 64*aacea0d0SFangrui Song sys.stderr.write(ex.stderr.decode()) 65*aacea0d0SFangrui Song return 1 66*aacea0d0SFangrui Song with cd(dir): 67*aacea0d0SFangrui Song if args.shell: 68*aacea0d0SFangrui Song print(f"invoke shell in the temporary directory '{dir}'") 69*aacea0d0SFangrui Song subprocess.run([os.environ.get("SHELL", "sh")]) 70*aacea0d0SFangrui Song return 0 71*aacea0d0SFangrui Song 72*aacea0d0SFangrui Song sub = subprocess.run( 73*aacea0d0SFangrui Song ["sh", "-eu", "gen"], 74*aacea0d0SFangrui Song capture_output=True, 75*aacea0d0SFangrui Song # Don't encode the directory information to the Clang output. 76*aacea0d0SFangrui Song # Remove unneeded details (.ident) as well. 77*aacea0d0SFangrui Song env=dict( 78*aacea0d0SFangrui Song os.environ, 79*aacea0d0SFangrui Song CCC_OVERRIDE_OPTIONS="#^-fno-ident", 80*aacea0d0SFangrui Song PWD="/proc/self/cwd", 81*aacea0d0SFangrui Song ), 82*aacea0d0SFangrui Song ) 83*aacea0d0SFangrui Song sys.stderr.write(sub.stderr.decode()) 84*aacea0d0SFangrui Song if sub.returncode != 0: 85*aacea0d0SFangrui Song print("'gen' failed", file=sys.stderr) 86*aacea0d0SFangrui Song return sub.returncode 87*aacea0d0SFangrui Song if not sub.stdout: 88*aacea0d0SFangrui Song print("stdout is empty; forgot -o - ?", file=sys.stderr) 89*aacea0d0SFangrui Song return 1 90*aacea0d0SFangrui Song content = sub.stdout.decode() 91*aacea0d0SFangrui Song 92*aacea0d0SFangrui Song with open(path, "w") as f: 93*aacea0d0SFangrui Song # Print lines up to '.endif'. 94*aacea0d0SFangrui Song print("\n".join(prolog), file=f) 95*aacea0d0SFangrui Song # Then print the stdout of 'gen'. 96*aacea0d0SFangrui Song f.write(content) 97*aacea0d0SFangrui Song 98*aacea0d0SFangrui Song 99*aacea0d0SFangrui Songparser = argparse.ArgumentParser( 100*aacea0d0SFangrui Song description="Generate test body using split-file and a custom script" 101*aacea0d0SFangrui Song) 102*aacea0d0SFangrui Songparser.add_argument("files", nargs="+") 103*aacea0d0SFangrui Songparser.add_argument( 104*aacea0d0SFangrui Song "--shell", action="store_true", help="invoke shell instead of 'gen'" 105*aacea0d0SFangrui Song) 106*aacea0d0SFangrui Songargs = parser.parse_args() 107*aacea0d0SFangrui Songfor path in args.files: 108*aacea0d0SFangrui Song retcode = process(args, path) 109*aacea0d0SFangrui Song if retcode != 0: 110*aacea0d0SFangrui Song sys.exit(retcode) 111