| #!/usr/bin/env python3 |
| # pylint: disable=R0902,R0911,R0912,R0914,R0915 |
| # Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>. |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| |
| """ |
| Parse the Linux Feature files and produce a ReST book. |
| """ |
| |
| import argparse |
| import os |
| import subprocess |
| import sys |
| |
| from pprint import pprint |
| |
| LIB_DIR = "../../tools/lib/python" |
| SRC_DIR = os.path.dirname(os.path.realpath(__file__)) |
| |
| sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR)) |
| |
| from feat.parse_features import ParseFeature # pylint: disable=C0413 |
| |
| SRCTREE = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../..") |
| DEFAULT_DIR = "Documentation/features" |
| |
| |
| class GetFeature: |
| """Helper class to parse feature parsing parameters""" |
| |
| @staticmethod |
| def get_current_arch(): |
| """Detects the current architecture""" |
| |
| proc = subprocess.run(["uname", "-m"], check=True, |
| capture_output=True, text=True) |
| |
| arch = proc.stdout.strip() |
| if arch in ["x86_64", "i386"]: |
| arch = "x86" |
| elif arch == "s390x": |
| arch = "s390" |
| |
| return arch |
| |
| def run_parser(self, args): |
| """Execute the feature parser""" |
| |
| feat = ParseFeature(args.directory, args.debug, args.enable_fname) |
| data = feat.parse() |
| |
| if args.debug > 2: |
| pprint(data) |
| |
| return feat |
| |
| def run_rest(self, args): |
| """ |
| Generate tables in ReST format. Three types of tables are |
| supported, depending on the calling arguments: |
| |
| - neither feature nor arch is passed: generates a full matrix; |
| - arch provided: generates a table of supported tables for the |
| guiven architecture, eventually filtered by feature; |
| - only feature provided: generates a table with feature details, |
| showing what architectures it is implemented. |
| """ |
| |
| feat = self.run_parser(args) |
| |
| if args.arch: |
| rst = feat.output_arch_table(args.arch, args.feat) |
| elif args.feat: |
| rst = feat.output_feature(args.feat) |
| else: |
| rst = feat.output_matrix() |
| |
| print(rst) |
| |
| def run_current(self, args): |
| """ |
| Instead of using a --arch parameter, get feature for the current |
| architecture. |
| """ |
| |
| args.arch = self.get_current_arch() |
| |
| self.run_rest(args) |
| |
| def run_list(self, args): |
| """ |
| Generate a list of features for a given architecture, in a format |
| parseable by other scripts. The output format is not ReST. |
| """ |
| |
| if not args.arch: |
| args.arch = self.get_current_arch() |
| |
| feat = self.run_parser(args) |
| msg = feat.list_arch_features(args.arch, args.feat) |
| |
| print(msg) |
| |
| def parse_arch(self, parser): |
| """Add a --arch parsing argument""" |
| |
| parser.add_argument("--arch", |
| help="Output features for an specific" |
| " architecture, optionally filtering for a " |
| "single specific feature.") |
| |
| def parse_feat(self, parser): |
| """Add a --feat parsing argument""" |
| |
| parser.add_argument("--feat", "--feature", |
| help="Output features for a single specific " |
| "feature.") |
| |
| |
| def current_args(self, subparsers): |
| """Implementscurrent argparse subparser""" |
| |
| parser = subparsers.add_parser("current", |
| formatter_class=argparse.RawTextHelpFormatter, |
| description="Output table in ReST " |
| "compatible ASCII format " |
| "with features for this " |
| "machine's architecture") |
| |
| self.parse_feat(parser) |
| parser.set_defaults(func=self.run_current) |
| |
| def rest_args(self, subparsers): |
| """Implement rest argparse subparser""" |
| |
| parser = subparsers.add_parser("rest", |
| formatter_class=argparse.RawTextHelpFormatter, |
| description="Output table(s) in ReST " |
| "compatible ASCII format " |
| "with features in ReST " |
| "markup language. The " |
| "output is affected by " |
| "--arch or --feat/--feature" |
| " flags.") |
| |
| self.parse_arch(parser) |
| self.parse_feat(parser) |
| parser.set_defaults(func=self.run_rest) |
| |
| def list_args(self, subparsers): |
| """Implement list argparse subparser""" |
| |
| parser = subparsers.add_parser("list", |
| formatter_class=argparse.RawTextHelpFormatter, |
| description="List features for this " |
| "machine's architecture, " |
| "using an easier to parse " |
| "format. The output is " |
| "affected by --arch flag.") |
| |
| self.parse_arch(parser) |
| self.parse_feat(parser) |
| parser.set_defaults(func=self.run_list) |
| |
| def validate_args(self, subparsers): |
| """Implement validate argparse subparser""" |
| |
| parser = subparsers.add_parser("validate", |
| formatter_class=argparse.RawTextHelpFormatter, |
| description="Validate the contents of " |
| "the files under " |
| f"{DEFAULT_DIR}.") |
| |
| parser.set_defaults(func=self.run_parser) |
| |
| def parser(self): |
| """ |
| Create an arparse with common options and several subparsers |
| """ |
| parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) |
| |
| parser.add_argument("-d", "--debug", action="count", default=0, |
| help="Put the script in verbose mode, useful for " |
| "debugging. Can be called multiple times, to " |
| "increase verbosity.") |
| |
| parser.add_argument("--directory", "--dir", default=DEFAULT_DIR, |
| help="Changes the location of the Feature files. " |
| f"By default, it uses the {DEFAULT_DIR} " |
| "directory.") |
| |
| parser.add_argument("--enable-fname", action="store_true", |
| help="Prints the file name of the feature files. " |
| "This can be used in order to track " |
| "dependencies during documentation build.") |
| |
| subparsers = parser.add_subparsers() |
| |
| self.current_args(subparsers) |
| self.rest_args(subparsers) |
| self.list_args(subparsers) |
| self.validate_args(subparsers) |
| |
| args = parser.parse_args() |
| |
| return args |
| |
| |
| def main(): |
| """Main program""" |
| |
| feat = GetFeature() |
| |
| args = feat.parser() |
| |
| 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() |