Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:34

0001 #!/usr/bin/env python3
0002 """
0003 This script accepts a cmake lists file as an argument extracts all
0004 `option` and `set(... CACHE ...)` variables. It then writes a
0005 markdown table to stdout
0006 """
0007 
0008 import argparse
0009 from pathlib import Path
0010 import re
0011 import textwrap
0012 import sys
0013 import difflib
0014 
0015 p = argparse.ArgumentParser(description=__doc__)
0016 
0017 p.add_argument("cmakefile", help="Input cmake lists file to parse")
0018 p.add_argument(
0019     "--prefix", default="ACTS_", help="Prefix to identify relevant variables to extract"
0020 )
0021 p.add_argument(
0022     "--width",
0023     type=int,
0024     default=40,
0025     help="Width of second column generated from cmake doc strings",
0026 )
0027 p.add_argument(
0028     "--write",
0029     "-w",
0030     help="Write table to this file, expects delimiters CMAKE_OPTS_{BEGIN,END}",
0031     type=Path,
0032 )
0033 p.add_argument(
0034     "--verify",
0035     "-v",
0036     help="Only verify the target file contains the right table, don't write",
0037     action="store_true",
0038 )
0039 
0040 
0041 args = p.parse_args()
0042 
0043 cmakefile = Path(args.cmakefile)
0044 
0045 with cmakefile.open() as fh:
0046     opts = {}
0047     rows = []
0048     for line in fh:
0049         if m := re.match(
0050             rf"option\( *({args.prefix}\w*) \"(.*)\" (ON|OFF|\${{.+}})\ *\) ?(?:# (.*))?.*",
0051             line,
0052         ):
0053             name, doc, default, comment = m.groups()
0054             # manual default override mechanism
0055             if comment is not None and comment.strip().startswith("default:"):
0056                 default = comment.strip().split("default:")[1].strip()
0057 
0058             type = "bool"
0059             if m := re.match(r"\${(\w+)}", default):
0060                 lookup = m.group(1)
0061                 if lookup in opts:
0062                     default = f"{lookup} -> {opts[lookup]}"
0063         elif m := re.match(
0064             rf"set\( *({args.prefix}\w*) \"(.*)\" CACHE (\w+) \"(.*)\"( FORCE)? *\)",
0065             line,
0066         ):
0067             name, default, type, doc, _ = m.groups()
0068             type = type.lower()
0069             if default == "":
0070                 default = '""'
0071         else:
0072             continue
0073 
0074         opts[name] = default
0075         doc = "<br>".join(textwrap.wrap(doc, width=args.width))
0076         rows.append((name, f"{doc}<br> type: `{type}`, default: `{default}`"))
0077 
0078 output = ""
0079 
0080 headers = ("Option", "Description")
0081 column_lengths = [0] * len(rows[0])
0082 
0083 for row in rows:
0084     for i, col in enumerate(row):
0085         column_lengths[i] = max(column_lengths[i], len(col))
0086 
0087 output += "|"
0088 for i, header in enumerate(headers):
0089     output += " " + header.ljust(column_lengths[i]) + " |"
0090 output += "\n"
0091 
0092 output += "|"
0093 for i in range(len(column_lengths)):
0094     output += "-" + ("-" * column_lengths[i]) + "-|"
0095 output += "\n"
0096 
0097 
0098 for row in rows:
0099     output += "|"
0100     for i, col in enumerate(row):
0101         output += " " + col.ljust(column_lengths[i]) + " |"
0102     output += "\n"
0103 
0104 output = output.strip()
0105 
0106 if args.write and args.write.exists():
0107     source = args.write.read_text().split("\n")
0108     try:
0109         begin = source.index("<!-- CMAKE_OPTS_BEGIN -->")
0110         end = source.index("<!-- CMAKE_OPTS_END -->")
0111     except ValueError:
0112         print("Markers not found in output file")
0113         sys.exit(1)
0114 
0115     if args.verify:
0116         actual = "\n".join(source[begin + 1 : end])
0117         if output != actual:
0118             print("MISMATCH:\n" + "-" * 9 + "\n")
0119             print(
0120                 "\n".join(
0121                     difflib.unified_diff(
0122                         actual.split("\n"),
0123                         output.split("\n"),
0124                         fromfile="actual",
0125                         tofile="output",
0126                     )
0127                 )
0128             )
0129             sys.exit(1)
0130     elif args.write:
0131         out = source[: begin + 1] + output.split("\n") + source[end:]
0132         args.write.write_text("\n".join(out))
0133 else:
0134     print(output)