| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 |
|
| 6 | |
| 7 | Parse ABI documentation and produce results from it.
|
| 8 |
|
| 9 |
|
| 10 | import argparse
|
| 11 | import logging
|
| 12 | import os
|
| 13 | import sys
|
| 14 |
|
| 15 | |
| 16 |
|
| 17 | LIB_DIR = "../lib/python"
|
| 18 | SRC_DIR = os.path.dirname(os.path.realpath(__file__))
|
| 19 |
|
| 20 | sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
|
| 21 |
|
| 22 | from abi.abi_parser import AbiParser |
| 23 | from abi.abi_regex import AbiRegex |
| 24 | from abi.helpers import ABI_DIR, DEBUG_HELP |
| 25 | from abi.system_symbols import SystemSymbols |
| 26 |
|
| 27 | |
| 28 |
|
| 29 |
|
| 30 | REST_DESC = """
|
| 31 | Produce output in ReST format.
|
| 32 |
|
| 33 | The output is done on two sections:
|
| 34 |
|
| 35 | - Symbols: show all parsed symbols in alphabetic order;
|
| 36 | - Files: cross reference the content of each file with the symbols on it.
|
| 37 | """
|
| 38 |
|
| 39 | class AbiRest:
|
| 40 |
|
| 41 |
|
| 42 | def __init__(self, subparsers):
|
| 43 |
|
| 44 |
|
| 45 | parser = subparsers.add_parser("rest",
|
| 46 | formatter_class=argparse.RawTextHelpFormatter,
|
| 47 | description=REST_DESC)
|
| 48 |
|
| 49 | parser.add_argument("--enable-lineno", action="store_true",
|
| 50 | help="enable lineno")
|
| 51 | parser.add_argument("--raw", action="store_true",
|
| 52 | help="output text as contained in the ABI files. "
|
| 53 | "It not used, output will contain dynamically"
|
| 54 | " generated cross references when possible.")
|
| 55 | parser.add_argument("--no-file", action="store_true",
|
| 56 | help="Don't the files section")
|
| 57 | parser.add_argument("--show-hints", help="Show-hints")
|
| 58 |
|
| 59 | parser.set_defaults(func=self.run)
|
| 60 |
|
| 61 | def run(self, args):
|
| 62 |
|
| 63 |
|
| 64 | parser = AbiParser(args.dir, debug=args.debug)
|
| 65 | parser.parse_abi()
|
| 66 | parser.check_issues()
|
| 67 |
|
| 68 | for t in parser.doc(args.raw, not args.no_file):
|
| 69 | if args.enable_lineno:
|
| 70 | print (f".. LINENO {t[1]}#{t[2]}\n\n")
|
| 71 |
|
| 72 | print(t[0])
|
| 73 |
|
| 74 | class AbiValidate:
|
| 75 |
|
| 76 |
|
| 77 | def __init__(self, subparsers):
|
| 78 |
|
| 79 |
|
| 80 | parser = subparsers.add_parser("validate",
|
| 81 | formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
| 82 | description="list events")
|
| 83 |
|
| 84 | parser.set_defaults(func=self.run)
|
| 85 |
|
| 86 | def run(self, args):
|
| 87 |
|
| 88 |
|
| 89 | parser = AbiParser(args.dir, debug=args.debug)
|
| 90 | parser.parse_abi()
|
| 91 | parser.check_issues()
|
| 92 |
|
| 93 |
|
| 94 | class AbiSearch:
|
| 95 |
|
| 96 |
|
| 97 | def __init__(self, subparsers):
|
| 98 |
|
| 99 |
|
| 100 | parser = subparsers.add_parser("search",
|
| 101 | formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
| 102 | description="Search ABI using a regular expression")
|
| 103 |
|
| 104 | parser.add_argument("expression",
|
| 105 | help="Case-insensitive search pattern for the ABI symbol")
|
| 106 |
|
| 107 | parser.set_defaults(func=self.run)
|
| 108 |
|
| 109 | def run(self, args):
|
| 110 |
|
| 111 |
|
| 112 | parser = AbiParser(args.dir, debug=args.debug)
|
| 113 | parser.parse_abi()
|
| 114 | parser.search_symbols(args.expression)
|
| 115 |
|
| 116 | UNDEFINED_DESC="""
|
| 117 | Check undefined ABIs on local machine.
|
| 118 |
|
| 119 | Read sysfs devnodes and check if the devnodes there are defined inside
|
| 120 | ABI documentation.
|
| 121 |
|
| 122 | The search logic tries to minimize the number of regular expressions to
|
| 123 | search per each symbol.
|
| 124 |
|
| 125 | By default, it runs on a single CPU, as Python support for CPU threads
|
| 126 | is still experimental, and multi-process runs on Python is very slow.
|
| 127 |
|
| 128 | On experimental tests, if the number of ABI symbols to search per devnode
|
| 129 | is contained on a limit of ~150 regular expressions, using a single CPU
|
| 130 | is a lot faster than using multiple processes. However, if the number of
|
| 131 | regular expressions to check is at the order of ~30000, using multiple
|
| 132 | CPUs speeds up the check.
|
| 133 | """
|
| 134 |
|
| 135 | class AbiUndefined:
|
| 136 | |
| 137 | Initialize an argparse subparser for logic to check undefined ABI at
|
| 138 | the current machine's sysfs
|
| 139 |
|
| 140 |
|
| 141 | def __init__(self, subparsers):
|
| 142 |
|
| 143 |
|
| 144 | parser = subparsers.add_parser("undefined",
|
| 145 | formatter_class=argparse.RawTextHelpFormatter,
|
| 146 | description=UNDEFINED_DESC)
|
| 147 |
|
| 148 | parser.add_argument("-S", "--sysfs-dir", default="/sys",
|
| 149 | help="directory where sysfs is mounted")
|
| 150 | parser.add_argument("-s", "--search-string",
|
| 151 | help="search string regular expression to limit symbol search")
|
| 152 | parser.add_argument("-H", "--show-hints", action="store_true",
|
| 153 | help="Hints about definitions for missing ABI symbols.")
|
| 154 | parser.add_argument("-j", "--jobs", "--max-workers", type=int, default=1,
|
| 155 | help="If bigger than one, enables multiprocessing.")
|
| 156 | parser.add_argument("-c", "--max-chunk-size", type=int, default=50,
|
| 157 | help="Maximum number of chunk size")
|
| 158 | parser.add_argument("-f", "--found", action="store_true",
|
| 159 | help="Also show found items. "
|
| 160 | "Helpful to debug the parser."),
|
| 161 | parser.add_argument("-d", "--dry-run", action="store_true",
|
| 162 | help="Don't actually search for undefined. "
|
| 163 | "Helpful to debug the parser."),
|
| 164 |
|
| 165 | parser.set_defaults(func=self.run)
|
| 166 |
|
| 167 | def run(self, args):
|
| 168 |
|
| 169 |
|
| 170 | abi = AbiRegex(args.dir, debug=args.debug,
|
| 171 | search_string=args.search_string)
|
| 172 |
|
| 173 | abi_symbols = SystemSymbols(abi=abi, hints=args.show_hints,
|
| 174 | sysfs=args.sysfs_dir)
|
| 175 |
|
| 176 | abi_symbols.check_undefined_symbols(dry_run=args.dry_run,
|
| 177 | found=args.found,
|
| 178 | max_workers=args.jobs,
|
| 179 | chunk_size=args.max_chunk_size)
|
| 180 |
|
| 181 |
|
| 182 | def main():
|
| 183 |
|
| 184 |
|
| 185 | parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
|
| 186 |
|
| 187 | parser.add_argument("-d", "--debug", type=int, default=0, help="debug level")
|
| 188 | parser.add_argument("-D", "--dir", default=ABI_DIR, help=DEBUG_HELP)
|
| 189 |
|
| 190 | subparsers = parser.add_subparsers()
|
| 191 |
|
| 192 | AbiRest(subparsers)
|
| 193 | AbiValidate(subparsers)
|
| 194 | AbiSearch(subparsers)
|
| 195 | AbiUndefined(subparsers)
|
| 196 |
|
| 197 | args = parser.parse_args()
|
| 198 |
|
| 199 | if args.debug:
|
| 200 | level = logging.DEBUG
|
| 201 | else:
|
| 202 | level = logging.INFO
|
| 203 |
|
| 204 | logging.basicConfig(level=level, format="[%(levelname)s] %(message)s")
|
| 205 |
|
| 206 | if "func" in args:
|
| 207 | args.func(args)
|
| 208 | else:
|
| 209 | sys.exit(f"Please specify a valid command for {sys.argv[0]}")
|
| 210 |
|
| 211 |
|
| 212 | |
| 213 | if __name__ == "__main__":
|
| 214 | main()
|