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()
|