mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-01 18:25:59 +00:00
Combine check-* scripts into super check-tool script. Add check-spelling, check-dev-env, and docs/test-coverage directory.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
config/NaturalDocs/Data
|
||||
docs/dev/*
|
||||
docs/user/html
|
||||
docs/test-coverage/db
|
||||
docs/test-coverage/html
|
||||
.DS_Store
|
||||
|
@@ -75,7 +75,7 @@ how wide each column should be, and then prints them out.
|
||||
This is useful for things like aligning the output of vmstat or iostat so it
|
||||
is easier to read.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -5536,7 +5536,7 @@ A sample module might look like this:
|
||||
|
||||
1;
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -1301,7 +1301,7 @@ Show version and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -298,7 +298,7 @@ Usage: pt-collect [OPTION...]
|
||||
pt-collect focuses on gathering diagnostic data during a MySQL performance
|
||||
problem. It is typically executed by C<stalk>.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -3162,7 +3162,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2641,7 +2641,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -656,7 +656,7 @@ The file read should look like this:
|
||||
... et cetera
|
||||
TS <timestamp> <-- must end with a TS line.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -4175,7 +4175,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -1448,7 +1448,7 @@ Show version and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -3723,7 +3723,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2361,7 +2361,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -4206,7 +4206,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -6091,7 +6091,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
48
bin/pt-kill
48
bin/pt-kill
@@ -4106,12 +4106,6 @@ short form: -P; type: int
|
||||
|
||||
Port number to use for connection.
|
||||
|
||||
=item --[no]strip-comments
|
||||
|
||||
default: yes
|
||||
|
||||
Remove SQL comments from queries in the Info column of the PROCESSLIST.
|
||||
|
||||
=item --run-time
|
||||
|
||||
type: time
|
||||
@@ -4152,6 +4146,12 @@ Causes pt-kill to create the sentinel file specified by L<"--sentinel"> and
|
||||
exit. This should have the effect of stopping all running instances which are
|
||||
watching the same sentinel file.
|
||||
|
||||
=item --[no]strip-comments
|
||||
|
||||
default: yes
|
||||
|
||||
Remove SQL comments from queries in the Info column of the PROCESSLIST.
|
||||
|
||||
=item --user
|
||||
|
||||
short form: -u; type: string
|
||||
@@ -4226,23 +4226,6 @@ See also L<"GROUP, MATCH AND KILL">.
|
||||
|
||||
=over
|
||||
|
||||
=item --match-all
|
||||
|
||||
group: Query Matches
|
||||
|
||||
Match all queries that are not ignored. If no ignore options are specified,
|
||||
then every query matches (except replication threads, unless
|
||||
L<"--replication-threads"> is also specified). This option allows you to
|
||||
specify negative matches, i.e. "match every query I<except>..." where the
|
||||
exceptions are defined by specifying various C<--ignore> options.
|
||||
|
||||
This option is I<not> the same as L<"--victims"> C<all>. This option matches
|
||||
all queries within a class, whereas L<"--victims"> C<all> specifies that all
|
||||
matching queries in a class (however they matched) will be killed. Normally,
|
||||
however, the two are used together because if, for example, you specify
|
||||
L<"--victims"> C<oldest>, then although all queries may match, only the oldest
|
||||
will be killed.
|
||||
|
||||
=item --busy-time
|
||||
|
||||
type: time; group: Query Matches
|
||||
@@ -4314,6 +4297,23 @@ Ignore queries whose user matches this Perl regex.
|
||||
|
||||
See L<"--match-user">.
|
||||
|
||||
=item --match-all
|
||||
|
||||
group: Query Matches
|
||||
|
||||
Match all queries that are not ignored. If no ignore options are specified,
|
||||
then every query matches (except replication threads, unless
|
||||
L<"--replication-threads"> is also specified). This option allows you to
|
||||
specify negative matches, i.e. "match every query I<except>..." where the
|
||||
exceptions are defined by specifying various C<--ignore> options.
|
||||
|
||||
This option is I<not> the same as L<"--victims"> C<all>. This option matches
|
||||
all queries within a class, whereas L<"--victims"> C<all> specifies that all
|
||||
matching queries in a class (however they matched) will be killed. Normally,
|
||||
however, the two are used together because if, for example, you specify
|
||||
L<"--victims"> C<oldest>, then although all queries may match, only the oldest
|
||||
will be killed.
|
||||
|
||||
=item --match-command
|
||||
|
||||
type: string; group: Query Matches
|
||||
@@ -4581,7 +4581,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -3517,7 +3517,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -112,7 +112,7 @@ Usage: pt-mext [OPTION...]
|
||||
|
||||
pt-mext aggregates and summarizes mysqladmin extended output.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -1289,7 +1289,7 @@ you would use to connect to MySQL, such as "./mysql-summary --user=foo"
|
||||
|
||||
* Parse queries out of processlist and aggregate them.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -5203,7 +5203,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -205,7 +205,7 @@ Usage: pt-pmp [OPTION...]
|
||||
|
||||
pt-pmp aggregates stack traces.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -1266,7 +1266,7 @@ Show version and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -7191,7 +7191,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -15635,7 +15635,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2751,7 +2751,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -84,7 +84,7 @@ The output will be
|
||||
Mutex spin waits 0, rounds 6645565, OS waits 34159
|
||||
RW-shared spins 14648, OS waits 882; RW-excl spins 13146
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2129,7 +2129,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -481,7 +481,7 @@ Usage: pt-sift [OPTION...]
|
||||
|
||||
pt-sift browses the files created by the collect tool.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2613,7 +2613,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -3093,7 +3093,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -3264,7 +3264,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -183,7 +183,7 @@ and restarting this one.
|
||||
|
||||
The name 'stalk' is because 'watch' is already taken, and 'stalk' is fun.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -1203,7 +1203,7 @@ Options:
|
||||
NETWORK: Don't print out information on network controllers & config.
|
||||
PROCESS: Don't print out top processes and vmstat information.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -8645,7 +8645,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -9970,7 +9970,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2318,7 +2318,7 @@ number.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -1992,7 +1992,7 @@ Show version and exit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -11732,7 +11732,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -794,7 +794,7 @@ This tool is based on Neil Gunther's book Guerrilla Capacity Planning.
|
||||
other samples; it will introduce skew into the throughput for that sample,
|
||||
too.
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -3806,7 +3806,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
@@ -2996,7 +2996,7 @@ User for login if not current user.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DOWNLOADING
|
||||
=head1 DOWNLOADING
|
||||
|
||||
Visit L<http://www.percona.com/software/> to download the latest release of
|
||||
Percona Toolkit. Or, to get the latest release from the command line:
|
||||
|
90
util/aspell.en.pws
Normal file
90
util/aspell.en.pws
Normal file
@@ -0,0 +1,90 @@
|
||||
personal_ws-1.1 en 86
|
||||
STDOUT
|
||||
MKDEBUG
|
||||
PTDEBUG
|
||||
timestamp
|
||||
perlgpl
|
||||
perlartistic
|
||||
Ver
|
||||
Distrib
|
||||
Nichter
|
||||
Percona
|
||||
binmode
|
||||
config
|
||||
PID
|
||||
MySQL
|
||||
mysql
|
||||
Maatkit
|
||||
processlist
|
||||
PROCESSLIST
|
||||
STDIN
|
||||
login
|
||||
STDERR
|
||||
wget
|
||||
DSN
|
||||
SQL
|
||||
charset
|
||||
daemonize
|
||||
daemonized
|
||||
POSIX
|
||||
regex
|
||||
cron
|
||||
DBI
|
||||
DBD
|
||||
Freenode
|
||||
IRC
|
||||
MERCHANTABILITY
|
||||
whitespace
|
||||
manpage
|
||||
binlog
|
||||
runtime
|
||||
OLTP
|
||||
mojibake
|
||||
archiver
|
||||
INFILE
|
||||
OUTFILE
|
||||
umask
|
||||
InnoDB
|
||||
transactional
|
||||
MyISAM
|
||||
checksum
|
||||
checksums
|
||||
checksumming
|
||||
checksummed
|
||||
chunking
|
||||
chunked
|
||||
chunkable
|
||||
hostname
|
||||
PostgreSQL
|
||||
Continuent
|
||||
LLC
|
||||
sakila
|
||||
gzip
|
||||
lossless
|
||||
mysqldump
|
||||
mysqlbinlog
|
||||
mysqlimport
|
||||
fifo
|
||||
recurse
|
||||
wildcard
|
||||
bool
|
||||
boolean
|
||||
subquery
|
||||
subqueries
|
||||
memcached
|
||||
cardinality
|
||||
Apdex
|
||||
sparkline
|
||||
cryptographic
|
||||
tcpdump
|
||||
timeline
|
||||
profiler
|
||||
canonicalize
|
||||
prefetch
|
||||
unresolvable
|
||||
incrementing
|
||||
scalability
|
||||
IP
|
||||
runnable
|
||||
online
|
||||
Aspersa
|
40
util/check-dev-env
Executable file
40
util/check-dev-env
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# This pseudo-script is for developers to see if their box has all
|
||||
# the modules necessary for testing Maatkit. Any missing modules
|
||||
# will cause an error like "Can't locate Foo.pm in @INC ...". Else
|
||||
# the version for each module used by this script will be printed.
|
||||
|
||||
use Data::Dumper;
|
||||
use DBD::mysql;
|
||||
use DBI;
|
||||
use Digest::MD5;
|
||||
use File::Basename;
|
||||
use File::Find;
|
||||
use File::Spec;
|
||||
use File::Temp;
|
||||
use Getopt::Long;
|
||||
use IO::Compress::Gzip;
|
||||
use IO::File;
|
||||
use IO::Uncompress::Inflate;
|
||||
use List::Util;
|
||||
use POSIX;
|
||||
use Socket;
|
||||
use Term::ReadKey;
|
||||
use Test::More;
|
||||
use threads;
|
||||
use Thread::Queue;
|
||||
use Time::HiRes;
|
||||
use Time::Local;
|
||||
#use Digest::Crc32;
|
||||
|
||||
my $file = __FILE__;
|
||||
my $m = `cat $file | grep '^use'`;
|
||||
my @modules = map { m/use (.+?);/; $1 } split("\n", $m);
|
||||
|
||||
foreach my $module ( @modules ) {
|
||||
my $version = "${module}::VERSION";
|
||||
print "$module " . ${$version} . "\n";
|
||||
}
|
||||
|
||||
exit;
|
45
util/check-spelling
Executable file
45
util/check-spelling
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# You must run the program from util/.
|
||||
if ( !(-f 'aspell.en.pws' && -f 'parse-aspell-output') ) {
|
||||
die "This script must be run from the util/ directory of a branch\n"
|
||||
}
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
|
||||
# These programs should be in your PATH.
|
||||
my $pod2text = 'pod2text';
|
||||
my $aspell = 'aspell';
|
||||
|
||||
my $tool_file = shift @ARGV;
|
||||
if ( !$tool_file ) {
|
||||
die "Usage: $PROGRAM_NAME TOOL\n";
|
||||
}
|
||||
|
||||
my ($tool_name) = $tool_file =~ m{([a-z-]+)$};
|
||||
if ( !$tool_name ) {
|
||||
die "Cannot parse tool name from $tool_file";
|
||||
}
|
||||
|
||||
# Temp files.
|
||||
my $pod_file = "/tmp/$tool_name-pod";
|
||||
my $bad_words_file = "/tmp/$tool_name-misspelled-words";
|
||||
|
||||
# Convert tool's POD to text.
|
||||
`$pod2text $tool_file > $pod_file`;
|
||||
|
||||
# Spell check the text file.
|
||||
`cat $pod_file | $aspell --pipe --lang en_US --personal ./aspell.en.pws > $bad_words_file`;
|
||||
|
||||
# Parse and match the aspell output to the text file.
|
||||
print "$tool_name:\n\n";
|
||||
print `./parse-aspell-output $bad_words_file $pod_file`;
|
||||
print "\n";
|
||||
|
||||
# Cleanup.
|
||||
`rm -rf $pod_file`;
|
||||
`rm -rf $bad_words_file`;
|
||||
|
||||
exit;
|
435
util/check-tool
Executable file
435
util/check-tool
Executable file
@@ -0,0 +1,435 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use English qw(-no_match_vars);
|
||||
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
|
||||
|
||||
use Data::Dumper;
|
||||
$Data::Dumper::Indent = 1;
|
||||
$Data::Dumper::Sortkeys = 1;
|
||||
$Data::Dumper::Quotekeys = 0;
|
||||
|
||||
my @tool_files = @ARGV;
|
||||
if ( !@tool_files ) {
|
||||
die "Usage: $PROGRAM_NAME [TOOL...]\n";
|
||||
}
|
||||
|
||||
my $exit_status = 0; # 0 no problems, 1 any problems
|
||||
my $tool_file; # bin/pt-archiver
|
||||
my $tool_name; # pt-archiver (no path)
|
||||
|
||||
my @check_subs = (qw(
|
||||
check_alpha_order
|
||||
check_module_usage
|
||||
check_option_types
|
||||
check_pod_header_order
|
||||
check_pod_formatting
|
||||
check_option_usage
|
||||
));
|
||||
|
||||
TOOL:
|
||||
while ( defined($tool_file = shift @ARGV) ) {
|
||||
my $fh;
|
||||
eval {
|
||||
open $fh, "<", $tool_file;
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
$exit_status = 1;
|
||||
warn "Cannot open $tool_file: $OS_ERROR";
|
||||
next TOOL;
|
||||
}
|
||||
|
||||
($tool_name) = $tool_file =~ m{/([a-z-]+)$};
|
||||
if ( !$tool_name ) {
|
||||
$exit_status = 1;
|
||||
warn "Cannot parse tool name from $tool_file";
|
||||
next TOOL;
|
||||
}
|
||||
|
||||
foreach my $check_sub ( @check_subs ) {
|
||||
seek $fh, 0, 0;
|
||||
print "# $check_sub ", ('#' x (70 - length $check_sub)), "\n";
|
||||
my $sub = \&$check_sub;
|
||||
eval {
|
||||
&$sub($fh);
|
||||
};
|
||||
if ( $EVAL_ERROR ) {
|
||||
$exit_status = 1;
|
||||
warn "Error while checking $tool_name: $EVAL_ERROR";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit $exit_status;
|
||||
|
||||
# ############################################################################
|
||||
# Subroutines
|
||||
# ############################################################################
|
||||
|
||||
# Check that options in the tool's POD are in alphabetical order. Only the
|
||||
# head1 OPTIONS section and any head2 subsections are checked. Subsections
|
||||
# are considered independent. The "[no]" part of negatable options is not
|
||||
# part of the base option name, so it's ignored.
|
||||
sub check_alpha_order {
|
||||
my ($fh) = @_;
|
||||
local $INPUT_RECORD_SEPARATOR = '';
|
||||
my $para;
|
||||
my $section;
|
||||
while ( $para = <$fh> ) {
|
||||
last if ($section) = $para =~ m/^=head1 (OPTIONS)/;
|
||||
}
|
||||
die "Cannot find =head1 OPTIONS" unless $section;
|
||||
parse_options($fh, $section);
|
||||
return;
|
||||
}
|
||||
|
||||
sub parse_options {
|
||||
my ($fh, $section) = @_;
|
||||
my $para;
|
||||
my @opts;
|
||||
while ( $para = <$fh> ) {
|
||||
last if $para =~ m/^=head1/;
|
||||
|
||||
if ( my ($option) = $para =~ m/^=item --(?:\[no\])?(.*)/ ) {
|
||||
push @opts, $option;
|
||||
}
|
||||
elsif ( $para =~ m/^=head2 (.+)/ ) {
|
||||
parse_options($fh, $1);
|
||||
}
|
||||
}
|
||||
|
||||
my $fmt = "%-20s %-20s\n";
|
||||
my @sorted = sort @opts;
|
||||
for my $i ( 0..$#sorted ) {
|
||||
if ( $opts[$i] ne $sorted[$i] ) {
|
||||
$exit_status = 1;
|
||||
printf "$tool_name has unsorted options in $section\n";
|
||||
printf $fmt, 'ACTUAL', 'CORRECT';
|
||||
printf $fmt, '=' x 20, '=' x 20;
|
||||
map { printf $fmt, $opts[$_], $sorted[$_] }
|
||||
grep { $opts[$_] ne $sorted[$_] }
|
||||
($i..$#sorted);
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub check_module_usage {
|
||||
my ($fh) = @_;
|
||||
|
||||
# These modules are not instantiated as objects.
|
||||
my %not_obj = (
|
||||
Transformers => 1,
|
||||
);
|
||||
|
||||
# Many tools dyanmically instantiate objs like $plugin="WatchStatus",
|
||||
# $plugin->new(). So this script can't detect that.
|
||||
my %dynamic = (
|
||||
'pt-loadavg' => {
|
||||
WatchStatus => 1,
|
||||
WatchProcesslist => 1,
|
||||
WatchServer => 1,
|
||||
},
|
||||
'pt-query-advisor' => {
|
||||
SlowLogParser => 1,
|
||||
GeneralLogParser => 1,
|
||||
},
|
||||
'pt-query-digest' => {
|
||||
TcpdumpParser => 1,
|
||||
MySQLProtocolParser => 1,
|
||||
PgLogParser => 1,
|
||||
SlowLogParser => 1,
|
||||
MemcachedProtocolParser => 1,
|
||||
MemcachedEvent => 1,
|
||||
BinaryLogParser => 1,
|
||||
GeneralLogParser => 1,
|
||||
ProtocolParser => 1,
|
||||
HTTPProtocolParser => 1,
|
||||
},
|
||||
'pt-table-sync' => {
|
||||
TableSyncStream => 1,
|
||||
TableSyncChunk => 1,
|
||||
TableSyncNibble => 1,
|
||||
TableSyncGroupBy => 1,
|
||||
},
|
||||
'pt-table-usage' => {
|
||||
SlowLogParser => 1,
|
||||
},
|
||||
);
|
||||
|
||||
# If these base-class modules are present, they should be accompanied
|
||||
# by a subclass.
|
||||
my %base_class = (
|
||||
'AdvisorRules' => [ qw(QueryAdvisorRules VariableAdvisorRules) ],
|
||||
);
|
||||
|
||||
# Nearly every tool has or needs these modules.
|
||||
my %ignore = (
|
||||
OptionParser => 1,
|
||||
DSNParser => 1,
|
||||
);
|
||||
|
||||
my $contents = do { local $/ = undef; <$fh> };
|
||||
my %uses = map { $_ => 1 } $contents =~ m/new ([A-Z]\w+)(?:\(|;)/gm;
|
||||
my @unused = grep {
|
||||
my $module = $_;
|
||||
my $unused = 0;
|
||||
if ( $not_obj{$module} ) {
|
||||
# MaatkitCommon::_d
|
||||
chomp(my $g = `grep -c '${_}::' $tool_file`);
|
||||
# Transformers->import
|
||||
chomp(my $i = `grep -c '${_}->import' $tool_file`);
|
||||
$g ||= 0;
|
||||
$i ||= 0;
|
||||
$unused = 1 if $g + $i == 0;
|
||||
}
|
||||
elsif ( $dynamic{$tool_name}->{$module} ) {
|
||||
# Can't detect these.
|
||||
}
|
||||
elsif ( $base_class{$module} ) {
|
||||
$unused = 1 unless grep { $uses{$_} } @{$base_class{$module}};
|
||||
}
|
||||
else {
|
||||
$unused = 1 unless $uses{$module};
|
||||
}
|
||||
$unused;
|
||||
}
|
||||
grep { !$ignore{$_} } $contents =~ m/^# (\w+) package$/gm;
|
||||
|
||||
if ( @unused ) {
|
||||
print "$tool_name has unused modules:\n"
|
||||
. join('', map { "\t$_\n" } @unused);
|
||||
$exit_status = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub check_option_types {
|
||||
my ($fh) = @_;
|
||||
|
||||
# Standard options: http://code.google.com/p/maatkit/wiki/CommandLineOptions
|
||||
my $sop = {
|
||||
'defaults-file' => {type => 's', short => 'F' },
|
||||
'host' => {type => 's', short => 'h' },
|
||||
'password' => {type => 's', short => 'p' },
|
||||
'port' => {type => 'i', short => 'P' },
|
||||
'socket' => {type => 's', short => 'S' },
|
||||
'user' => {type => 's', short => 'u' },
|
||||
'charset' => {type => 's', short => 'A' },
|
||||
'ask-pass' => {type => '', short => '', },
|
||||
'database' => {type => 's', short => 'D' },
|
||||
'set-vars' => {type => 's', short => '', },
|
||||
'where' => {type => 's', short => '', },
|
||||
'databases' => {type => 'h', short => 'd' },
|
||||
'tables' => {type => 'h', short => 't' },
|
||||
'columns' => {type => 'a', short => 'c' },
|
||||
'engines' => {type => 'h', short => 'e' },
|
||||
'ignore-databases'=> {type => 'H', short => '', },
|
||||
'ignore-tables' => {type => 'H', short => '', },
|
||||
'ignore-columns' => {type => 'H', short => '', },
|
||||
'ignore-engines' => {type => 'H', short => '', },
|
||||
'config' => {type => 'A', short => '', },
|
||||
'daemonize' => {type => '', short => '', },
|
||||
'dry-run' => {type => '', short => '', },
|
||||
'log' => {type => 's', short => '', },
|
||||
'pid' => {type => 's', short => '', },
|
||||
# --progress is not standard. Some older tools had their own special
|
||||
# progress, whereas newer tools use Progress.
|
||||
# 'progress' => {type => 'a', short => '', },
|
||||
'quiet' => {type => '', short => 'q' },
|
||||
'sentinel' => {type => 's', short => '', },
|
||||
'stop' => {type => '', short => '', },
|
||||
'run-time' => {type => 'm', short => '', },
|
||||
'threads' => {type => 'i', short => '', },
|
||||
'verbose' => {type => '', short => 'v' },
|
||||
'wait' => {type => 'm', short => 'w' },
|
||||
'recurse' => {type => 'i', short => '' },
|
||||
};
|
||||
|
||||
# Exceptions are inevitable. E.g., pt-deadlock-logger --columns is not the
|
||||
# standard filter --columns (e.g. same family as --databases, --tables, etc.)
|
||||
# These exceptions are good candidates for change, so our standard options
|
||||
# really are standard across all tools.
|
||||
my $exception = {
|
||||
'pt-deadlock-logger' => { # not standard filter
|
||||
columns => {
|
||||
type => 'h',
|
||||
short => '',
|
||||
},
|
||||
},
|
||||
'pt-checksum-filter' => { # not standard filter
|
||||
'ignore-databases' => {
|
||||
type => '',
|
||||
short => '',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
my $help = `$tool_file --help`;
|
||||
|
||||
# Options are listed after the line "Options:" (default group).
|
||||
# Each line is like:
|
||||
# --defaults-file=s -F Only read mysql options from the given file
|
||||
# The short form (-F) is optional. The list is terminated at
|
||||
# the line "Option types:". Problem is: there's a second list
|
||||
# of options. The second list shows each option's value. So
|
||||
# we stop parsing when we get an option that we already have.
|
||||
my $opt = {};
|
||||
while ( $help =~ m/^\s{2,}--(\S+?)(?:=(.))?\s+(?:-([a-zA-Z]))?\s+\w+/mg ) {
|
||||
my ($long, $type, $short) = ($1, $2, $3);
|
||||
die "Failed to parse $help" unless $long;
|
||||
last if $opt->{$long};
|
||||
$opt->{$long} = 1;
|
||||
|
||||
if ( $sop->{$long} ) {
|
||||
# Check option type.
|
||||
my $expected_type = $sop->{$long}->{type};
|
||||
$expected_type = $exception->{$tool_name}->{$long}->{type}
|
||||
if exists $exception->{$tool_name}->{$long}->{type};
|
||||
$expected_type = '' unless defined $expected_type;
|
||||
if ( ($type || '') ne $expected_type ) {
|
||||
$exit_status = 1;
|
||||
print "$tool_name --$long "
|
||||
. ($type ? "is type $type" : "has no type")
|
||||
. " but should "
|
||||
. ($expected_type ? "be type $expected_type"
|
||||
: "have no type")
|
||||
. "\n";
|
||||
}
|
||||
|
||||
# Check short form.
|
||||
my $expected_short = $sop->{$long}->{short};
|
||||
$expected_short = $exception->{$tool_name}->{$long}->{short}
|
||||
if exists $exception->{$tool_name}->{$long}->{short};
|
||||
$expected_short = '' unless defined $expected_short;
|
||||
if ( ($short || '') ne $expected_short ) {
|
||||
print "$tool_name --$long "
|
||||
. ($short ? "has short form -$short" : "has no short form")
|
||||
. " but should have "
|
||||
. ($expected_short ? "short form -$expected_short"
|
||||
: "no short form")
|
||||
. "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Check that the POD headers are in standard order. Only major, required
|
||||
# headers are checked. For example, there maybe be other headers between
|
||||
# DESCRIPTION and OPTIONS, but these are ignored.
|
||||
sub check_pod_header_order {
|
||||
my @std_hdrs = (
|
||||
'NAME',
|
||||
'SYNOPSIS',
|
||||
'RISKS',
|
||||
'DESCRIPTION',
|
||||
'OPTIONS',
|
||||
'DOWNLOADING',
|
||||
'ENVIRONMENT',
|
||||
'SYSTEM REQUIREMENTS',
|
||||
'BUGS',
|
||||
'AUTHORS',
|
||||
'COPYRIGHT, LICENSE, AND WARRANTY',
|
||||
'VERSION',
|
||||
);
|
||||
|
||||
my @hdrs;
|
||||
foreach my $hdr ( split(/\n/, `grep '^=head1' $tool_file`) ) {
|
||||
$hdr =~ s/^=head1 //;
|
||||
if ( $hdr =~ s/\s+$// ) {
|
||||
print "Extra space after $hdr\n";
|
||||
}
|
||||
push @hdrs, $hdr if grep { $hdr eq $_ } @std_hdrs;
|
||||
}
|
||||
|
||||
my $fmt = "%-32s %-32s\n";
|
||||
for my $i ( 0..$#std_hdrs ) {
|
||||
if ( ($hdrs[$i] || '') ne $std_hdrs[$i] ) {
|
||||
$exit_status = 1;
|
||||
print "$tool_name has missing or out-of-order standard headers:\n";
|
||||
printf $fmt, 'ACTUAL', 'CORRECT';
|
||||
printf $fmt, '=' x 32, '=' x 32;
|
||||
map { printf $fmt, ($hdrs[$_] || ''), $std_hdrs[$_] }
|
||||
grep { ($hdrs[$_] || '') ne $std_hdrs[$_] }
|
||||
($i..$#std_hdrs);
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub check_pod_formatting {
|
||||
my ($fh) = @_;
|
||||
|
||||
my $output = `perldoc -T $tool_file 2>&1`;
|
||||
# unlike() will print the whole POD if this fails; ok() is more terse.
|
||||
if ( $output =~ m/can't break/ ) {
|
||||
$exit_status = 1;
|
||||
print "$tool_name POD has lines that are too long\n";
|
||||
}
|
||||
|
||||
chomp(my $podchecker = `which podchecker`);
|
||||
if ( $podchecker ) {
|
||||
$output = `$podchecker $tool_file 2>&1`;
|
||||
if ( $output !~ m/pod syntax OK/ ) {
|
||||
$exit_status = 1;
|
||||
print "$output\n";
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub check_option_usage {
|
||||
my ($fh) = @_;
|
||||
|
||||
# help and version are special opts, intrinsic to OptionParser.
|
||||
# The other opts are usually processed all at once by calling
|
||||
# DSNParser::parse_options().
|
||||
my %ignore = qw(
|
||||
version 1
|
||||
help 1
|
||||
charset 1
|
||||
defaults-file 1
|
||||
host 1
|
||||
password 1
|
||||
port 1
|
||||
socket 1
|
||||
user 1
|
||||
);
|
||||
|
||||
my $contents = do { local $/ = undef; <$fh> };
|
||||
my @options = grep { !$ignore{$_} }
|
||||
map { s/^\[no\]//; $_; }
|
||||
$contents =~ m/^=item --(.+)$/gm;
|
||||
my @unused = grep {
|
||||
chomp(my $get = `grep -c "get('$_')" $tool_file`);
|
||||
chomp(my $got = `grep -c "got('$_')" $tool_file`);
|
||||
$get ||= 0;
|
||||
$got ||= 0;
|
||||
my $used = $get + $got;
|
||||
!$used;
|
||||
} @options;
|
||||
|
||||
if ( @unused ) {
|
||||
$exit_status = 1;
|
||||
print "$tool_name has unused options:\n"
|
||||
. join('', map { "\t--$_\n" } @unused);
|
||||
}
|
||||
|
||||
(my $pkg = $tool_name) =~ s/-/_/g;
|
||||
my $main = `grep -A 1000 $pkg $tool_file`;
|
||||
if ( $main !~ m/->parse_options\(/ ) {
|
||||
$exit_status = 1;
|
||||
print "$tool_name does not call DSNParser::parse_options()\n";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
89
util/parse-aspell-output
Executable file
89
util/parse-aspell-output
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# This script parses the output of ispell/aspell --pipe into something
|
||||
# meaningful. The output is like:
|
||||
#
|
||||
# @(#) International Ispell Version 3.1.20 (but really Aspell 0.60.6)
|
||||
# & mk 50 0: Mk, km, mks, ml, K, M, k, ...
|
||||
# *
|
||||
# *
|
||||
# *
|
||||
# *
|
||||
#
|
||||
# *
|
||||
# *
|
||||
# & mk 50 6: Mk, km, mks, ml, K, M, k, ...
|
||||
#
|
||||
# Spelling errors are the "& WORD COUNT OFFSET: SUGGESTIONS" lines. We
|
||||
# don't care about COUNT and OFFSET is per-word (or so it seems), so it's
|
||||
# not helpful to us either. We also don't care about the suggestions.
|
||||
#
|
||||
# What we care about is on which line the bad WORD appears. Lines are
|
||||
# separated by blank lines in the output; so that output reflects 2 lines
|
||||
# in the input. The asterisk lines are good/spelled correctly words.
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
|
||||
use English qw(-no_match_vars);
|
||||
use Data::Dumper;
|
||||
|
||||
my ($ispell_output, $pod_text) = @ARGV;
|
||||
die "No ispell output file given" unless $ispell_output && -f $ispell_output;
|
||||
die "No POD text file given" unless $pod_text && -f $pod_text;
|
||||
|
||||
my $fh;
|
||||
|
||||
open $fh, '<', $pod_text or die "Cannot open $pod_text: $OS_ERROR";
|
||||
my @pod = <$fh>;
|
||||
close $fh;
|
||||
|
||||
open $fh, '<', $ispell_output or die "Cannot open $ispell_output: $OS_ERROR";
|
||||
|
||||
my $pod_lineno = 1;
|
||||
my $i = 0;
|
||||
my $j = 0;
|
||||
LINE:
|
||||
while ( defined(my $line = <$fh>) ) {
|
||||
if ( $line =~ m/^\s*$/ ) {
|
||||
$pod_lineno++;
|
||||
next LINE;
|
||||
}
|
||||
|
||||
my ($word, $correct) = $line =~ m/^& (\w+) \d+ \d+: (.+)/;
|
||||
next LINE unless $word;
|
||||
|
||||
next LINE if $word eq 'mk';
|
||||
|
||||
if ( $i < $pod_lineno ) {
|
||||
for my $pod_line ( $j..$#pod ) {
|
||||
$i++ if $pod[$j++] ne "\n";
|
||||
last if $i == $pod_lineno;
|
||||
}
|
||||
}
|
||||
|
||||
my $pod_line = $pod[$j - 1];
|
||||
|
||||
next LINE if $pod_line =~ m/^\s*(?:type|short form): [\w-]+/;
|
||||
|
||||
next LINE if $word =~ m/utf/i && $pod_line =~ m/utf8/i;
|
||||
|
||||
next LINE if $pod_line =~ m/^\s+--$word$/;
|
||||
|
||||
next LINE if $word eq 'maatkit' && $pod_line =~ m/maatkit manpage/;
|
||||
next LINE if $word eq 'maatkit' && $pod_line =~ m{http://code.google.com/p/maatkit/};
|
||||
next LINE if $word eq 'dsn' && $pod_line =~ m/dsn: \w+/;
|
||||
next LINE if $word eq 'tmp' && $pod_line =~ m/tmp table/;
|
||||
next LINE if $word eq 'toolname' && $pod_line =~ m/Where "toolname"/;
|
||||
|
||||
$pod_line =~ s/^\s+//;
|
||||
my @correct = map { s/^s+//g; s/\s+$//g; $_ } split(',', $correct);
|
||||
|
||||
print " Misspelled: $word\n"
|
||||
. " Suggestions: " . join(', ',
|
||||
grep { defined $_ } map { $correct[$_] } (0..2)) . "\n"
|
||||
. " Line: $pod_line\n";
|
||||
}
|
||||
|
||||
close $fh;
|
||||
exit;
|
Reference in New Issue
Block a user