diff --git a/contrib/check-help-strings.pl b/contrib/check-help-strings.pl new file mode 100644 index 0000000000..ecd5e55591 --- /dev/null +++ b/contrib/check-help-strings.pl @@ -0,0 +1,292 @@ +#!/usr/bin/env perl +# +# Copyright (c) 2014 Cisco Systems, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Simple script to check all the opal_show_help (and orte_show_help) +# strings against what is found in help files. +# + +use strict; + +use Cwd; +use File::Find; +use Getopt::Long; +use Data::Dumper; + +my $num_warnings = 0; +my $num_errors = 0; + +########################################################################### + +my $VERBOSE = 0; +my $HELP = 0; + +GetOptions( + "help" => \$HELP, + "verbose" => \$VERBOSE, +) or die "unable to parse options, aborted"; + +if ($HELP) { + print <Purity(1)->Indent(1); + my $s = $d->Dump; + print $s; +} + +########################################################################### + +# Find the top-level OMPI source tree dir +my $start = cwd(); +my $top = $start; +while (! -f "$top/Makefile.ompi-rules") { + chdir(".."); + $top = cwd(); + die "Can't find top-level Open MPI directory" + if ($top eq "/"); +} +chdir($start); + +########################################################################### + +my @source_files; +my @help_files; + +# Helper: Search for all source and help files +sub match_files { + # Don't process sym links + return + if (-l $_); + + # Don't recurse down "special" directories + if (-d $_ && + ((/^\.deps$/) || (/^\.libs$/) || + (/^\.svn$/) || (/^\.hg$/) || (/^\.git$/))) { + $File::Find::prune = 1; + return; + } + + # $File::Find::name is the path relative to the starting point. + # $_ contains the file's basename. The code automatically changes + # to the processed directory, so we want to open / close $_. + + verbose("--> $File::Find::name\n"); + + my $relative = $File::Find::name; + $relative =~ s/^$top//; + $relative =~ s/^\///; + + my $short = $_; + if ($short =~ /^help-.*\.txt$/) { + push(@help_files, { + full => $File::Find::name, + short => $short, + relative => $relative, + }); + verbose(" Found help file: $short\n"); + } + + if ($short =~ /\.c$/ || + $short =~ /\.h$/ || + $short =~ /\.cc$/) { + push(@source_files, { + full => $File::Find::name, + short => $short, + relative => $relative, + }); + verbose(" Found source file: $short\n"); + } +} + +# Find all source and help files +print "Searching for source and help files...\n"; +print "Starting in: $start\n"; +find(\&match_files, "."); + +########################################################################### + +# Index all help files +my $help_topics; +my $help_file_refs; + +print "Indexing help files...\n"; + +foreach my $info (@help_files) { + verbose("Indexing help: $info->{full}\n"); + + # Check for short name collision + if (exists($help_topics->{$info->{short}})) { + + # Found a collision! Find the original's full name. + my $collide_relative = "unknown"; + foreach my $i (@help_files) { + if ($i->{short} eq $info->{short}) { + $collide_relative = $i->{relative}; + last; + } + } + + # Print error message + print "*** ERROR: Help file name collision: + File 1: $info->{relative} + File 2: $collide_relative\n"; + ++$num_errors; + } + + # Read in file, find all of its topics + my $num_topics = 0; + open(FH, $info->{full}) || die "Can't open $info->{full}"; + while () { + if (m/^\s*\[(.+?)\]\s*$/) { + my $topic = $1; + verbose(" Topic: $topic\n"); + $help_topics->{$info->{short}}->{$topic} = 0; + ++$num_topics; + } + } + close(FH); + + if (0 == $num_topics) { + print "*** WARNING: Empty help file (no topics) + Help file: $info->{short}\n"; + ++$num_warnings; + } +} + +########################################################################### + +# Search source files for calls to opal_show_help and (o)rte_show_help + +print "Searching source files...\n"; + +# Helper: for a given filename/topic, see if it exists +sub check_file_topic { + my $info = shift; + my $file = shift; + my $topic = shift; + + verbose("Found $info->{short}: $file / $topic\n"); + + # Do we have a help file for this? + if (!exists($help_topics->{$file})) { + print "*** ERROR: Source-referenced help file does not exist + Source file: $info->{relative} + Help file referenced: $file\n"; + ++$num_errors; + } + + # Do we have a topic in that help file for this? + elsif (!exists($help_topics->{$file}->{$topic})) { + print "*** ERROR: Source-referenced help topic does not exist + Source file: $info->{relative} + Help file referenced: $file + Help topic referenced: $topic\n"; + ++$num_errors; + } + + # Yes, we do have a topic in that help file for this. + # Increase its ref count. + else { + ++$help_topics->{$file}->{$topic}; + } +} + +# Helper: search source file for a regexps matching a help filename +# and topic. +sub check_name { + my $info = shift, + my $name = shift; + my $sep = shift; + my $src = shift; + + while ($src =~ m/$name\s*$sep\s*"(.+?)"\s*,\s*"(.+?)"/) { + my $file = $1; + my $topic = $2; + check_file_topic($info, $file, $topic); + + # Don't find this one again + $src =~ s/$name\s*$sep\s*"(.+?)"\s*,\s*"(.+?)"/SHOW_HELP_REPLACED/; + } + + return $src; +} + + +# Check to ensure helpfile/topic combos exist +foreach my $info (@source_files) { + verbose("Searching source: $info->{full}\n"); + + my $src; + open(FH, $info->{full}) || die "Can't open $info->{full}"; + while () { + # Eliminate newlines, just for regexp simplicity later + chomp; + $src .= $_; + } + close(FH); + + # Find calls to opal_show_help() + $src = check_name($info, "opal_show_help", "\\(", $src); + # Find calls to opal_show_help_string() + $src = check_name($info, "opal_show_help_string", "\\(", $src); + # Find calls to rte_show_help() (and also orte_show_help()) + $src = check_name($info, "rte_show_help", "\\(", $src); + # Find special tokens from comments + $src = check_name($info, "SHOW_HELP", ":", $src); +} + +########################################################################### + +# Check that all indexed help strings were referenced + +print "Checking for stale help messages / files...\n"; + +foreach my $file (sort(keys(%{$help_topics}))) { + my $num_used = 0; + foreach my $topic (sort(keys(%{$help_topics->{$file}}))) { + if (0 == $help_topics->{$file}->{$topic}) { + print "*** WARNING: Possibly unused help topic + Help file: $file + Help topic: $topic\n"; + ++$num_warnings; + } else { + ++$num_used; + } + } + + # Were no topics used in this file at all? + if (0 == $num_used) { + print "*** WARNING: Possibly unused help file (no topics used from this file) + Help file: $file\n"; + ++$num_warnings; + } +} + +########################################################################### + +# All done +if (0 == $num_errors && 0 == $num_warnings) { + print "+++ All seems good!\n"; + exit(0); +} else { + print "Total number of warnings: $num_warnings +Total number of errors: $num_errors\n"; + exit(1); +}