lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # Copyright lowRISC contributors. |
| 3 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 4 | # SPDX-License-Identifier: Apache-2.0 |
| 5 | """Show a diff between the generated output from utils in the current working |
| 6 | tree versus a previous revision (HEAD by default). This makes it easy to |
| 7 | inspect the impact of modifications to either the utility implementation or |
| 8 | its input files on the generated output (e.g. HTML). |
| 9 | """ |
| 10 | |
| 11 | import argparse |
| 12 | import os |
| 13 | import shlex |
| 14 | import subprocess |
| 15 | import sys |
| 16 | import tempfile |
| 17 | |
| 18 | from reggen import version |
| 19 | |
| 20 | # Test list format: |
| 21 | # output, outisdir, commandpre, commandpost |
| 22 | # if outisdir then it will be mkdired |
| 23 | # command is commandpre + fullpath_output + commandpost |
| 24 | |
| 25 | testlist = [ |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 26 | ["regdoc.md", False, |
| 27 | "./regtool.py --doc > ", ""], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 28 | ["uart_rtl", True, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 29 | "./regtool.py -r -t ", " ../hw/ip/uart/data/uart.hjson"], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 30 | ["uart_dv", True, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 31 | "./regtool.py -s -t ", " ../hw/ip/uart/data/uart.hjson"], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 32 | # generating include define headers |
| 33 | ["uart.h", False, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 34 | "./regtool.py -D ../hw/ip/uart/data/uart.hjson > ", ""], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 35 | ["gpio.h", False, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 36 | "./regtool.py -D ../hw/ip/gpio/data/gpio.hjson > ", ""], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 37 | ["spi_device.h", False, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 38 | "./regtool.py -D ../hw/ip/spi_device/data/spi_device.hjson > ", ""] |
Tobias Wölfel | b4b624d | 2020-05-15 11:06:07 +0200 | [diff] [blame] | 39 | ] # yapf: disable |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 40 | |
| 41 | |
| 42 | def generate_output(outdir, verbose): |
| 43 | for t in testlist: |
| 44 | out = shlex.quote(os.path.join(outdir, t[0])) |
| 45 | if t[1]: |
| 46 | # in new tmpdir so the directory should never be there already |
| 47 | os.mkdir(out) |
| 48 | errors_out = open(out + ".STDERR", 'w', encoding='UTF-8') |
| 49 | with errors_out: |
| 50 | err = subprocess.call(t[2] + out + t[3], |
| 51 | stderr=errors_out, |
| 52 | shell=True) |
| 53 | # write a file so it pops up in the diff |
| 54 | # if it is different |
| 55 | # (i.e. won't mention any that always return same error) |
| 56 | if err != 0: |
| 57 | rtn_out = open(out + ".RETURN", 'w', encoding='UTF-8') |
| 58 | with rtn_out: |
| 59 | rtn_out.write("Non-Zero Return code " + str(err) + "\n") |
| 60 | |
| 61 | # useful for debug: |
| 62 | if (verbose): |
| 63 | subprocess.call("ls -l " + outdir, shell=True) |
| 64 | |
| 65 | |
| 66 | def main(): |
| 67 | parser = argparse.ArgumentParser( |
| 68 | description=__doc__, |
| 69 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| 70 | parser.add_argument("treeish", |
| 71 | default="HEAD", |
| 72 | nargs="?", |
| 73 | help="git tree or commit to compare against") |
| 74 | parser.add_argument('--version', |
| 75 | action='store_true', |
| 76 | help='Show version and exit') |
| 77 | parser.add_argument('-v', |
| 78 | '--verbose', |
| 79 | action='store_true', |
| 80 | help='Verbose output: ls the output directories') |
| 81 | |
| 82 | args = parser.parse_args() |
| 83 | if args.version: |
| 84 | version.show_and_exit(__file__, []) |
| 85 | args.treeish = shlex.quote(args.treeish) |
| 86 | |
| 87 | util_path = os.path.dirname(os.path.realpath(__file__)) |
| 88 | repo_root = os.path.abspath(os.path.join(util_path, os.pardir)) |
| 89 | os.chdir(repo_root) |
| 90 | |
| 91 | if not os.path.isdir(os.path.join(repo_root, '.git')): |
| 92 | print("Script not in expected location in a git repo", file=sys.stderr) |
| 93 | sys.exit(1) |
| 94 | |
| 95 | # Exit early if there are no diffs between the working tree and |
| 96 | # args.treeish. |
| 97 | output = subprocess.check_output("git diff " + args.treeish, shell=True) |
| 98 | if not output: |
| 99 | sys.exit(0) |
| 100 | |
| 101 | # Create temporary directories in util_path rather than defaulting to /tmp. |
| 102 | # /tmp may be small and may may be mounted noexec. |
| 103 | tempfile.tempdir = util_path |
| 104 | |
| 105 | with tempfile.TemporaryDirectory() as tmpdir: |
| 106 | tmpdir_basename = os.path.basename(tmpdir) |
| 107 | subprocess.check_call("git archive " + args.treeish + |
| 108 | " | tar -x -C util/" + tmpdir_basename, |
| 109 | shell=True) |
| 110 | |
| 111 | # Execute commands for working tree, saving output |
| 112 | os.chdir(util_path) |
| 113 | newoutdir = os.path.join(tmpdir, "newout") |
| 114 | os.mkdir(newoutdir) |
| 115 | generate_output(newoutdir, args.verbose) |
| 116 | |
| 117 | # Execute commands for previous revision, saving output |
| 118 | os.chdir(os.path.join(tmpdir_basename, "util")) |
| 119 | oldoutdir = os.path.join(tmpdir, "oldout") |
| 120 | os.mkdir(oldoutdir) |
| 121 | generate_output(oldoutdir, args.verbose) |
| 122 | |
| 123 | # Show diff (if any) |
| 124 | os.chdir(tmpdir) |
| 125 | # Don't use a checked call because the exit code indicates whether there |
| 126 | # is a diff or not, rather than indicating error. |
| 127 | subprocess.call('git diff -p --stat --no-index oldout newout', |
| 128 | shell=True) |
| 129 | |
| 130 | |
| 131 | if __name__ == "__main__": |
| 132 | main() |