Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:09:26

0001 #!/usr/bin/env python3
0002 import argparse
0003 import os
0004 from glob import glob
0005 import re
0006 from fnmatch import fnmatch
0007 import sys
0008 
0009 
0010 def line_fmt(line):
0011     return "{: >4d} ".format(line)
0012 
0013 
0014 def code_print(code, start, maxlines=15):
0015     lines = code.split("\n")
0016     nlines = len(lines)
0017 
0018     lines = [line_fmt(i + start) + l for i, l in enumerate(lines)]
0019 
0020     nlup = int(maxlines / 2)
0021     nllo = maxlines - nlup - 1
0022 
0023     if nlines > maxlines:
0024         lines = lines[:nlup] + [" " * 5 + "// ..."] + lines[-nllo:]
0025 
0026     return "\n".join(lines)
0027 
0028 
0029 def check_include_guards(file):
0030     with open(file) as f:
0031         text = f.read()
0032 
0033     match_local = list(
0034         re.finditer(
0035             r"(#ifndef [A-Za-z0-9_]*\n#define [A-Za-z0-9_]*.*)\n((:?.|\n)+?)#endif",
0036             text,
0037         )
0038     )
0039     match_global = re.search(
0040         r"#ifndef (.*)\n#define \1.*\n[\s\S]+#endif[A-Za-z0-9\-_/* ]*$", text
0041     )
0042 
0043     valid_global = True
0044     valid_local = True
0045     errbuf = ""
0046 
0047     if match_global is not None and len(match_local) <= 1:
0048         valid_global = False
0049 
0050         errbuf += "This looks like a file-spanning include guard\n"
0051         errbuf += "This is discouraged as per [ACTS-450]"
0052         errbuf += "(https://its.cern.ch/jira/browse/ACTS-450)" + "\n" * 2
0053 
0054         start = text[: match_global.start()].count("\n") + 1
0055         errbuf += code_print(match_global.group(0), start)
0056         errbuf += "\n" * 2
0057 
0058     if valid_global or len(match_local) > 1:
0059         for m in match_local:
0060             lineno = text[: m.start()].count("\n") + 1
0061 
0062             valid_local = False
0063             errbuf += "This looks like a local #ifndef / include-guard\n"
0064             errbuf += "This is discouraged as per [ACTS-450]"
0065             errbuf += "(https://its.cern.ch/jira/browse/ACTS-450)" + "\n" * 2
0066             errbuf += code_print(m.group(0), lineno)
0067             errbuf += "\n" * 2
0068 
0069     return valid_local, valid_global, errbuf
0070 
0071 
0072 def main():
0073     p = argparse.ArgumentParser()
0074 
0075     input_help = """
0076 Input files: either file path, dir path (will glob for headers) or custom glob pattern
0077     """
0078     p.add_argument("input", help=input_help.strip())
0079     p.add_argument(
0080         "--fail-local", "-l", action="store_true", help="Fail on local include guards"
0081     )
0082     p.add_argument(
0083         "--fail-global", "-g", action="store_true", help="Fail on global include guards"
0084     )
0085     p.add_argument("--quiet-local", "-ql", action="store_true")
0086     p.add_argument("--quiet-global", "-qg", action="store_true")
0087     p.add_argument("--exclude", "-e", action="append", default=[])
0088 
0089     args = p.parse_args()
0090 
0091     headers = []
0092 
0093     if os.path.isfile(args.input):
0094         headers = [args.input]
0095     elif os.path.isdir(args.input):
0096         patterns = ["**/*.hpp", "**/*.h"]
0097         headers = sum(
0098             [glob(os.path.join(args.input, p), recursive=True) for p in patterns], []
0099         )
0100     else:
0101         headers = glob(args.input, recursive=True)
0102 
0103     valid = True
0104     nlocal = 0
0105     nglobal = 0
0106 
0107     for h in headers:
0108         if any([fnmatch(h, e) for e in args.exclude]):
0109             continue
0110         valid_local, valid_global, errbuf = check_include_guards(h)
0111 
0112         if not valid_local:
0113             nlocal += 1
0114             if args.fail_local:
0115                 valid = False
0116         if not valid_global:
0117             nglobal += 1
0118             if args.fail_global:
0119                 valid = False
0120 
0121         if not valid_local or not valid_global:
0122             head = "Issue(s) in file {}:\n".format(h)
0123             print("-" * len(head))
0124             print(head)
0125             print(errbuf)
0126             print("\n")
0127 
0128     print("=" * 40)
0129     print("Checked {} files".format(len(headers)))
0130     print("Issues found in {} files".format(nlocal + nglobal))
0131     print("{} files have local include guards".format(nlocal))
0132     print("{} files have global include guards".format(nglobal))
0133 
0134     if valid:
0135         sys.exit(0)
0136     else:
0137         sys.exit(1)
0138 
0139 
0140 if "__main__" == __name__:
0141     main()