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 = [ |
| 26 | ["eguart.html", False, |
| 27 | "./docgen.py docgen/examples/uart.md > ", ""], |
| 28 | ["eguartcfg.html", False, |
| 29 | "./docgen.py docgen/examples/uartcfg.md > ", ""], |
| 30 | ["uart.html", False, |
| 31 | "./docgen.py ../hw/ip/uart/doc/uart.md > ", ""], |
| 32 | ["uart-d.html", False, |
| 33 | "./docgen.py -d docgen/examples/uart.md > ", ""], |
| 34 | ["uart16550-j.html", False, |
| 35 | "./docgen.py -j docgen/examples/uart16550.md > ", ""], |
| 36 | ["uart16550.html", False, |
| 37 | "./docgen.py docgen/examples/uart16550.md > ", ""], |
| 38 | ["regdoc.md", False, |
| 39 | "./regtool.py --doc > ", ""], |
| 40 | ["wave.html", False, |
| 41 | "./wavetool.py wavegen/examples/* > ", ""], |
| 42 | ["uart_rtl", True, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 43 | "./regtool.py -r -t ", " ../hw/ip/uart/data/uart.hjson"], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 44 | ["uart_dv", True, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 45 | "./regtool.py -s -t ", " ../hw/ip/uart/data/uart.hjson"], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 46 | # gp test multireg |
| 47 | ["gp.html", False, |
| 48 | "./docgen.py docgen/examples/gp.md > ", ""], |
| 49 | ["gp_rtl", True, |
| 50 | "./regtool.py -r -t ", " docgen/examples/gp.hjson"], |
| 51 | ["gp_dv", True, |
| 52 | "./regtool.py -s -t ", " docgen/examples/gp.hjson"], |
| 53 | # errors tests error detection |
| 54 | ["errors.html", False, |
| 55 | "./docgen.py docgen/examples/errors.md > ", ""], |
| 56 | # window tests |
| 57 | ["window.html", False, |
| 58 | "./docgen.py docgen/examples/test_win.md > ", ""], |
| 59 | # include tests |
| 60 | ["includes.html", False, |
| 61 | "./docgen.py docgen/examples/test_inc.md > ", ""], |
| 62 | # bad write enable tests |
| 63 | ["badwen.html", False, |
| 64 | "./docgen.py docgen/examples/badwen.md > ", ""], |
| 65 | # generating include define headers |
| 66 | ["uart.h", False, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 67 | "./regtool.py -D ../hw/ip/uart/data/uart.hjson > ", ""], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 68 | ["gpio.h", False, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 69 | "./regtool.py -D ../hw/ip/gpio/data/gpio.hjson > ", ""], |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 70 | ["spi_device.h", False, |
Tobias Wölfel | 4c5fbec | 2019-10-23 12:43:17 +0200 | [diff] [blame] | 71 | "./regtool.py -D ../hw/ip/spi_device/data/spi_device.hjson > ", ""] |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 72 | ] # yapf: disable |
| 73 | |
| 74 | |
| 75 | def generate_output(outdir, verbose): |
| 76 | for t in testlist: |
| 77 | out = shlex.quote(os.path.join(outdir, t[0])) |
| 78 | if t[1]: |
| 79 | # in new tmpdir so the directory should never be there already |
| 80 | os.mkdir(out) |
| 81 | errors_out = open(out + ".STDERR", 'w', encoding='UTF-8') |
| 82 | with errors_out: |
| 83 | err = subprocess.call(t[2] + out + t[3], |
| 84 | stderr=errors_out, |
| 85 | shell=True) |
| 86 | # write a file so it pops up in the diff |
| 87 | # if it is different |
| 88 | # (i.e. won't mention any that always return same error) |
| 89 | if err != 0: |
| 90 | rtn_out = open(out + ".RETURN", 'w', encoding='UTF-8') |
| 91 | with rtn_out: |
| 92 | rtn_out.write("Non-Zero Return code " + str(err) + "\n") |
| 93 | |
| 94 | # useful for debug: |
| 95 | if (verbose): |
| 96 | subprocess.call("ls -l " + outdir, shell=True) |
| 97 | |
| 98 | |
| 99 | def main(): |
| 100 | parser = argparse.ArgumentParser( |
| 101 | description=__doc__, |
| 102 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| 103 | parser.add_argument("treeish", |
| 104 | default="HEAD", |
| 105 | nargs="?", |
| 106 | help="git tree or commit to compare against") |
| 107 | parser.add_argument('--version', |
| 108 | action='store_true', |
| 109 | help='Show version and exit') |
| 110 | parser.add_argument('-v', |
| 111 | '--verbose', |
| 112 | action='store_true', |
| 113 | help='Verbose output: ls the output directories') |
| 114 | |
| 115 | args = parser.parse_args() |
| 116 | if args.version: |
| 117 | version.show_and_exit(__file__, []) |
| 118 | args.treeish = shlex.quote(args.treeish) |
| 119 | |
| 120 | util_path = os.path.dirname(os.path.realpath(__file__)) |
| 121 | repo_root = os.path.abspath(os.path.join(util_path, os.pardir)) |
| 122 | os.chdir(repo_root) |
| 123 | |
| 124 | if not os.path.isdir(os.path.join(repo_root, '.git')): |
| 125 | print("Script not in expected location in a git repo", file=sys.stderr) |
| 126 | sys.exit(1) |
| 127 | |
| 128 | # Exit early if there are no diffs between the working tree and |
| 129 | # args.treeish. |
| 130 | output = subprocess.check_output("git diff " + args.treeish, shell=True) |
| 131 | if not output: |
| 132 | sys.exit(0) |
| 133 | |
| 134 | # Create temporary directories in util_path rather than defaulting to /tmp. |
| 135 | # /tmp may be small and may may be mounted noexec. |
| 136 | tempfile.tempdir = util_path |
| 137 | |
| 138 | with tempfile.TemporaryDirectory() as tmpdir: |
| 139 | tmpdir_basename = os.path.basename(tmpdir) |
| 140 | subprocess.check_call("git archive " + args.treeish + |
| 141 | " | tar -x -C util/" + tmpdir_basename, |
| 142 | shell=True) |
| 143 | |
| 144 | # Execute commands for working tree, saving output |
| 145 | os.chdir(util_path) |
| 146 | newoutdir = os.path.join(tmpdir, "newout") |
| 147 | os.mkdir(newoutdir) |
| 148 | generate_output(newoutdir, args.verbose) |
| 149 | |
| 150 | # Execute commands for previous revision, saving output |
| 151 | os.chdir(os.path.join(tmpdir_basename, "util")) |
| 152 | oldoutdir = os.path.join(tmpdir, "oldout") |
| 153 | os.mkdir(oldoutdir) |
| 154 | generate_output(oldoutdir, args.verbose) |
| 155 | |
| 156 | # Show diff (if any) |
| 157 | os.chdir(tmpdir) |
| 158 | # Don't use a checked call because the exit code indicates whether there |
| 159 | # is a diff or not, rather than indicating error. |
| 160 | subprocess.call('git diff -p --stat --no-index oldout newout', |
| 161 | shell=True) |
| 162 | |
| 163 | |
| 164 | if __name__ == "__main__": |
| 165 | main() |