mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
tools/docs/get_feat.py: convert get_feat.pl to Python
As we want to call Python code directly at the Sphinx extension, convert get_feat.pl to Python. The code was made to be (almost) bug-compatible with the Perl version, with two exceptions: 1. Currently, Perl script outputs a wrong table if arch is set to a non-existing value; 2. the ReST table output when --feat is used without --arch has an invalid format, as the number of characters for the table delimiters are wrong. Those two bugs were fixed while testing the conversion. Additionally, another caveat was solved: the output when --feat is used without arch and the feature doesn't exist doesn't contain an empty table anymore. Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> Signed-off-by: Jonathan Corbet <corbet@lwn.net> Message-ID: <03c26cee1ec567804735a33047e625ef5ab7bfa8.1763492868.git.mchehab+huawei@kernel.org>
This commit is contained in:
committed by
Jonathan Corbet
parent
55fb2d5726
commit
caa642bf3b
225
tools/docs/get_feat.py
Executable file
225
tools/docs/get_feat.py
Executable file
@@ -0,0 +1,225 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user