blob: c8f19dfb4db770d422231abf8c3765ae560d3f26 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001#!/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
6tree versus a previous revision (HEAD by default). This makes it easy to
7inspect the impact of modifications to either the utility implementation or
8its input files on the generated output (e.g. HTML).
9"""
10
11import argparse
12import os
13import shlex
14import subprocess
15import sys
16import tempfile
17
18from 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
25testlist = [
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ölfel4c5fbec2019-10-23 12:43:17 +020043 "./regtool.py -r -t ", " ../hw/ip/uart/data/uart.hjson"],
lowRISC Contributors802543a2019-08-31 12:12:56 +010044 ["uart_dv", True,
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +020045 "./regtool.py -s -t ", " ../hw/ip/uart/data/uart.hjson"],
lowRISC Contributors802543a2019-08-31 12:12:56 +010046 # 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ölfel4c5fbec2019-10-23 12:43:17 +020067 "./regtool.py -D ../hw/ip/uart/data/uart.hjson > ", ""],
lowRISC Contributors802543a2019-08-31 12:12:56 +010068 ["gpio.h", False,
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +020069 "./regtool.py -D ../hw/ip/gpio/data/gpio.hjson > ", ""],
lowRISC Contributors802543a2019-08-31 12:12:56 +010070 ["spi_device.h", False,
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +020071 "./regtool.py -D ../hw/ip/spi_device/data/spi_device.hjson > ", ""]
lowRISC Contributors802543a2019-08-31 12:12:56 +010072] # yapf: disable
73
74
75def 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
99def 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
164if __name__ == "__main__":
165 main()