Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
check_clang_tidy.py
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file check_clang_tidy.py
1 #!/usr/bin/env python3
2 import argparse
3 import sys
4 from pathlib import Path
5 import json
6 import itertools
7 import fnmatch
8 import re
9 
10 import yaml
11 from rich.console import Console, Group
12 from rich.text import Text
13 from rich.panel import Panel
14 from rich.rule import Rule
15 from rich.emoji import Emoji
16 from rich.table import Table
17 
18 
19 from item import Item, ItemCollection
20 
21 
22 def main():
23  p = argparse.ArgumentParser()
24  p.add_argument("--report", type=Path, required=True)
25  p.add_argument("--config", type=Path, required=True)
26  p.add_argument("--strip-prefix-path", type=Path)
27 
28  args = p.parse_args()
29 
30  console = Console()
31 
32  with args.config.open() as fh:
33  config = yaml.safe_load(fh)
34 
35  data = []
36  with args.report.open() as fh:
37  data = ItemCollection(__root__=json.load(fh)).__root__
38  for item in data:
39  if args.strip_prefix_path and not item.path.is_absolute:
40  item.path = item.path.relative_to(args.strip_prefix_path)
41 
42  counts = config["limits"].copy()
43 
44  kf = lambda i: i.path
45  for file, items in itertools.groupby(sorted(data, key=kf), key=kf):
46 
47  output = []
48  for item in items:
49 
50  emoji = Emoji(
51  {"warning": "yellow_circle", "error": "red_circle"}[item.severity]
52  )
53 
54  style = "bold "
55  if item.severity == "warning":
56  style += "yellow"
57  elif item.severity == "error":
58  style += "red"
59 
60  s = Text()
61  s.append(f"{emoji}")
62  s.append(f" {item.path}:{item.line}:{item.col}", style="bold")
63  s.append(f" {item.severity.upper()} ", style=style)
64  s.append("[")
65  s.append(item.code, style="bold")
66  s.append(f"]")
67 
68  def subpath(m):
69  return f"[bold]{m.group(1)}[/bold]:"
70 
71  message = re.sub(r"([\w/.\-+]+:\d+:\d+):", subpath, item.message)
72 
73  accounted_for = False
74  for pattern in config["limits"].keys():
75 
76  if not fnmatch.fnmatch(item.code, pattern):
77  continue
78  counts[pattern] += 1
79  accounted_for = True
80 
81  if accounted_for:
82  output.append(s)
83  output.append(Panel(message))
84  output.append(Rule())
85  pass
86  else:
87  counts.setdefault(item.code, 0)
88  counts[item.code] += 1
89 
90  # output = output[:-1]
91  if len(output) > 0:
92  console.print(Panel(Group(*output), title=str(file)))
93 
94  table = Table()
95  table.add_column("", width=2)
96  table.add_column("code / pattern")
97  table.add_column("count", justify="right")
98  table.add_column("limit", justify="right")
99  exit = 0
100  for pattern, count in counts.items():
101  limit = config["limits"].get(pattern, float("inf"))
102  emoji = Emoji("green_circle")
103  style = "green"
104  if limit == float("inf"):
105  emoji = Emoji("white_circle")
106  style = "white"
107  elif count > limit:
108  exit = 1
109  emoji = Emoji("red_circle")
110  style = "red bold"
111  table.add_row(emoji, pattern, str(count), str(limit), style=style)
112 
113  console.rule()
114  console.print(Panel.fit(table, title="Results"), justify="center")
115 
116  if exit != 0:
117  console.print(
118  Panel(
119  Text(f"{Emoji('red_circle')} FAILURE", justify="center"),
120  style="red bold",
121  )
122  )
123  else:
124  console.print(
125  Panel(
126  Text(f"{Emoji('green_circle')} SUCCESS", justify="center"),
127  style="green bold",
128  )
129  )
130 
131  sys.exit(exit)
132 
133 
134 if "__main__" == __name__:
135  main()