|  | #!/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() |