1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 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()
|