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