| #!/usr/bin/env python3 | |
| # Copyright lowRISC contributors. | |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| """Show a diff between the generated output from utils in the current working | |
| tree versus a previous revision (HEAD by default). This makes it easy to | |
| inspect the impact of modifications to either the utility implementation or | |
| its input files on the generated output (e.g. HTML). | |
| """ | |
| import argparse | |
| import os | |
| import shlex | |
| import subprocess | |
| import sys | |
| import tempfile | |
| from reggen import version | |
| # Test list format: | |
| # output, outisdir, commandpre, commandpost | |
| # if outisdir then it will be mkdired | |
| # command is commandpre + fullpath_output + commandpost | |
| testlist = [ | |
| ["regdoc.md", False, | |
| "./regtool.py --doc > ", ""], | |
| ["uart_rtl", True, | |
| "./regtool.py -r -t ", " ../hw/ip/uart/data/uart.hjson"], | |
| ["uart_dv", True, | |
| "./regtool.py -s -t ", " ../hw/ip/uart/data/uart.hjson"], | |
| # generating include define headers | |
| ["uart.h", False, | |
| "./regtool.py -D ../hw/ip/uart/data/uart.hjson > ", ""], | |
| ["gpio.h", False, | |
| "./regtool.py -D ../hw/ip/gpio/data/gpio.hjson > ", ""], | |
| ["spi_device.h", False, | |
| "./regtool.py -D ../hw/ip/spi_device/data/spi_device.hjson > ", ""] | |
| ] # yapf: disable | |
| def generate_output(outdir, verbose): | |
| for t in testlist: | |
| out = shlex.quote(os.path.join(outdir, t[0])) | |
| if t[1]: | |
| # in new tmpdir so the directory should never be there already | |
| os.mkdir(out) | |
| errors_out = open(out + ".STDERR", 'w', encoding='UTF-8') | |
| with errors_out: | |
| err = subprocess.call(t[2] + out + t[3], | |
| stderr=errors_out, | |
| shell=True) | |
| # write a file so it pops up in the diff | |
| # if it is different | |
| # (i.e. won't mention any that always return same error) | |
| if err != 0: | |
| rtn_out = open(out + ".RETURN", 'w', encoding='UTF-8') | |
| with rtn_out: | |
| rtn_out.write("Non-Zero Return code " + str(err) + "\n") | |
| # useful for debug: | |
| if (verbose): | |
| subprocess.call("ls -l " + outdir, shell=True) | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description=__doc__, | |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter) | |
| parser.add_argument("treeish", | |
| default="HEAD", | |
| nargs="?", | |
| help="git tree or commit to compare against") | |
| parser.add_argument('--version', | |
| action='store_true', | |
| help='Show version and exit') | |
| parser.add_argument('-v', | |
| '--verbose', | |
| action='store_true', | |
| help='Verbose output: ls the output directories') | |
| args = parser.parse_args() | |
| if args.version: | |
| version.show_and_exit(__file__, []) | |
| args.treeish = shlex.quote(args.treeish) | |
| util_path = os.path.dirname(os.path.realpath(__file__)) | |
| repo_root = os.path.abspath(os.path.join(util_path, os.pardir)) | |
| os.chdir(repo_root) | |
| if not os.path.isdir(os.path.join(repo_root, '.git')): | |
| print("Script not in expected location in a git repo", file=sys.stderr) | |
| sys.exit(1) | |
| # Exit early if there are no diffs between the working tree and | |
| # args.treeish. | |
| output = subprocess.check_output("git diff " + args.treeish, shell=True) | |
| if not output: | |
| sys.exit(0) | |
| # Create temporary directories in util_path rather than defaulting to /tmp. | |
| # /tmp may be small and may may be mounted noexec. | |
| tempfile.tempdir = util_path | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| tmpdir_basename = os.path.basename(tmpdir) | |
| subprocess.check_call("git archive " + args.treeish + | |
| " | tar -x -C util/" + tmpdir_basename, | |
| shell=True) | |
| # Execute commands for working tree, saving output | |
| os.chdir(util_path) | |
| newoutdir = os.path.join(tmpdir, "newout") | |
| os.mkdir(newoutdir) | |
| generate_output(newoutdir, args.verbose) | |
| # Execute commands for previous revision, saving output | |
| os.chdir(os.path.join(tmpdir_basename, "util")) | |
| oldoutdir = os.path.join(tmpdir, "oldout") | |
| os.mkdir(oldoutdir) | |
| generate_output(oldoutdir, args.verbose) | |
| # Show diff (if any) | |
| os.chdir(tmpdir) | |
| # Don't use a checked call because the exit code indicates whether there | |
| # is a diff or not, rather than indicating error. | |
| subprocess.call('git diff -p --stat --no-index oldout newout', | |
| shell=True) | |
| if __name__ == "__main__": | |
| main() |