| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- #!/usr/bin/env python3
- # pylint: disable=R0903
- # Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
- # SPDX-License-Identifier: GPL-2.0
- """
- Parse ABI documentation and produce results from it.
- """
- import argparse
- import logging
- import os
- import sys
- # Import Python modules
- LIB_DIR = "../lib/python"
- SRC_DIR = os.path.dirname(os.path.realpath(__file__))
- sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
- from abi.abi_parser import AbiParser # pylint: disable=C0413
- from abi.abi_regex import AbiRegex # pylint: disable=C0413
- from abi.helpers import ABI_DIR, DEBUG_HELP # pylint: disable=C0413
- from abi.system_symbols import SystemSymbols # pylint: disable=C0413
- # Command line classes
- REST_DESC = """
- Produce output in ReST format.
- The output is done on two sections:
- - Symbols: show all parsed symbols in alphabetic order;
- - Files: cross reference the content of each file with the symbols on it.
- """
- class AbiRest:
- """Initialize an argparse subparser for rest output"""
- def __init__(self, subparsers):
- """Initialize argparse subparsers"""
- parser = subparsers.add_parser("rest",
- formatter_class=argparse.RawTextHelpFormatter,
- description=REST_DESC)
- parser.add_argument("--enable-lineno", action="store_true",
- help="enable lineno")
- parser.add_argument("--raw", action="store_true",
- help="output text as contained in the ABI files. "
- "It not used, output will contain dynamically"
- " generated cross references when possible.")
- parser.add_argument("--no-file", action="store_true",
- help="Don't the files section")
- parser.add_argument("--show-hints", help="Show-hints")
- parser.set_defaults(func=self.run)
- def run(self, args):
- """Run subparser"""
- parser = AbiParser(args.dir, debug=args.debug)
- parser.parse_abi()
- parser.check_issues()
- for t in parser.doc(args.raw, not args.no_file):
- if args.enable_lineno:
- print (f".. LINENO {t[1]}#{t[2]}\n\n")
- print(t[0])
- class AbiValidate:
- """Initialize an argparse subparser for ABI validation"""
- def __init__(self, subparsers):
- """Initialize argparse subparsers"""
- parser = subparsers.add_parser("validate",
- formatter_class=argparse.ArgumentDefaultsHelpFormatter,
- description="list events")
- parser.set_defaults(func=self.run)
- def run(self, args):
- """Run subparser"""
- parser = AbiParser(args.dir, debug=args.debug)
- parser.parse_abi()
- parser.check_issues()
- class AbiSearch:
- """Initialize an argparse subparser for ABI search"""
- def __init__(self, subparsers):
- """Initialize argparse subparsers"""
- parser = subparsers.add_parser("search",
- formatter_class=argparse.ArgumentDefaultsHelpFormatter,
- description="Search ABI using a regular expression")
- parser.add_argument("expression",
- help="Case-insensitive search pattern for the ABI symbol")
- parser.set_defaults(func=self.run)
- def run(self, args):
- """Run subparser"""
- parser = AbiParser(args.dir, debug=args.debug)
- parser.parse_abi()
- parser.search_symbols(args.expression)
- UNDEFINED_DESC="""
- Check undefined ABIs on local machine.
- Read sysfs devnodes and check if the devnodes there are defined inside
- ABI documentation.
- The search logic tries to minimize the number of regular expressions to
- search per each symbol.
- By default, it runs on a single CPU, as Python support for CPU threads
- is still experimental, and multi-process runs on Python is very slow.
- On experimental tests, if the number of ABI symbols to search per devnode
- is contained on a limit of ~150 regular expressions, using a single CPU
- is a lot faster than using multiple processes. However, if the number of
- regular expressions to check is at the order of ~30000, using multiple
- CPUs speeds up the check.
- """
- class AbiUndefined:
- """
- Initialize an argparse subparser for logic to check undefined ABI at
- the current machine's sysfs
- """
- def __init__(self, subparsers):
- """Initialize argparse subparsers"""
- parser = subparsers.add_parser("undefined",
- formatter_class=argparse.RawTextHelpFormatter,
- description=UNDEFINED_DESC)
- parser.add_argument("-S", "--sysfs-dir", default="/sys",
- help="directory where sysfs is mounted")
- parser.add_argument("-s", "--search-string",
- help="search string regular expression to limit symbol search")
- parser.add_argument("-H", "--show-hints", action="store_true",
- help="Hints about definitions for missing ABI symbols.")
- parser.add_argument("-j", "--jobs", "--max-workers", type=int, default=1,
- help="If bigger than one, enables multiprocessing.")
- parser.add_argument("-c", "--max-chunk-size", type=int, default=50,
- help="Maximum number of chunk size")
- parser.add_argument("-f", "--found", action="store_true",
- help="Also show found items. "
- "Helpful to debug the parser."),
- parser.add_argument("-d", "--dry-run", action="store_true",
- help="Don't actually search for undefined. "
- "Helpful to debug the parser."),
- parser.set_defaults(func=self.run)
- def run(self, args):
- """Run subparser"""
- abi = AbiRegex(args.dir, debug=args.debug,
- search_string=args.search_string)
- abi_symbols = SystemSymbols(abi=abi, hints=args.show_hints,
- sysfs=args.sysfs_dir)
- abi_symbols.check_undefined_symbols(dry_run=args.dry_run,
- found=args.found,
- max_workers=args.jobs,
- chunk_size=args.max_chunk_size)
- def main():
- """Main program"""
- parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
- parser.add_argument("-d", "--debug", type=int, default=0, help="debug level")
- parser.add_argument("-D", "--dir", default=ABI_DIR, help=DEBUG_HELP)
- subparsers = parser.add_subparsers()
- AbiRest(subparsers)
- AbiValidate(subparsers)
- AbiSearch(subparsers)
- AbiUndefined(subparsers)
- args = parser.parse_args()
- if args.debug:
- level = logging.DEBUG
- else:
- level = logging.INFO
- logging.basicConfig(level=level, format="[%(levelname)s] %(message)s")
- if "func" in args:
- args.func(args)
- else:
- sys.exit(f"Please specify a valid command for {sys.argv[0]}")
- # Call main method
- if __name__ == "__main__":
- main()
|