blob: 5988bcc45470d3182c2296603376857b4ea23b2f [file] [log] [blame]
#!/usr/bin/env python3
"""
Compares previous output of all kazoo generation with current output.
The current golden state (vs. real syscalls) is saved in golden.txt.
A `cp` command will be printed to update golden.txt if the current
pipeline generates different output than previously checked in.
"""
import argparse
import datetime
import os
import shutil
import subprocess
import sys
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
GOLDEN = os.path.abspath(os.path.join(os.path.dirname(__file__), 'golden.txt'))
def parse_args():
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--builddir',
help='build root to which rsp files are relative',
required=True)
parser.add_argument('--fidlc',
help='rspfile containing fidlc binary',
required=True)
parser.add_argument('--kazoo',
help='rspfile containing kazoo binary',
required=True)
parser.add_argument('--syscalls',
help='path to syscalls',
default=os.path.normpath(
os.path.join(SCRIPT_DIR, os.pardir, os.pardir,
'vdso')))
parser.add_argument('--p4merge',
action='store_true',
help='open diffs in p4merge if changes')
parser.add_argument('--output-touch',
help='file to touch on success',
required=True)
parser.add_argument('--tmp-base',
help='location to use for temporary files',
required=True)
return parser.parse_args()
def generate_fidlc_json(fidlc_binary, syscall_dir, output_fidlc_json_path):
fidl_files = []
with os.scandir(syscall_dir) as it:
for entry in it:
if (not entry.name.startswith('.') and entry.is_file() and
entry.name.endswith('.fidl')):
fidl_files.append(os.path.join(syscall_dir, entry.name))
subprocess.check_call(
[fidlc_binary, '--json', output_fidlc_json_path, '--files'] +
sorted(fidl_files))
def build_golden(input_files, output_combined):
with open(output_combined, 'w') as outf:
for filename in input_files:
outf.write('----- %s START -----\n' % os.path.basename(filename))
outf.write(open(filename, 'r').read())
outf.write('----- %s END -----\n\n\n' % os.path.basename(filename))
def generate_kazoo_outputs(kazoo_binary, fidlc_json_path, all_output_styles,
output_dir):
def guess_ext(style):
if style in ('go-vdso-arm64-calls', 'go-vdso-x86-calls'):
return 's'
if style.startswith('go'):
return 'go'
if style == 'rust':
return 'rs'
if style == 'json':
return 'json'
return 'h'
style_args = []
files = []
for style in all_output_styles:
filename = '%s.%s' % (os.path.join(output_dir, style), guess_ext(style))
files.append(filename)
style_args.append('--%s=%s' % (style, filename))
subprocess.check_call([kazoo_binary] + style_args + [fidlc_json_path])
return files
def read_rsp_and_rebase(path, builddir):
with open(path, 'r') as f:
from_rsp = f.read().strip()
return os.path.join(builddir, from_rsp)
def main():
args = parse_args()
tmp_json = os.path.join(args.tmp_base, 'syscalls.json')
fidlc = read_rsp_and_rebase(args.fidlc, args.builddir)
generate_fidlc_json(fidlc, args.syscalls, tmp_json)
tmp_kazoo_dir = os.path.join(args.tmp_base, 'kazoo-outputs')
try:
shutil.rmtree(tmp_kazoo_dir)
except:
pass
os.makedirs(tmp_kazoo_dir)
all_styles = (
'c-ulib-header',
'category',
'go-syscall-arm64-asm',
'go-syscall-stubs',
'go-syscall-x86-asm',
'go-vdso-arm64-calls',
'go-vdso-keys',
'go-vdso-x86-calls',
'json',
'kernel-header',
'kernel-wrappers',
'private-header',
'public-header',
'rust',
'syscall-numbers',
'testonly-public-header',
)
kazoo = read_rsp_and_rebase(args.kazoo, args.builddir)
files = generate_kazoo_outputs(kazoo, tmp_json, all_styles, tmp_kazoo_dir)
tmp_golden = os.path.join(args.tmp_base, 'new-golden.txt')
build_golden(files, tmp_golden)
rc = subprocess.call(['diff', GOLDEN, tmp_golden])
if rc != 0:
print('CHANGES DETECTED IN SYSCALL OUTPUT')
print()
print('Please run:')
print(' cp %s %s' % (tmp_golden, GOLDEN))
print('to acknowledge these changes.')
print()
print('Files can be found locally in %s for inspection.' %
tmp_kazoo_dir)
if args.p4merge:
subprocess.call(['p4merge', GOLDEN, tmp_golden])
else:
with open(args.output_touch, 'w') as f:
f.write(str(datetime.datetime.utcnow()))
return rc
if __name__ == '__main__':
sys.exit(main())