Skip to content

Commit 6d3f935

Browse files
committed
Cleanup help files
Add utility for scanning help files to identify unused topics and/or completely unused or missing files. Update code tree. Note that tools cannot be treated this way because they contain a help entry for each option. Need to update the script to handle that special case. Signed-off-by: Ralph Castain <[email protected]>
1 parent 90925e7 commit 6d3f935

31 files changed

+462
-405
lines changed

contrib/check-help-strings.pl

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
#!/usr/bin/env perl
2+
#
3+
# Copyright (c) 2014-2022 Cisco Systems, Inc. All rights reserved.
4+
# Copyright (c) 2023 Jeffrey M. Squyres. All rights reserved.
5+
# Copyright (c) 2025 Nanook Consulting All rights reserved.
6+
# $COPYRIGHT$
7+
#
8+
# Simple script to check all the opal_show_help (and orte_show_help)
9+
# strings against what is found in help files.
10+
#
11+
12+
use strict;
13+
14+
use Cwd;
15+
use File::Find;
16+
use Getopt::Long;
17+
use Data::Dumper;
18+
19+
my $num_warnings = 0;
20+
my $num_errors = 0;
21+
22+
my $topdir_flag = "Makefile.openpmix-rules";
23+
24+
###########################################################################
25+
26+
my $VERBOSE = 0;
27+
my $HELP = 0;
28+
29+
GetOptions(
30+
"help|h" => \$HELP,
31+
"verbose|v" => \$VERBOSE,
32+
) or die "unable to parse options, aborted";
33+
34+
if ($HELP) {
35+
print <<EOF;
36+
%0 [options]
37+
38+
--help | h This help message
39+
--verbose | v Be verbose in output
40+
EOF
41+
exit(0);
42+
}
43+
44+
###########################################################################
45+
46+
sub verbose {
47+
print @_
48+
if ($VERBOSE);
49+
}
50+
51+
sub DebugDump {
52+
my $d = new Data::Dumper([@_]);
53+
$d->Purity(1)->Indent(1);
54+
my $s = $d->Dump;
55+
print $s;
56+
}
57+
58+
sub isTopDir {
59+
my ($d) = @_;
60+
61+
if (-f "$d/$topdir_flag") {
62+
return 1;
63+
}
64+
65+
return 0;
66+
}
67+
68+
###########################################################################
69+
70+
# Find the top-level source tree dir
71+
my $start = cwd();
72+
my $top = $start;
73+
while (!isTopDir($top)) {
74+
chdir("..");
75+
$top = cwd();
76+
die "Can't find top-level directory"
77+
if ($top eq "/");
78+
}
79+
chdir($start);
80+
81+
###########################################################################
82+
83+
my @source_files;
84+
my @help_files;
85+
86+
# Helper: Search for all source and help files
87+
sub match_files {
88+
# Don't process sym links
89+
return
90+
if (-l $_);
91+
92+
# Don't recurse down "special" directories
93+
if (-d $_ &&
94+
((/^\.deps$/) || (/^\.libs$/) || (/^\.git$/))) {
95+
$File::Find::prune = 1;
96+
return;
97+
}
98+
99+
# $File::Find::name is the path relative to the starting point.
100+
# $_ contains the file's basename. The code automatically changes
101+
# to the processed directory, so we want to open / close $_.
102+
103+
verbose("--> $File::Find::name\n");
104+
105+
my $relative = $File::Find::name;
106+
$relative =~ s/^$top//;
107+
$relative =~ s/^\///;
108+
109+
my $short = $_;
110+
if ($short =~ /^help-.*\.txt$/) {
111+
push(@help_files, {
112+
full => $File::Find::name,
113+
short => $short,
114+
relative => $relative,
115+
});
116+
verbose(" Found help file: $short\n");
117+
}
118+
119+
if ($short =~ /\.c$/ ||
120+
$short =~ /\.h$/ ||
121+
$short =~ /\.cc$/) {
122+
push(@source_files, {
123+
full => $File::Find::name,
124+
short => $short,
125+
relative => $relative,
126+
});
127+
verbose(" Found source file: $short\n");
128+
}
129+
}
130+
131+
# Find all source and help files
132+
print "Searching for source and help files...\n";
133+
my $startrel = $start;
134+
if ($top ne $start) {
135+
$startrel =~ s/^$top//;
136+
$startrel =~ s/^\///;
137+
}
138+
find(\&match_files, ".");
139+
140+
###########################################################################
141+
142+
# Index all help files
143+
my $help_topics;
144+
my $help_file_refs;
145+
146+
print "Indexing help files (from entire source tree)...\n";
147+
148+
foreach my $info (@help_files) {
149+
verbose("Indexing help: $info->{full}\n");
150+
151+
# Check for short name collision
152+
if (exists($help_topics->{$info->{short}})) {
153+
154+
# Found a collision! Find the original's full name.
155+
my $collide_relative = "unknown";
156+
foreach my $i (@help_files) {
157+
if ($i->{short} eq $info->{short}) {
158+
$collide_relative = $i->{relative};
159+
last;
160+
}
161+
}
162+
163+
# Print error message
164+
print "*** ERROR: Help file name collision:
165+
File 1: $info->{relative}
166+
File 2: $collide_relative\n";
167+
++$num_errors;
168+
}
169+
170+
# Read in file, find all of its topics
171+
my $num_topics = 0;
172+
open(FH, $info->{full}) || die "Can't open $info->{full}";
173+
while (<FH>) {
174+
if (m/^\s*\[(.+?)\]\s*$/) {
175+
my $topic = $1;
176+
verbose(" Topic: $topic\n");
177+
$help_topics->{$info->{short}}->{topic}->{$topic} = 0;
178+
$help_topics->{$info->{short}}->{full} = $info->{full};
179+
++$num_topics;
180+
}
181+
}
182+
close(FH);
183+
184+
if (0 == $num_topics) {
185+
print "*** WARNING: Empty help file (no topics)
186+
Help file: $info->{full}\n";
187+
++$num_warnings;
188+
}
189+
}
190+
191+
###########################################################################
192+
193+
# Search source files for calls to opal_show_help and (o)rte_show_help
194+
195+
if ($start eq $top) {
196+
print "Searching source files (from entire source tree)...\n";
197+
} else {
198+
print "Searching source files (under $startrel)...\n";
199+
}
200+
201+
# Helper: for a given filename/topic, see if it exists
202+
sub check_file_topic {
203+
my $info = shift;
204+
my $file = shift;
205+
my $topic = shift;
206+
207+
verbose("Found $info->{short}: $file / $topic\n");
208+
209+
# Do we have a help file for this?
210+
if (!exists($help_topics->{$file})) {
211+
print "*** ERROR: Source-referenced help file does not exist
212+
Source file: $info->{relative}
213+
Help file referenced: $file\n";
214+
++$num_errors;
215+
}
216+
217+
# Do we have a topic in that help file for this?
218+
elsif (!exists($help_topics->{$file}->{topic}->{$topic})) {
219+
print "*** ERROR: Source-referenced help topic does not exist
220+
Source file: $info->{relative}
221+
Help file referenced: $file
222+
which is: $help_topics->{$file}->{full}
223+
Help topic referenced: $topic\n";
224+
++$num_errors;
225+
}
226+
227+
# Yes, we do have a topic in that help file for this.
228+
# Increase its ref count.
229+
else {
230+
++$help_topics->{$file}->{topic}->{$topic};
231+
}
232+
}
233+
234+
# Helper: search source file for a regexps matching a help filename
235+
# and topic.
236+
sub check_name {
237+
my $info = shift,
238+
my $name = shift;
239+
my $sep = shift;
240+
my $src = shift;
241+
242+
while ($src =~ m/$name\s*$sep\s*"(.+?)"\s*,.*?"(.+?)"/) {
243+
my $file = $1;
244+
my $topic = $2;
245+
check_file_topic($info, $file, $topic);
246+
247+
# Don't find this one again
248+
$src =~ s/$name\s*$sep\s*"(.+?)"\s*,.*?"(.+?)"/SHOW_HELP_REPLACED/;
249+
}
250+
251+
return $src;
252+
}
253+
254+
255+
# Check to ensure helpfile/topic combos exist
256+
foreach my $info (@source_files) {
257+
verbose("Searching source: $info->{full}\n");
258+
259+
# If this source file is not in the target area, then skip it
260+
next
261+
if ($info->{relative} != /^$startrel/);
262+
263+
my $src;
264+
open(FH, $info->{full}) || die "Can't open $info->{full}";
265+
while (<FH>) {
266+
# Eliminate newlines, just for regexp simplicity later
267+
chomp;
268+
$src .= $_;
269+
}
270+
close(FH);
271+
272+
# Find calls to pmix_show_help()
273+
$src = check_name($info, "pmix_show_help", "\\(", $src);
274+
# Find calls to pmix_show_help_string()
275+
$src = check_name($info, "pmix_show_help_string", "\\(", $src);
276+
# Find special tokens from comments
277+
$src = check_name($info, "SHOW_HELP", ":", $src);
278+
}
279+
280+
###########################################################################
281+
282+
# Check that all indexed help strings were referenced
283+
284+
print "Checking for stale help messages / files...\n";
285+
286+
foreach my $file (sort(keys(%{$help_topics}))) {
287+
my $num_used = 0;
288+
foreach my $topic (sort(keys(%{$help_topics->{$file}->{topic}}))) {
289+
if (0 == $help_topics->{$file}->{topic}->{$topic}) {
290+
print "*** WARNING: Possibly unused help topic
291+
Help file: $help_topics->{$file}->{full}
292+
Help topic: $topic\n";
293+
++$num_warnings;
294+
} else {
295+
++$num_used;
296+
}
297+
}
298+
299+
# Were no topics used in this file at all?
300+
if (0 == $num_used) {
301+
print "*** WARNING: Possibly unused help file (no topics used from this file)
302+
Help file: $help_topics->{$file}->{full}\n";
303+
++$num_warnings;
304+
}
305+
}
306+
307+
###########################################################################
308+
309+
# All done
310+
if (0 == $num_errors && 0 == $num_warnings) {
311+
print "+++ All seems good!\n";
312+
exit(0);
313+
} else {
314+
print "Total number of warnings: $num_warnings
315+
Total number of errors: $num_errors\n";
316+
exit(1);
317+
}

0 commit comments

Comments
 (0)