History

scripts: get_feat.pl: add a script to handle Documentation/features

The Documentation/features contains a set of parseable files. It is not worth converting them to ReST format, as they're useful the way it is. It is, however, interesting to parse them and produce output on different formats: 1) Output the contents of a feature in ReST format; 2) Output what features a given architecture supports; 3) Output a matrix with features x architectures.

Mauro Carvalho Chehab committed 5 years ago

Commit 52a4be31 parent 868770c1 file · +474 −0Browse files

Showing the changes to scripts (1 of 1 file). Show all

Unified · Split

scripts/get_feat.pl+474−0
@@ -0,0 +1,474 @@
1#!/usr/bin/perl
2# SPDX-License-Identifier: GPL-2.0
3
4use strict;
5use Pod::Usage;
6use Getopt::Long;
7use File::Find;
8use Fcntl ':mode';
9
10my $help;
11my $man;
12my $debug;
13my $arch;
14my $feat;
15my $prefix="Documentation/features";
16
17GetOptions(
18 "debug|d+" => \$debug,
19 "dir=s" => \$prefix,
20 'help|?' => \$help,
21 'arch=s' => \$arch,
22 'feat=s' => \$feat,
23 man => \$man
24) or pod2usage(2);
25
26pod2usage(1) if $help;
27pod2usage(-exitstatus => 0, -verbose => 2) if $man;
28
29pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
30
31my ($cmd, $arg) = @ARGV;
32
33pod2usage(2) if ($cmd ne "current" && $cmd ne "rest" && $cmd ne "validate");
34
35require Data::Dumper if ($debug);
36
37my %data;
38my %archs;
39
40#
41# Displays an error message, printing file name and line
42#
43sub parse_error($$$$) {
44 my ($file, $ln, $msg, $data) = @_;
45
46 $data =~ s/\s+$/\n/;
47
48 print STDERR "Warning: file $file#$ln:\n\t$msg";
49
50 if ($data ne "") {
51 print STDERR ". Line\n\t\t$data";
52 } else {
53 print STDERR "\n";
54 }
55}
56
57#
58# Parse a features file, storing its contents at %data
59#
60
61my $h_name = "Feature";
62my $h_kconfig = "Kconfig";
63my $h_description = "Description";
64my $h_subsys = "Subsystem";
65my $h_status = "Status";
66my $h_arch = "Architecture";
67
68my $max_size_name = length($h_name);
69my $max_size_kconfig = length($h_kconfig);
70my $max_size_description = length($h_description);
71my $max_size_subsys = length($h_subsys);
72my $max_size_status = length($h_status);
73my $max_size_arch = length($h_arch);
74
75sub parse_feat {
76 my $file = $File::Find::name;
77
78 my $mode = (stat($file))[2];
79 return if ($mode & S_IFDIR);
80 return if ($file =~ m,($prefix)/arch-support.txt,);
81 return if (!($file =~ m,arch-support.txt$,));
82
83 my $subsys = "";
84 $subsys = $2 if ( m,.*($prefix)/([^/]+).*,);
85
86 if (length($subsys) > $max_size_subsys) {
87 $max_size_subsys = length($subsys);
88 }
89
90 my $name;
91 my $kconfig;
92 my $description;
93 my $comments = "";
94 my $last_status;
95 my $ln;
96 my %arch_table;
97
98 print STDERR "Opening $file\n" if ($debug > 1);
99 open IN, $file;
100
101 while(<IN>) {
102 $ln++;
103
104 if (m/^\#\s+Feature\s+name:\s*(.*\S)/) {
105 $name = $1;
106 if (length($name) > $max_size_name) {
107 $max_size_name = length($name);
108 }
109 next;
110 }
111 if (m/^\#\s+Kconfig:\s*(.*\S)/) {
112 $kconfig = $1;
113 if (length($kconfig) > $max_size_kconfig) {
114 $max_size_kconfig = length($kconfig);
115 }
116 next;
117 }
118 if (m/^\#\s+description:\s*(.*\S)/) {
119 $description = $1;
120 if (length($description) > $max_size_description) {
121 $max_size_description = length($description);
122 }
123 next;
124 }
125 next if (m/^\\s*$/);
126 next if (m/^\s*\-+\s*$/);
127 next if (m/^\s*\|\s*arch\s*\|\s*status\s*\|\s*$/);
128
129 if (m/^\#\s*(.*)/) {
130 $comments .= "$1\n";
131 next;
132 }
133 if (m/^\s*\|\s*(\S+):\s*\|\s*(\S+)\s*\|\s*$/) {
134 my $a = $1;
135 my $status = $2;
136
137 if (length($status) > $max_size_status) {
138 $max_size_status = length($status);
139 }
140 if (length($a) > $max_size_arch) {
141 $max_size_arch = length($a);
142 }
143
144 $status = "---" if ($status =~ m/^\.\.$/);
145
146 $archs{$a} = 1;
147 $arch_table{$a} = $status;
148 next;
149 }
150
151 #Everything else is an error
152 parse_error($file, $ln, "line is invalid", $_);
153 }
154 close IN;
155
156 if (!$name) {
157 parse_error($file, $ln, "Feature name not found", "");
158 return;
159 }
160
161 parse_error($file, $ln, "Subsystem not found", "") if (!$subsys);
162 parse_error($file, $ln, "Kconfig not found", "") if (!$kconfig);
163 parse_error($file, $ln, "Description not found", "") if (!$description);
164
165 if (!%arch_table) {
166 parse_error($file, $ln, "Architecture table not found", "");
167 return;
168 }
169
170 $data{$name}->{where} = $file;
171 $data{$name}->{subsys} = $subsys;
172 $data{$name}->{kconfig} = $kconfig;
173 $data{$name}->{description} = $description;
174 $data{$name}->{comments} = $comments;
175 $data{$name}->{table} = \%arch_table;
176}
177
178#
179# Output feature(s) for a given architecture
180#
181sub output_arch_table {
182 my $title = "Feature status on $arch architecture";
183
184 print "=" x length($title) . "\n";
185 print "$title\n";
186 print "=" x length($title) . "\n\n";
187
188 print "=" x $max_size_subsys;
189 print " ";
190 print "=" x $max_size_name;
191 print " ";
192 print "=" x $max_size_kconfig;
193 print " ";
194 print "=" x $max_size_status;
195 print " ";
196 print "=" x $max_size_description;
197 print "\n";
198 printf "%-${max_size_subsys}s ", $h_subsys;
199 printf "%-${max_size_name}s ", $h_name;
200 printf "%-${max_size_kconfig}s ", $h_kconfig;
201 printf "%-${max_size_status}s ", $h_status;
202 printf "%-${max_size_description}s\n", $h_description;
203 print "=" x $max_size_subsys;
204 print " ";
205 print "=" x $max_size_name;
206 print " ";
207 print "=" x $max_size_kconfig;
208 print " ";
209 print "=" x $max_size_status;
210 print " ";
211 print "=" x $max_size_description;
212 print "\n";
213
214 foreach my $name (sort {
215 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) ||
216 ($data{$a}->{name} cmp $data{$b}->{name})
217 } keys %data) {
218 next if ($feat && $name ne $feat);
219
220 my %arch_table = %{$data{$name}->{table}};
221 printf "%-${max_size_subsys}s ", $data{$name}->{subsys};
222 printf "%-${max_size_name}s ", $name;
223 printf "%-${max_size_kconfig}s ", $data{$name}->{kconfig};
224 printf "%-${max_size_status}s ", $arch_table{$arch};
225 printf "%-${max_size_description}s\n", $data{$name}->{description};
226 }
227
228 print "=" x $max_size_subsys;
229 print " ";
230 print "=" x $max_size_name;
231 print " ";
232 print "=" x $max_size_kconfig;
233 print " ";
234 print "=" x $max_size_status;
235 print " ";
236 print "=" x $max_size_description;
237 print "\n";
238}
239
240#
241# Output a feature on all architectures
242#
243sub output_feature {
244 my $title = "Feature $feat";
245
246 print "=" x length($title) . "\n";
247 print "$title\n";
248 print "=" x length($title) . "\n\n";
249
250 print ":Subsystem: $data{$feat}->{subsys} \n" if ($data{$feat}->{subsys});
251 print ":Kconfig: $data{$feat}->{kconfig} \n" if ($data{$feat}->{kconfig});
252
253 my $desc = $data{$feat}->{description};
254 $desc =~ s/^([a-z])/\U$1/;
255 $desc =~ s/\.?\s*//;
256 print "\n$desc.\n\n";
257
258 my $com = $data{$feat}->{comments};
259 $com =~ s/^\s+//;
260 $com =~ s/\s+$//;
261 if ($com) {
262 print "Comments\n";
263 print "--------\n\n";
264 print "$com\n\n";
265 }
266
267 print "=" x $max_size_arch;
268 print " ";
269 print "=" x $max_size_status;
270 print "\n";
271
272 printf "%-${max_size_arch}s ", $h_arch;
273 printf "%-${max_size_status}s", $h_status . "\n";
274
275 print "=" x $max_size_arch;
276 print " ";
277 print "=" x $max_size_status;
278 print "\n";
279
280 my %arch_table = %{$data{$feat}->{table}};
281 foreach my $arch (sort keys %arch_table) {
282 printf "%-${max_size_arch}s ", $arch;
283 printf "%-${max_size_status}s\n", $arch_table{$arch};
284 }
285
286 print "=" x $max_size_arch;
287 print " ";
288 print "=" x $max_size_status;
289 print "\n";
290}
291
292#
293# Output all features for all architectures
294#
295
296sub matrix_lines {
297 print "=" x $max_size_subsys;
298 print " ";
299 print "=" x $max_size_name;
300 print " ";
301
302 foreach my $arch (sort keys %archs) {
303 my $len = $max_size_status;
304
305 $len = length($arch) if ($len < length($arch));
306
307 print "=" x $len;
308 print " ";
309 }
310 print "=" x $max_size_kconfig;
311 print " ";
312 print "=" x $max_size_description;
313 print "\n";
314}
315
316sub output_matrix {
317
318 my $title = "Feature List (feature x architecture)";
319
320 print "=" x length($title) . "\n";
321 print "$title\n";
322 print "=" x length($title) . "\n\n";
323
324 matrix_lines;
325
326 printf "%-${max_size_subsys}s ", $h_subsys;
327 printf "%-${max_size_name}s ", $h_name;
328
329 foreach my $arch (sort keys %archs) {
330 printf "%-${max_size_status}s ", $arch;
331 }
332 printf "%-${max_size_kconfig}s ", $h_kconfig;
333 printf "%-${max_size_description}s\n", $h_description;
334
335 matrix_lines;
336
337 foreach my $name (sort {
338 ($data{$a}->{subsys} cmp $data{$b}->{subsys}) ||
339 ($data{$a}->{name} cmp $data{$b}->{name})
340 } keys %data) {
341 printf "%-${max_size_subsys}s ", $data{$name}->{subsys};
342 printf "%-${max_size_name}s ", $name;
343
344 my %arch_table = %{$data{$name}->{table}};
345
346 foreach my $arch (sort keys %arch_table) {
347 my $len = $max_size_status;
348
349 $len = length($arch) if ($len < length($arch));
350
351 printf "%-${len}s ", $arch_table{$arch};
352 }
353 printf "%-${max_size_kconfig}s ", $data{$name}->{kconfig};
354 printf "%-${max_size_description}s\n", $data{$name}->{description};
355 }
356
357 matrix_lines;
358}
359
360
361#
362# Parses all feature files located at $prefix dir
363#
364find({wanted =>\&parse_feat, no_chdir => 1}, $prefix);
365
366print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
367
368#
369# Handles the command
370#
371if ($cmd eq "current") {
372 $arch = qx(uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/');
373 $arch =~s/\s+$//;
374}
375
376if ($cmd ne "validate") {
377 if ($arch) {
378 output_arch_table;
379 } elsif ($feat) {
380 output_feature;
381 } else {
382 output_matrix;
383 }
384}
385
386__END__
387
388=head1 NAME
389
390get_feat.pl - parse the Linux Feature files and produce a ReST book.
391
392=head1 SYNOPSIS
393
394B<get_feat.pl> [--debug] [--man] [--help] [--dir=<dir>]
395 [--arch=<arch>] [--feat=<feature>] <COMAND> [<ARGUMENT>]
396
397Where <COMMAND> can be:
398
399=over 8
400
401B<current> - output features for this machine's architecture
402
403B<rest> - output features in ReST markup language
404
405B<validate> - validate the feature contents
406
407=back
408
409=head1 OPTIONS
410
411=over 8
412
413=item B<--arch>
414
415Output features for an specific architecture, optionally filtering for
416a single specific feature.
417
418=item B<--feat>
419
420Output features for a single specific architecture.
421
422=item B<--dir>
423
424Changes the location of the Feature files. By default, it uses
425the Documentation/features directory.
426
427=item B<--debug>
428
429Put the script in verbose mode, useful for debugging. Can be called multiple
430times, to increase verbosity.
431
432=item B<--help>
433
434Prints a brief help message and exits.
435
436=item B<--man>
437
438Prints the manual page and exits.
439
440=back
441
442=head1 DESCRIPTION
443
444Parse the Linux feature files from Documentation/features (by default),
445optionally producing results at ReST format.
446
447It supports output data per architecture, per feature or a
448feature x arch matrix.
449
450When used with B<rest> command, it will use either one of the tree formats:
451
452If neither B<--arch> or B<--feature> arguments are used, it will output a
453matrix with features per architecture.
454
455If B<--arch> argument is used, it will output the features availability for
456a given architecture.
457
458If B<--feat> argument is used, it will output the content of the feature
459file using ReStructured Text markup.
460
461=head1 BUGS
462
463Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
464
465=head1 COPYRIGHT
466
467Copyright (c) 2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
468
469License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
470
471This is free software: you are free to change and redistribute it.
472There is NO WARRANTY, to the extent permitted by law.
473
474=cut