~percona-toolkit-dev/percona-toolkit/pqd-enhanced-resume-file

3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1
#!/usr/bin/env perl
2
12 by Daniel Nichter
Remove duplicate copyright notices. Add POD and copyright for Aspersa tools. Fix checking for "pt-pmp" instead of "pmp", etc.
3
# This program is part of Percona Toolkit: http://www.percona.com/software/
4
# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
5
# notices and disclaimers.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
6
7
use strict;
8
use warnings FATAL => 'all';
395.1.4 by Brian Fraser
Final update-modules before the release
9
10
# This tool is "fat-packed": most of its dependent modules are embedded
11
# in this file.  Setting %INC to this file for each module makes Perl aware
12
# of this so it will not try to load the module from @INC.  See the tool's
13
# documentation for a full list of dependencies.
14
BEGIN {
15
   $INC{$_} = __FILE__ for map { (my $pkg = "$_.pm") =~ s!::!/!g; $pkg } (qw(
16
      OptionParser
17
      Daemon
18
   ));
19
}
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
20
21
# ###########################################################################
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
22
# OptionParser package
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
23
# This package is a copy without comments from the original.  The original
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
24
# with comments and its test file can be found in the Bazaar repository at,
25
#   lib/OptionParser.pm
26
#   t/lib/OptionParser.t
27
# See https://launchpad.net/percona-toolkit for more information.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
28
# ###########################################################################
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
29
{
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
30
package OptionParser;
31
32
use strict;
33
use warnings FATAL => 'all';
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
34
use English qw(-no_match_vars);
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
35
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
36
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
37
use List::Util qw(max);
38
use Getopt::Long;
580.1.3 by Brian Fraser
Build percona-toolkit-2.2.2
39
use Data::Dumper;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
40
41
my $POD_link_re = '[LC]<"?([^">]+)"?>';
42
43
sub new {
44
   my ( $class, %args ) = @_;
45
   my @required_args = qw();
46
   foreach my $arg ( @required_args ) {
47
      die "I need a $arg argument" unless $args{$arg};
48
   }
49
50
   my ($program_name) = $PROGRAM_NAME =~ m/([.A-Za-z-]+)$/;
51
   $program_name ||= $PROGRAM_NAME;
52
   my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.';
53
54
   my %attributes = (
55
      'type'       => 1,
56
      'short form' => 1,
57
      'group'      => 1,
58
      'default'    => 1,
59
      'cumulative' => 1,
60
      'negatable'  => 1,
61
   );
62
63
   my $self = {
64
      head1             => 'OPTIONS',        # These args are used internally
65
      skip_rules        => 0,                # to instantiate another Option-
66
      item              => '--(.*)',         # Parser obj that parses the
67
      attributes        => \%attributes,     # DSN OPTIONS section.  Tools
68
      parse_attributes  => \&_parse_attribs, # don't tinker with these args.
69
70
      %args,
71
72
      strict            => 1,  # disabled by a special rule
73
      program_name      => $program_name,
74
      opts              => {},
75
      got_opts          => 0,
76
      short_opts        => {},
77
      defaults          => {},
78
      groups            => {},
79
      allowed_groups    => {},
80
      errors            => [],
81
      rules             => [],  # desc of rules for --help
82
      mutex             => [],  # rule: opts are mutually exclusive
83
      atleast1          => [],  # rule: at least one opt is required
84
      disables          => {},  # rule: opt disables other opts 
85
      defaults_to       => {},  # rule: opt defaults to value of other opt
86
      DSNParser         => undef,
87
      default_files     => [
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
88
         "/etc/percona-toolkit/percona-toolkit.conf",
89
         "/etc/percona-toolkit/$program_name.conf",
90
         "$home/.percona-toolkit.conf",
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
91
         "$home/.$program_name.conf",
92
      ],
93
      types             => {
94
         string => 's', # standard Getopt type
95
         int    => 'i', # standard Getopt type
96
         float  => 'f', # standard Getopt type
97
         Hash   => 'H', # hash, formed from a comma-separated list
98
         hash   => 'h', # hash as above, but only if a value is given
99
         Array  => 'A', # array, similar to Hash
100
         array  => 'a', # array, similar to hash
101
         DSN    => 'd', # DSN
102
         size   => 'z', # size with kMG suffix (powers of 2^10)
103
         time   => 'm', # time, with an optional suffix of s/h/m/d
104
      },
105
   };
106
107
   return bless $self, $class;
108
}
109
110
sub get_specs {
111
   my ( $self, $file ) = @_;
112
   $file ||= $self->{file} || __FILE__;
113
   my @specs = $self->_pod_to_specs($file);
114
   $self->_parse_specs(@specs);
115
116
   open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR";
117
   my $contents = do { local $/ = undef; <$fh> };
118
   close $fh;
119
   if ( $contents =~ m/^=head1 DSN OPTIONS/m ) {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
120
      PTDEBUG && _d('Parsing DSN OPTIONS');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
121
      my $dsn_attribs = {
122
         dsn  => 1,
123
         copy => 1,
124
      };
125
      my $parse_dsn_attribs = sub {
126
         my ( $self, $option, $attribs ) = @_;
127
         map {
128
            my $val = $attribs->{$_};
129
            if ( $val ) {
130
               $val    = $val eq 'yes' ? 1
131
                       : $val eq 'no'  ? 0
132
                       :                 $val;
133
               $attribs->{$_} = $val;
134
            }
135
         } keys %$attribs;
136
         return {
137
            key => $option,
138
            %$attribs,
139
         };
140
      };
141
      my $dsn_o = new OptionParser(
142
         description       => 'DSN OPTIONS',
143
         head1             => 'DSN OPTIONS',
144
         dsn               => 0,         # XXX don't infinitely recurse!
145
         item              => '\* (.)',  # key opts are a single character
146
         skip_rules        => 1,         # no rules before opts
147
         attributes        => $dsn_attribs,
148
         parse_attributes  => $parse_dsn_attribs,
149
      );
150
      my @dsn_opts = map {
151
         my $opts = {
152
            key  => $_->{spec}->{key},
153
            dsn  => $_->{spec}->{dsn},
154
            copy => $_->{spec}->{copy},
155
            desc => $_->{desc},
156
         };
157
         $opts;
158
      } $dsn_o->_pod_to_specs($file);
159
      $self->{DSNParser} = DSNParser->new(opts => \@dsn_opts);
160
   }
161
105 by Daniel
Update OptionParser in all tools.
162
   if ( $contents =~ m/^=head1 VERSION\n\n^(.+)$/m ) {
76.1.2 by Daniel Nichter
Update OptionParser in all tools.
163
      $self->{version} = $1;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
164
      PTDEBUG && _d($self->{version});
76.1.2 by Daniel Nichter
Update OptionParser in all tools.
165
   }
166
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
167
   return;
168
}
169
170
sub DSNParser {
171
   my ( $self ) = @_;
172
   return $self->{DSNParser};
173
};
174
175
sub get_defaults_files {
176
   my ( $self ) = @_;
177
   return @{$self->{default_files}};
178
}
179
180
sub _pod_to_specs {
181
   my ( $self, $file ) = @_;
182
   $file ||= $self->{file} || __FILE__;
183
   open my $fh, '<', $file or die "Cannot open $file: $OS_ERROR";
184
185
   my @specs = ();
186
   my @rules = ();
187
   my $para;
188
189
   local $INPUT_RECORD_SEPARATOR = '';
190
   while ( $para = <$fh> ) {
191
      next unless $para =~ m/^=head1 $self->{head1}/;
192
      last;
193
   }
194
195
   while ( $para = <$fh> ) {
196
      last if $para =~ m/^=over/;
197
      next if $self->{skip_rules};
198
      chomp $para;
199
      $para =~ s/\s+/ /g;
200
      $para =~ s/$POD_link_re/$1/go;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
201
      PTDEBUG && _d('Option rule:', $para);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
202
      push @rules, $para;
203
   }
204
205
   die "POD has no $self->{head1} section" unless $para;
206
207
   do {
208
      if ( my ($option) = $para =~ m/^=item $self->{item}/ ) {
209
         chomp $para;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
210
         PTDEBUG && _d($para);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
211
         my %attribs;
212
213
         $para = <$fh>; # read next paragraph, possibly attributes
214
215
         if ( $para =~ m/: / ) { # attributes
216
            $para =~ s/\s+\Z//g;
217
            %attribs = map {
218
                  my ( $attrib, $val) = split(/: /, $_);
219
                  die "Unrecognized attribute for --$option: $attrib"
220
                     unless $self->{attributes}->{$attrib};
221
                  ($attrib, $val);
222
               } split(/; /, $para);
223
            if ( $attribs{'short form'} ) {
224
               $attribs{'short form'} =~ s/-//;
225
            }
226
            $para = <$fh>; # read next paragraph, probably short help desc
227
         }
228
         else {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
229
            PTDEBUG && _d('Option has no attributes');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
230
         }
231
232
         $para =~ s/\s+\Z//g;
233
         $para =~ s/\s+/ /g;
234
         $para =~ s/$POD_link_re/$1/go;
235
236
         $para =~ s/\.(?:\n.*| [A-Z].*|\Z)//s;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
237
         PTDEBUG && _d('Short help:', $para);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
238
239
         die "No description after option spec $option" if $para =~ m/^=item/;
240
241
         if ( my ($base_option) =  $option =~ m/^\[no\](.*)/ ) {
242
            $option = $base_option;
243
            $attribs{'negatable'} = 1;
244
         }
245
246
         push @specs, {
247
            spec  => $self->{parse_attributes}->($self, $option, \%attribs), 
248
            desc  => $para
249
               . (defined $attribs{default} ? " (default $attribs{default})" : ''),
250
            group => ($attribs{'group'} ? $attribs{'group'} : 'default'),
251
         };
252
      }
253
      while ( $para = <$fh> ) {
254
         last unless $para;
255
         if ( $para =~ m/^=head1/ ) {
256
            $para = undef; # Can't 'last' out of a do {} block.
257
            last;
258
         }
259
         last if $para =~ m/^=item /;
260
      }
261
   } while ( $para );
262
263
   die "No valid specs in $self->{head1}" unless @specs;
264
265
   close $fh;
266
   return @specs, @rules;
267
}
268
269
sub _parse_specs {
270
   my ( $self, @specs ) = @_;
271
   my %disables; # special rule that requires deferred checking
272
273
   foreach my $opt ( @specs ) {
274
      if ( ref $opt ) { # It's an option spec, not a rule.
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
275
         PTDEBUG && _d('Parsing opt spec:',
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
276
            map { ($_, '=>', $opt->{$_}) } keys %$opt);
277
278
         my ( $long, $short ) = $opt->{spec} =~ m/^([\w-]+)(?:\|([^!+=]*))?/;
279
         if ( !$long ) {
280
            die "Cannot parse long option from spec $opt->{spec}";
281
         }
282
         $opt->{long} = $long;
283
284
         die "Duplicate long option --$long" if exists $self->{opts}->{$long};
285
         $self->{opts}->{$long} = $opt;
286
287
         if ( length $long == 1 ) {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
288
            PTDEBUG && _d('Long opt', $long, 'looks like short opt');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
289
            $self->{short_opts}->{$long} = $long;
290
         }
291
292
         if ( $short ) {
293
            die "Duplicate short option -$short"
294
               if exists $self->{short_opts}->{$short};
295
            $self->{short_opts}->{$short} = $long;
296
            $opt->{short} = $short;
297
         }
298
         else {
299
            $opt->{short} = undef;
300
         }
301
435.5.1 by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm
302
         $opt->{is_negatable}  = $opt->{spec} =~ m/!/        ? 1 : 0;
303
         $opt->{is_cumulative} = $opt->{spec} =~ m/\+/       ? 1 : 0;
304
         $opt->{is_required}   = $opt->{desc} =~ m/required/ ? 1 : 0;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
305
306
         $opt->{group} ||= 'default';
307
         $self->{groups}->{ $opt->{group} }->{$long} = 1;
308
309
         $opt->{value} = undef;
310
         $opt->{got}   = 0;
311
312
         my ( $type ) = $opt->{spec} =~ m/=(.)/;
313
         $opt->{type} = $type;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
314
         PTDEBUG && _d($long, 'type:', $type);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
315
316
317
         $opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
318
319
         if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
320
            $self->{defaults}->{$long} = defined $def ? $def : 1;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
321
            PTDEBUG && _d($long, 'default:', $def);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
322
         }
323
324
         if ( $long eq 'config' ) {
325
            $self->{defaults}->{$long} = join(',', $self->get_defaults_files());
326
         }
327
328
         if ( (my ($dis) = $opt->{desc} =~ m/(disables .*)/) ) {
329
            $disables{$long} = $dis;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
330
            PTDEBUG && _d('Deferring check of disables rule for', $opt, $dis);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
331
         }
332
333
         $self->{opts}->{$long} = $opt;
334
      }
335
      else { # It's an option rule, not a spec.
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
336
         PTDEBUG && _d('Parsing rule:', $opt); 
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
337
         push @{$self->{rules}}, $opt;
338
         my @participants = $self->_get_participants($opt);
339
         my $rule_ok = 0;
340
341
         if ( $opt =~ m/mutually exclusive|one and only one/ ) {
342
            $rule_ok = 1;
343
            push @{$self->{mutex}}, \@participants;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
344
            PTDEBUG && _d(@participants, 'are mutually exclusive');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
345
         }
346
         if ( $opt =~ m/at least one|one and only one/ ) {
347
            $rule_ok = 1;
348
            push @{$self->{atleast1}}, \@participants;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
349
            PTDEBUG && _d(@participants, 'require at least one');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
350
         }
351
         if ( $opt =~ m/default to/ ) {
352
            $rule_ok = 1;
353
            $self->{defaults_to}->{$participants[0]} = $participants[1];
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
354
            PTDEBUG && _d($participants[0], 'defaults to', $participants[1]);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
355
         }
356
         if ( $opt =~ m/restricted to option groups/ ) {
357
            $rule_ok = 1;
358
            my ($groups) = $opt =~ m/groups ([\w\s\,]+)/;
359
            my @groups = split(',', $groups);
360
            %{$self->{allowed_groups}->{$participants[0]}} = map {
361
               s/\s+//;
362
               $_ => 1;
363
            } @groups;
364
         }
365
         if( $opt =~ m/accepts additional command-line arguments/ ) {
366
            $rule_ok = 1;
367
            $self->{strict} = 0;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
368
            PTDEBUG && _d("Strict mode disabled by rule");
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
369
         }
370
371
         die "Unrecognized option rule: $opt" unless $rule_ok;
372
      }
373
   }
374
375
   foreach my $long ( keys %disables ) {
376
      my @participants = $self->_get_participants($disables{$long});
377
      $self->{disables}->{$long} = \@participants;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
378
      PTDEBUG && _d('Option', $long, 'disables', @participants);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
379
   }
380
381
   return; 
382
}
383
384
sub _get_participants {
385
   my ( $self, $str ) = @_;
386
   my @participants;
387
   foreach my $long ( $str =~ m/--(?:\[no\])?([\w-]+)/g ) {
388
      die "Option --$long does not exist while processing rule $str"
389
         unless exists $self->{opts}->{$long};
390
      push @participants, $long;
391
   }
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
392
   PTDEBUG && _d('Participants for', $str, ':', @participants);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
393
   return @participants;
394
}
395
396
sub opts {
397
   my ( $self ) = @_;
398
   my %opts = %{$self->{opts}};
399
   return %opts;
400
}
401
402
sub short_opts {
403
   my ( $self ) = @_;
404
   my %short_opts = %{$self->{short_opts}};
405
   return %short_opts;
406
}
407
408
sub set_defaults {
409
   my ( $self, %defaults ) = @_;
410
   $self->{defaults} = {};
411
   foreach my $long ( keys %defaults ) {
412
      die "Cannot set default for nonexistent option $long"
413
         unless exists $self->{opts}->{$long};
414
      $self->{defaults}->{$long} = $defaults{$long};
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
415
      PTDEBUG && _d('Default val for', $long, ':', $defaults{$long});
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
416
   }
417
   return;
418
}
419
420
sub get_defaults {
421
   my ( $self ) = @_;
422
   return $self->{defaults};
423
}
424
425
sub get_groups {
426
   my ( $self ) = @_;
427
   return $self->{groups};
428
}
429
430
sub _set_option {
431
   my ( $self, $opt, $val ) = @_;
432
   my $long = exists $self->{opts}->{$opt}       ? $opt
433
            : exists $self->{short_opts}->{$opt} ? $self->{short_opts}->{$opt}
434
            : die "Getopt::Long gave a nonexistent option: $opt";
435
436
   $opt = $self->{opts}->{$long};
437
   if ( $opt->{is_cumulative} ) {
438
      $opt->{value}++;
439
   }
435.5.1 by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm
440
   else {
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
441
      $opt->{value} = $val;
442
   }
443
   $opt->{got} = 1;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
444
   PTDEBUG && _d('Got option', $long, '=', $val);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
445
}
446
447
sub get_opts {
448
   my ( $self ) = @_; 
449
450
   foreach my $long ( keys %{$self->{opts}} ) {
451
      $self->{opts}->{$long}->{got} = 0;
452
      $self->{opts}->{$long}->{value}
453
         = exists $self->{defaults}->{$long}       ? $self->{defaults}->{$long}
454
         : $self->{opts}->{$long}->{is_cumulative} ? 0
455
         : undef;
456
   }
457
   $self->{got_opts} = 0;
458
459
   $self->{errors} = [];
460
461
   if ( @ARGV && $ARGV[0] eq "--config" ) {
462
      shift @ARGV;
463
      $self->_set_option('config', shift @ARGV);
464
   }
465
   if ( $self->has('config') ) {
466
      my @extra_args;
467
      foreach my $filename ( split(',', $self->get('config')) ) {
468
         eval {
469
            push @extra_args, $self->_read_config_file($filename);
470
         };
471
         if ( $EVAL_ERROR ) {
472
            if ( $self->got('config') ) {
473
               die $EVAL_ERROR;
474
            }
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
475
            elsif ( PTDEBUG ) {
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
476
               _d($EVAL_ERROR);
477
            }
478
         }
479
      }
480
      unshift @ARGV, @extra_args;
481
   }
482
483
   Getopt::Long::Configure('no_ignore_case', 'bundling');
484
   GetOptions(
485
      map    { $_->{spec} => sub { $self->_set_option(@_); } }
486
      grep   { $_->{long} ne 'config' } # --config is handled specially above.
487
      values %{$self->{opts}}
488
   ) or $self->save_error('Error parsing options');
489
490
   if ( exists $self->{opts}->{version} && $self->{opts}->{version}->{got} ) {
76.1.2 by Daniel Nichter
Update OptionParser in all tools.
491
      if ( $self->{version} ) {
492
         print $self->{version}, "\n";
493
      }
494
      else {
495
         print "Error parsing version.  See the VERSION section of the tool's documentation.\n";
496
      }
424.1.3 by Daniel Nichter
Update OptionParser in all tools.
497
      exit 1;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
498
   }
499
500
   if ( @ARGV && $self->{strict} ) {
501
      $self->save_error("Unrecognized command-line options @ARGV");
502
   }
503
504
   foreach my $mutex ( @{$self->{mutex}} ) {
505
      my @set = grep { $self->{opts}->{$_}->{got} } @$mutex;
506
      if ( @set > 1 ) {
507
         my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" }
508
                      @{$mutex}[ 0 .. scalar(@$mutex) - 2] )
509
                 . ' and --'.$self->{opts}->{$mutex->[-1]}->{long}
510
                 . ' are mutually exclusive.';
511
         $self->save_error($err);
512
      }
513
   }
514
515
   foreach my $required ( @{$self->{atleast1}} ) {
516
      my @set = grep { $self->{opts}->{$_}->{got} } @$required;
517
      if ( @set == 0 ) {
518
         my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" }
519
                      @{$required}[ 0 .. scalar(@$required) - 2] )
520
                 .' or --'.$self->{opts}->{$required->[-1]}->{long};
521
         $self->save_error("Specify at least one of $err");
522
      }
523
   }
524
525
   $self->_check_opts( keys %{$self->{opts}} );
526
   $self->{got_opts} = 1;
527
   return;
528
}
529
530
sub _check_opts {
531
   my ( $self, @long ) = @_;
532
   my $long_last = scalar @long;
533
   while ( @long ) {
534
      foreach my $i ( 0..$#long ) {
535
         my $long = $long[$i];
536
         next unless $long;
537
         my $opt  = $self->{opts}->{$long};
538
         if ( $opt->{got} ) {
539
            if ( exists $self->{disables}->{$long} ) {
540
               my @disable_opts = @{$self->{disables}->{$long}};
541
               map { $self->{opts}->{$_}->{value} = undef; } @disable_opts;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
542
               PTDEBUG && _d('Unset options', @disable_opts,
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
543
                  'because', $long,'disables them');
544
            }
545
546
            if ( exists $self->{allowed_groups}->{$long} ) {
547
548
               my @restricted_groups = grep {
549
                  !exists $self->{allowed_groups}->{$long}->{$_}
550
               } keys %{$self->{groups}};
551
552
               my @restricted_opts;
553
               foreach my $restricted_group ( @restricted_groups ) {
554
                  RESTRICTED_OPT:
555
                  foreach my $restricted_opt (
556
                     keys %{$self->{groups}->{$restricted_group}} )
557
                  {
558
                     next RESTRICTED_OPT if $restricted_opt eq $long;
559
                     push @restricted_opts, $restricted_opt
560
                        if $self->{opts}->{$restricted_opt}->{got};
561
                  }
562
               }
563
564
               if ( @restricted_opts ) {
565
                  my $err;
566
                  if ( @restricted_opts == 1 ) {
567
                     $err = "--$restricted_opts[0]";
568
                  }
569
                  else {
570
                     $err = join(', ',
571
                               map { "--$self->{opts}->{$_}->{long}" }
572
                               grep { $_ } 
573
                               @restricted_opts[0..scalar(@restricted_opts) - 2]
574
                            )
575
                          . ' or --'.$self->{opts}->{$restricted_opts[-1]}->{long};
576
                  }
577
                  $self->save_error("--$long is not allowed with $err");
578
               }
579
            }
580
581
         }
582
         elsif ( $opt->{is_required} ) { 
583
            $self->save_error("Required option --$long must be specified");
584
         }
585
586
         $self->_validate_type($opt);
587
         if ( $opt->{parsed} ) {
588
            delete $long[$i];
589
         }
590
         else {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
591
            PTDEBUG && _d('Temporarily failed to parse', $long);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
592
         }
593
      }
594
595
      die "Failed to parse options, possibly due to circular dependencies"
596
         if @long == $long_last;
597
      $long_last = @long;
598
   }
599
600
   return;
601
}
602
603
sub _validate_type {
604
   my ( $self, $opt ) = @_;
605
   return unless $opt;
606
607
   if ( !$opt->{type} ) {
608
      $opt->{parsed} = 1;
609
      return;
610
   }
611
612
   my $val = $opt->{value};
613
614
   if ( $val && $opt->{type} eq 'm' ) {  # type time
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
615
      PTDEBUG && _d('Parsing option', $opt->{long}, 'as a time value');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
616
      my ( $prefix, $num, $suffix ) = $val =~ m/([+-]?)(\d+)([a-z])?$/;
617
      if ( !$suffix ) {
618
         my ( $s ) = $opt->{desc} =~ m/\(suffix (.)\)/;
619
         $suffix = $s || 's';
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
620
         PTDEBUG && _d('No suffix given; using', $suffix, 'for',
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
621
            $opt->{long}, '(value:', $val, ')');
622
      }
623
      if ( $suffix =~ m/[smhd]/ ) {
624
         $val = $suffix eq 's' ? $num            # Seconds
625
              : $suffix eq 'm' ? $num * 60       # Minutes
626
              : $suffix eq 'h' ? $num * 3600     # Hours
627
              :                  $num * 86400;   # Days
628
         $opt->{value} = ($prefix || '') . $val;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
629
         PTDEBUG && _d('Setting option', $opt->{long}, 'to', $val);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
630
      }
631
      else {
632
         $self->save_error("Invalid time suffix for --$opt->{long}");
633
      }
634
   }
635
   elsif ( $val && $opt->{type} eq 'd' ) {  # type DSN
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
636
      PTDEBUG && _d('Parsing option', $opt->{long}, 'as a DSN');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
637
      my $prev = {};
638
      my $from_key = $self->{defaults_to}->{ $opt->{long} };
639
      if ( $from_key ) {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
640
         PTDEBUG && _d($opt->{long}, 'DSN copies from', $from_key, 'DSN');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
641
         if ( $self->{opts}->{$from_key}->{parsed} ) {
642
            $prev = $self->{opts}->{$from_key}->{value};
643
         }
644
         else {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
645
            PTDEBUG && _d('Cannot parse', $opt->{long}, 'until',
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
646
               $from_key, 'parsed');
647
            return;
648
         }
649
      }
650
      my $defaults = $self->{DSNParser}->parse_options($self);
651
      $opt->{value} = $self->{DSNParser}->parse($val, $prev, $defaults);
652
   }
653
   elsif ( $val && $opt->{type} eq 'z' ) {  # type size
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
654
      PTDEBUG && _d('Parsing option', $opt->{long}, 'as a size value');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
655
      $self->_parse_size($opt, $val);
656
   }
657
   elsif ( $opt->{type} eq 'H' || (defined $val && $opt->{type} eq 'h') ) {
658
      $opt->{value} = { map { $_ => 1 } split(/(?<!\\),\s*/, ($val || '')) };
659
   }
660
   elsif ( $opt->{type} eq 'A' || (defined $val && $opt->{type} eq 'a') ) {
661
      $opt->{value} = [ split(/(?<!\\),\s*/, ($val || '')) ];
662
   }
663
   else {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
664
      PTDEBUG && _d('Nothing to validate for option',
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
665
         $opt->{long}, 'type', $opt->{type}, 'value', $val);
666
   }
667
668
   $opt->{parsed} = 1;
669
   return;
670
}
671
672
sub get {
673
   my ( $self, $opt ) = @_;
674
   my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt);
675
   die "Option $opt does not exist"
676
      unless $long && exists $self->{opts}->{$long};
677
   return $self->{opts}->{$long}->{value};
678
}
679
680
sub got {
681
   my ( $self, $opt ) = @_;
682
   my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt);
683
   die "Option $opt does not exist"
684
      unless $long && exists $self->{opts}->{$long};
685
   return $self->{opts}->{$long}->{got};
686
}
687
688
sub has {
689
   my ( $self, $opt ) = @_;
690
   my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt);
691
   return defined $long ? exists $self->{opts}->{$long} : 0;
692
}
693
694
sub set {
695
   my ( $self, $opt, $val ) = @_;
696
   my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt);
697
   die "Option $opt does not exist"
698
      unless $long && exists $self->{opts}->{$long};
699
   $self->{opts}->{$long}->{value} = $val;
700
   return;
701
}
702
703
sub save_error {
704
   my ( $self, $error ) = @_;
705
   push @{$self->{errors}}, $error;
706
   return;
707
}
708
709
sub errors {
710
   my ( $self ) = @_;
711
   return $self->{errors};
712
}
713
714
sub usage {
715
   my ( $self ) = @_;
716
   warn "No usage string is set" unless $self->{usage}; # XXX
717
   return "Usage: " . ($self->{usage} || '') . "\n";
718
}
719
720
sub descr {
721
   my ( $self ) = @_;
722
   warn "No description string is set" unless $self->{description}; # XXX
723
   my $descr  = ($self->{description} || $self->{program_name} || '')
724
              . "  For more details, please use the --help option, "
725
              . "or try 'perldoc $PROGRAM_NAME' "
726
              . "for complete documentation.";
727
   $descr = join("\n", $descr =~ m/(.{0,80})(?:\s+|$)/g)
728
      unless $ENV{DONT_BREAK_LINES};
729
   $descr =~ s/ +$//mg;
730
   return $descr;
731
}
732
733
sub usage_or_errors {
734
   my ( $self, $file, $return ) = @_;
735
   $file ||= $self->{file} || __FILE__;
736
737
   if ( !$self->{description} || !$self->{usage} ) {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
738
      PTDEBUG && _d("Getting description and usage from SYNOPSIS in", $file);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
739
      my %synop = $self->_parse_synopsis($file);
740
      $self->{description} ||= $synop{description};
741
      $self->{usage}       ||= $synop{usage};
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
742
      PTDEBUG && _d("Description:", $self->{description},
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
743
         "\nUsage:", $self->{usage});
744
   }
745
746
   if ( $self->{opts}->{help}->{got} ) {
747
      print $self->print_usage() or die "Cannot print usage: $OS_ERROR";
748
      exit 0 unless $return;
749
   }
750
   elsif ( scalar @{$self->{errors}} ) {
751
      print $self->print_errors() or die "Cannot print errors: $OS_ERROR";
424.1.3 by Daniel Nichter
Update OptionParser in all tools.
752
      exit 1 unless $return;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
753
   }
754
755
   return;
756
}
757
758
sub print_errors {
759
   my ( $self ) = @_;
760
   my $usage = $self->usage() . "\n";
761
   if ( (my @errors = @{$self->{errors}}) ) {
762
      $usage .= join("\n  * ", 'Errors in command-line arguments:', @errors)
763
              . "\n";
764
   }
765
   return $usage . "\n" . $self->descr();
766
}
767
768
sub print_usage {
769
   my ( $self ) = @_;
770
   die "Run get_opts() before print_usage()" unless $self->{got_opts};
771
   my @opts = values %{$self->{opts}};
772
773
   my $maxl = max(
774
      map {
775
         length($_->{long})               # option long name
776
         + ($_->{is_negatable} ? 4 : 0)   # "[no]" if opt is negatable
777
         + ($_->{type} ? 2 : 0)           # "=x" where x is the opt type
778
      }
779
      @opts);
780
781
   my $maxs = max(0,
782
      map {
783
         length($_)
784
         + ($self->{opts}->{$_}->{is_negatable} ? 4 : 0)
785
         + ($self->{opts}->{$_}->{type} ? 2 : 0)
786
      }
787
      values %{$self->{short_opts}});
788
789
   my $lcol = max($maxl, ($maxs + 3));
790
   my $rcol = 80 - $lcol - 6;
791
   my $rpad = ' ' x ( 80 - $rcol );
792
793
   $maxs = max($lcol - 3, $maxs);
794
795
   my $usage = $self->descr() . "\n" . $self->usage();
796
797
   my @groups = reverse sort grep { $_ ne 'default'; } keys %{$self->{groups}};
798
   push @groups, 'default';
799
800
   foreach my $group ( reverse @groups ) {
801
      $usage .= "\n".($group eq 'default' ? 'Options' : $group).":\n\n";
802
      foreach my $opt (
803
         sort { $a->{long} cmp $b->{long} }
804
         grep { $_->{group} eq $group }
805
         @opts )
806
      {
807
         my $long  = $opt->{is_negatable} ? "[no]$opt->{long}" : $opt->{long};
808
         my $short = $opt->{short};
809
         my $desc  = $opt->{desc};
810
811
         $long .= $opt->{type} ? "=$opt->{type}" : "";
812
813
         if ( $opt->{type} && $opt->{type} eq 'm' ) {
814
            my ($s) = $desc =~ m/\(suffix (.)\)/;
815
            $s    ||= 's';
816
            $desc =~ s/\s+\(suffix .\)//;
817
            $desc .= ".  Optional suffix s=seconds, m=minutes, h=hours, "
818
                   . "d=days; if no suffix, $s is used.";
819
         }
472.1.2 by Brian Fraser
Update modules for all tools using DSNParser
820
         $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol}(?!\W))(?:\s+|(?<=\W)|$)/g);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
821
         $desc =~ s/ +$//mg;
822
         if ( $short ) {
823
            $usage .= sprintf("  --%-${maxs}s -%s  %s\n", $long, $short, $desc);
824
         }
825
         else {
826
            $usage .= sprintf("  --%-${lcol}s  %s\n", $long, $desc);
827
         }
828
      }
829
   }
830
831
   $usage .= "\nOption types: s=string, i=integer, f=float, h/H/a/A=comma-separated list, d=DSN, z=size, m=time\n";
832
833
   if ( (my @rules = @{$self->{rules}}) ) {
834
      $usage .= "\nRules:\n\n";
835
      $usage .= join("\n", map { "  $_" } @rules) . "\n";
836
   }
837
   if ( $self->{DSNParser} ) {
838
      $usage .= "\n" . $self->{DSNParser}->usage();
839
   }
840
   $usage .= "\nOptions and values after processing arguments:\n\n";
841
   foreach my $opt ( sort { $a->{long} cmp $b->{long} } @opts ) {
842
      my $val   = $opt->{value};
843
      my $type  = $opt->{type} || '';
844
      my $bool  = $opt->{spec} =~ m/^[\w-]+(?:\|[\w-])?!?$/;
845
      $val      = $bool              ? ( $val ? 'TRUE' : 'FALSE' )
846
                : !defined $val      ? '(No value)'
847
                : $type eq 'd'       ? $self->{DSNParser}->as_string($val)
848
                : $type =~ m/H|h/    ? join(',', sort keys %$val)
849
                : $type =~ m/A|a/    ? join(',', @$val)
850
                :                    $val;
851
      $usage .= sprintf("  --%-${lcol}s  %s\n", $opt->{long}, $val);
852
   }
853
   return $usage;
854
}
855
856
sub prompt_noecho {
857
   shift @_ if ref $_[0] eq __PACKAGE__;
858
   my ( $prompt ) = @_;
859
   local $OUTPUT_AUTOFLUSH = 1;
860
   print $prompt
861
      or die "Cannot print: $OS_ERROR";
862
   my $response;
863
   eval {
864
      require Term::ReadKey;
865
      Term::ReadKey::ReadMode('noecho');
866
      chomp($response = <STDIN>);
867
      Term::ReadKey::ReadMode('normal');
868
      print "\n"
869
         or die "Cannot print: $OS_ERROR";
870
   };
871
   if ( $EVAL_ERROR ) {
872
      die "Cannot read response; is Term::ReadKey installed? $EVAL_ERROR";
873
   }
874
   return $response;
875
}
876
877
sub _read_config_file {
878
   my ( $self, $filename ) = @_;
879
   open my $fh, "<", $filename or die "Cannot open $filename: $OS_ERROR\n";
880
   my @args;
881
   my $prefix = '--';
882
   my $parse  = 1;
883
884
   LINE:
885
   while ( my $line = <$fh> ) {
886
      chomp $line;
887
      next LINE if $line =~ m/^\s*(?:\#|\;|$)/;
888
      $line =~ s/\s+#.*$//g;
889
      $line =~ s/^\s+|\s+$//g;
890
      if ( $line eq '--' ) {
891
         $prefix = '';
892
         $parse  = 0;
893
         next LINE;
894
      }
895
      if ( $parse
896
         && (my($opt, $arg) = $line =~ m/^\s*([^=\s]+?)(?:\s*=\s*(.*?)\s*)?$/)
897
      ) {
898
         push @args, grep { defined $_ } ("$prefix$opt", $arg);
899
      }
900
      elsif ( $line =~ m/./ ) {
901
         push @args, $line;
902
      }
903
      else {
904
         die "Syntax error in file $filename at line $INPUT_LINE_NUMBER";
905
      }
906
   }
907
   close $fh;
908
   return @args;
909
}
910
911
sub read_para_after {
912
   my ( $self, $file, $regex ) = @_;
913
   open my $fh, "<", $file or die "Can't open $file: $OS_ERROR";
914
   local $INPUT_RECORD_SEPARATOR = '';
915
   my $para;
916
   while ( $para = <$fh> ) {
917
      next unless $para =~ m/^=pod$/m;
918
      last;
919
   }
920
   while ( $para = <$fh> ) {
921
      next unless $para =~ m/$regex/;
922
      last;
923
   }
924
   $para = <$fh>;
925
   chomp($para);
926
   close $fh or die "Can't close $file: $OS_ERROR";
927
   return $para;
928
}
929
930
sub clone {
931
   my ( $self ) = @_;
932
933
   my %clone = map {
934
      my $hashref  = $self->{$_};
935
      my $val_copy = {};
936
      foreach my $key ( keys %$hashref ) {
937
         my $ref = ref $hashref->{$key};
938
         $val_copy->{$key} = !$ref           ? $hashref->{$key}
939
                           : $ref eq 'HASH'  ? { %{$hashref->{$key}} }
940
                           : $ref eq 'ARRAY' ? [ @{$hashref->{$key}} ]
941
                           : $hashref->{$key};
942
      }
943
      $_ => $val_copy;
944
   } qw(opts short_opts defaults);
945
946
   foreach my $scalar ( qw(got_opts) ) {
947
      $clone{$scalar} = $self->{$scalar};
948
   }
949
950
   return bless \%clone;     
951
}
952
953
sub _parse_size {
954
   my ( $self, $opt, $val ) = @_;
955
956
   if ( lc($val || '') eq 'null' ) {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
957
      PTDEBUG && _d('NULL size for', $opt->{long});
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
958
      $opt->{value} = 'null';
959
      return;
960
   }
961
962
   my %factor_for = (k => 1_024, M => 1_048_576, G => 1_073_741_824);
963
   my ($pre, $num, $factor) = $val =~ m/^([+-])?(\d+)([kMG])?$/;
964
   if ( defined $num ) {
965
      if ( $factor ) {
966
         $num *= $factor_for{$factor};
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
967
         PTDEBUG && _d('Setting option', $opt->{y},
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
968
            'to num', $num, '* factor', $factor);
969
      }
970
      $opt->{value} = ($pre || '') . $num;
971
   }
972
   else {
94.2.184 by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage.
973
      $self->save_error("Invalid size for --$opt->{long}: $val");
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
974
   }
975
   return;
976
}
977
978
sub _parse_attribs {
979
   my ( $self, $option, $attribs ) = @_;
980
   my $types = $self->{types};
981
   return $option
982
      . ($attribs->{'short form'} ? '|' . $attribs->{'short form'}   : '' )
983
      . ($attribs->{'negatable'}  ? '!'                              : '' )
984
      . ($attribs->{'cumulative'} ? '+'                              : '' )
435.5.1 by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm
985
      . ($attribs->{'type'}       ? '=' . $types->{$attribs->{type}} : '' );
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
986
}
987
988
sub _parse_synopsis {
989
   my ( $self, $file ) = @_;
990
   $file ||= $self->{file} || __FILE__;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
991
   PTDEBUG && _d("Parsing SYNOPSIS in", $file);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
992
993
   local $INPUT_RECORD_SEPARATOR = '';  # read paragraphs
994
   open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR";
995
   my $para;
996
   1 while defined($para = <$fh>) && $para !~ m/^=head1 SYNOPSIS/;
997
   die "$file does not contain a SYNOPSIS section" unless $para;
998
   my @synop;
999
   for ( 1..2 ) {  # 1 for the usage, 2 for the description
1000
      my $para = <$fh>;
1001
      push @synop, $para;
1002
   }
1003
   close $fh;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1004
   PTDEBUG && _d("Raw SYNOPSIS text:", @synop);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1005
   my ($usage, $desc) = @synop;
1006
   die "The SYNOPSIS section in $file is not formatted properly"
1007
      unless $usage && $desc;
1008
1009
   $usage =~ s/^\s*Usage:\s+(.+)/$1/;
1010
   chomp $usage;
1011
1012
   $desc =~ s/\n/ /g;
1013
   $desc =~ s/\s{2,}/ /g;
1014
   $desc =~ s/\. ([A-Z][a-z])/.  $1/g;
1015
   $desc =~ s/\s+$//;
1016
1017
   return (
1018
      description => $desc,
1019
      usage       => $usage,
1020
   );
1021
};
1022
580.1.3 by Brian Fraser
Build percona-toolkit-2.2.2
1023
sub set_vars {
1024
   my ($self, $file) = @_;
1025
   $file ||= $self->{file} || __FILE__;
1026
1027
   my %user_vars;
1028
   my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef;
1029
   if ( $user_vars ) {
1030
      foreach my $var_val ( @$user_vars ) {
1031
         my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
1032
         die "Invalid --set-vars value: $var_val\n" unless $var && $val;
1033
         $user_vars{$var} = {
1034
            val     => $val,
1035
            default => 0,
1036
         };
1037
      }
1038
   }
1039
1040
   my %default_vars;
1041
   my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/);
1042
   if ( $default_vars ) {
1043
      %default_vars = map {
1044
         my $var_val = $_;
1045
         my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/;
1046
         die "Invalid --set-vars value: $var_val\n" unless $var && $val;
1047
         $var => {
1048
            val     => $val,
1049
            default => 1,
1050
         };
1051
      } split("\n", $default_vars);
1052
   }
1053
1054
   my %vars = (
1055
      %default_vars, # first the tool's defaults
1056
      %user_vars,    # then the user's which overwrite the defaults
1057
   );
1058
   PTDEBUG && _d('--set-vars:', Dumper(\%vars));
1059
   return \%vars;
1060
}
1061
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1062
sub _d {
1063
   my ($package, undef, $line) = caller 0;
1064
   @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1065
        map { defined $_ ? $_ : 'undef' }
1066
        @_;
1067
   print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1068
}
1069
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1070
if ( PTDEBUG ) {
76.1.2 by Daniel Nichter
Update OptionParser in all tools.
1071
   print '# ', $^X, ' ', $], "\n";
1072
   if ( my $uname = `uname -a` ) {
1073
      $uname =~ s/\s+/ /g;
1074
      print "# $uname\n";
1075
   }
1076
   print '# Arguments: ',
1077
      join(' ', map { my $a = "_[$_]_"; $a =~ s/\n/\n# /g; $a; } @ARGV), "\n";
1078
}
1079
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1080
1;
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
1081
}
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1082
# ###########################################################################
1083
# End OptionParser package
1084
# ###########################################################################
1085
1086
# ###########################################################################
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
1087
# Daemon package
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1088
# This package is a copy without comments from the original.  The original
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
1089
# with comments and its test file can be found in the Bazaar repository at,
1090
#   lib/Daemon.pm
1091
#   t/lib/Daemon.t
1092
# See https://launchpad.net/percona-toolkit for more information.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1093
# ###########################################################################
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
1094
{
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1095
package Daemon;
1096
1097
use strict;
1098
use warnings FATAL => 'all';
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
1099
use English qw(-no_match_vars);
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1100
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1101
1102
use POSIX qw(setsid);
1103
1104
sub new {
1105
   my ( $class, %args ) = @_;
1106
   foreach my $arg ( qw(o) ) {
1107
      die "I need a $arg argument" unless $args{$arg};
1108
   }
1109
   my $o = $args{o};
1110
   my $self = {
1111
      o        => $o,
1112
      log_file => $o->has('log') ? $o->get('log') : undef,
1113
      PID_file => $o->has('pid') ? $o->get('pid') : undef,
1114
   };
1115
1116
   check_PID_file(undef, $self->{PID_file});
1117
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1118
   PTDEBUG && _d('Daemonized child will log to', $self->{log_file});
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1119
   return bless $self, $class;
1120
}
1121
1122
sub daemonize {
1123
   my ( $self ) = @_;
1124
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1125
   PTDEBUG && _d('About to fork and daemonize');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1126
   defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR";
1127
   if ( $pid ) {
212 by Daniel Nichter
Update Daemon in all tools (bug 944420).
1128
      PTDEBUG && _d('Parent PID', $PID, 'exiting after forking child PID',$pid);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1129
      exit;
1130
   }
1131
212 by Daniel Nichter
Update Daemon in all tools (bug 944420).
1132
   PTDEBUG && _d('Daemonizing child PID', $PID);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1133
   $self->{PID_owner} = $PID;
1134
   $self->{child}     = 1;
1135
1136
   POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
1137
   chdir '/'       or die "Cannot chdir to /: $OS_ERROR";
1138
1139
   $self->_make_PID_file();
1140
1141
   $OUTPUT_AUTOFLUSH = 1;
1142
212 by Daniel Nichter
Update Daemon in all tools (bug 944420).
1143
   PTDEBUG && _d('Redirecting STDIN to /dev/null');
1144
   close STDIN;
1145
   open  STDIN, '/dev/null'
1146
      or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1147
1148
   if ( $self->{log_file} ) {
212 by Daniel Nichter
Update Daemon in all tools (bug 944420).
1149
      PTDEBUG && _d('Redirecting STDOUT and STDERR to', $self->{log_file});
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1150
      close STDOUT;
1151
      open  STDOUT, '>>', $self->{log_file}
1152
         or die "Cannot open log file $self->{log_file}: $OS_ERROR";
1153
1154
      close STDERR;
1155
      open  STDERR, ">&STDOUT"
1156
         or die "Cannot dupe STDERR to STDOUT: $OS_ERROR"; 
1157
   }
1158
   else {
1159
      if ( -t STDOUT ) {
212 by Daniel Nichter
Update Daemon in all tools (bug 944420).
1160
         PTDEBUG && _d('No log file and STDOUT is a terminal;',
1161
            'redirecting to /dev/null');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1162
         close STDOUT;
1163
         open  STDOUT, '>', '/dev/null'
1164
            or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR";
1165
      }
1166
      if ( -t STDERR ) {
212 by Daniel Nichter
Update Daemon in all tools (bug 944420).
1167
         PTDEBUG && _d('No log file and STDERR is a terminal;',
1168
            'redirecting to /dev/null');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1169
         close STDERR;
1170
         open  STDERR, '>', '/dev/null'
1171
            or die "Cannot reopen STDERR to /dev/null: $OS_ERROR";
1172
      }
1173
   }
1174
1175
   return;
1176
}
1177
1178
sub check_PID_file {
1179
   my ( $self, $file ) = @_;
1180
   my $PID_file = $self ? $self->{PID_file} : $file;
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1181
   PTDEBUG && _d('Checking PID file', $PID_file);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1182
   if ( $PID_file && -f $PID_file ) {
1183
      my $pid;
94.18.3 by Daniel Nichter
Update Daemon.pm in all tools.
1184
      eval {
1185
         chomp($pid = (slurp_file($PID_file) || ''));
1186
      };
1187
      if ( $EVAL_ERROR ) {
1188
         die "The PID file $PID_file already exists but it cannot be read: "
1189
            . $EVAL_ERROR;
1190
      }
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1191
      PTDEBUG && _d('PID file exists; it contains PID', $pid);
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1192
      if ( $pid ) {
1193
         my $pid_is_alive = kill 0, $pid;
1194
         if ( $pid_is_alive ) {
1195
            die "The PID file $PID_file already exists "
1196
               . " and the PID that it contains, $pid, is running";
1197
         }
1198
         else {
1199
            warn "Overwriting PID file $PID_file because the PID that it "
1200
               . "contains, $pid, is not running";
1201
         }
1202
      }
1203
      else {
1204
         die "The PID file $PID_file already exists but it does not "
1205
            . "contain a PID";
1206
      }
1207
   }
1208
   else {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1209
      PTDEBUG && _d('No PID file');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1210
   }
1211
   return;
1212
}
1213
1214
sub make_PID_file {
1215
   my ( $self ) = @_;
1216
   if ( exists $self->{child} ) {
1217
      die "Do not call Daemon::make_PID_file() for daemonized scripts";
1218
   }
1219
   $self->_make_PID_file();
1220
   $self->{PID_owner} = $PID;
1221
   return;
1222
}
1223
1224
sub _make_PID_file {
1225
   my ( $self ) = @_;
1226
1227
   my $PID_file = $self->{PID_file};
1228
   if ( !$PID_file ) {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1229
      PTDEBUG && _d('No PID file to create');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1230
      return;
1231
   }
1232
1233
   $self->check_PID_file();
1234
1235
   open my $PID_FH, '>', $PID_file
1236
      or die "Cannot open PID file $PID_file: $OS_ERROR";
1237
   print $PID_FH $PID
1238
      or die "Cannot print to PID file $PID_file: $OS_ERROR";
1239
   close $PID_FH
1240
      or die "Cannot close PID file $PID_file: $OS_ERROR";
1241
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1242
   PTDEBUG && _d('Created PID file:', $self->{PID_file});
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1243
   return;
1244
}
1245
1246
sub _remove_PID_file {
1247
   my ( $self ) = @_;
1248
   if ( $self->{PID_file} && -f $self->{PID_file} ) {
1249
      unlink $self->{PID_file}
1250
         or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR";
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1251
      PTDEBUG && _d('Removed PID file');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1252
   }
1253
   else {
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1254
      PTDEBUG && _d('No PID to remove');
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1255
   }
1256
   return;
1257
}
1258
1259
sub DESTROY {
1260
   my ( $self ) = @_;
1261
1262
   $self->_remove_PID_file() if ($self->{PID_owner} || 0) == $PID;
1263
1264
   return;
1265
}
1266
94.18.3 by Daniel Nichter
Update Daemon.pm in all tools.
1267
sub slurp_file {
1268
   my ($file) = @_;
1269
   return unless $file;
1270
   open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR";
1271
   return do { local $/; <$fh> };
1272
}
1273
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1274
sub _d {
1275
   my ($package, undef, $line) = caller 0;
1276
   @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1277
        map { defined $_ ? $_ : 'undef' }
1278
        @_;
1279
   print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1280
}
1281
1282
1;
19 by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools.
1283
}
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1284
# ###########################################################################
1285
# End Daemon package
1286
# ###########################################################################
1287
1288
# ###########################################################################
1289
# This is a combination of modules and programs in one -- a runnable module.
1290
# http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last
1291
# Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition.
1292
#
1293
# Check at the end of this package for the call to main() which actually runs
1294
# the program.
1295
# ###########################################################################
5 by Daniel Nichter
Change tool packages from mk_ to pt_.
1296
package pt_fifo_split;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1297
1298
use English qw(-no_match_vars);
1299
use POSIX qw(mkfifo);
1300
use IO::File;
1301
123 by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes.
1302
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1303
1304
sub main {
1305
   @ARGV = @_;  # set global ARGV for this package
1306
1307
   # ########################################################################
1308
   # Get configuration information.
1309
   # ########################################################################
1310
   my $o = new OptionParser();
1311
   $o->get_specs();
1312
   $o->get_opts();
1313
1314
   if ( !$o->get('lines') || $o->get('lines') <= 0 ) {
1315
      $o->save_error('--lines must be a positive integer');
1316
   }
1317
   $o->usage_or_errors();
1318
1319
   # ########################################################################
1320
   # If --pid, check it first since we'll die if it already exits.
1321
   # ########################################################################
1322
   my $daemon;
1323
   if ( $o->get('pid') ) {
1324
      # We're not daemoninzing, it just handles PID stuff.  Keep $daemon
1325
      # in the the scope of main() because when it's destroyed it automatically
1326
      # removes the PID file.
1327
      $daemon = new Daemon(o=>$o);
1328
      $daemon->make_PID_file();
1329
   }
1330
1331
   my $file = $o->get('fifo');
1332
1333
   if ( $o->get('force') && -e $file ) {
1334
      unlink($file) or die "Can't unlink $file: $OS_ERROR";
1335
   }
1336
1337
   my $fh;
1338
1339
   if ( $o->get('statistics') ) {
1340
      printf("%5s %9s %5s %8s %8s\n", qw(chunks lines time overall current));
1341
   }
1342
1343
   # This is for runtime efficiency.
1344
   my $OFFSET = $o->get('offset');
1345
   my $LINES  = $o->get('lines');
1346
419.1.1 by fraserb at gmail
Fix for 1052722: pt-fifo-split is processing n-1 rows initially
1347
   my $chunks  = 0;
1348
   my $start   = time();
1349
   my $cstart  = time();
1350
   my $printed = 0;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1351
   while ( my $line = <> ) {
419.1.1 by fraserb at gmail
Fix for 1052722: pt-fifo-split is processing n-1 rows initially
1352
      my $lines = $INPUT_LINE_NUMBER;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1353
      next if $OFFSET && $lines < $OFFSET;
419.1.1 by fraserb at gmail
Fix for 1052722: pt-fifo-split is processing n-1 rows initially
1354
      if ( $printed == 0 ) {
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1355
         mkfifo($file, 0777) or die "Can't make fifo $file: $OS_ERROR";
1356
         $fh = IO::File->new($file, '>') or die "Can't open $file: $OS_ERROR";
1357
         $fh->autoflush(1);
419.1.1 by fraserb at gmail
Fix for 1052722: pt-fifo-split is processing n-1 rows initially
1358
      }
1359
      print $fh $line or die "Can't print: $OS_ERROR";
1360
      $printed++;
1361
      if ( ($lines % $LINES) == 0 ) {
1362
         close $fh or die "Can't close: $OS_ERROR";
1363
1364
         unlink($file) or die "Can't unlink $file: $OS_ERROR";
1365
         $printed = 0;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1366
1367
         $chunks++;
1368
         my $end = time();
1369
         if ( $o->get('statistics') ) {
1370
            my $overall = ($end - $start)  || 1;
1371
            my $current = ($end - $cstart) || 1;
1372
            printf("%5d %9d %5d %5.2f %5.2f\n", $chunks, $lines, ($end - $start),
1373
               ($lines / $overall), ($LINES / $current));
1374
         }
1375
         $cstart = $end;
1376
      }
1377
   }
1378
419.1.1 by fraserb at gmail
Fix for 1052722: pt-fifo-split is processing n-1 rows initially
1379
   close $fh or die "Can't close: $OS_ERROR" if $fh && $fh->opened;
1380
   unlink($file) or die "Can't unlink $file: $OS_ERROR" if -e $file;
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1381
1382
   return 0;
1383
}
1384
1385
sub _d {
1386
   my ($package, undef, $line) = caller 0;
1387
   @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1388
        map { defined $_ ? $_ : 'undef' }
1389
        @_;
1390
   print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1391
}
1392
1393
# ############################################################################
1394
# Run the program.
1395
# ############################################################################
1396
if ( !caller ) { exit main(@ARGV); }
1397
1398
1; # Because this is a module as well as a script.
1399
1400
# ############################################################################
1401
# Documentation
1402
# ############################################################################
1403
=pod
1404
1405
=head1 NAME
1406
6 by Daniel Nichter
Change mk- to pt- in all tools.
1407
pt-fifo-split - Split files and pipe lines to a fifo without really splitting.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1408
1409
=head1 SYNOPSIS
1410
539 by Daniel Nichter
Fix t/pt-fifo-split/pt-fifo-split.t.
1411
Usage: pt-fifo-split [OPTIONS] [FILE]
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1412
6 by Daniel Nichter
Change mk- to pt- in all tools.
1413
pt-fifo-split splits FILE and pipes lines to a fifo.  With no FILE, or when FILE
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1414
is -, read standard input.
1415
1416
Read hugefile.txt in chunks of a million lines without physically splitting it:
1417
6 by Daniel Nichter
Change mk- to pt- in all tools.
1418
 pt-fifo-split --lines 1000000 hugefile.txt
1419
 while [ -e /tmp/pt-fifo-split ]; do cat /tmp/pt-fifo-split; done
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1420
1421
=head1 RISKS
1422
548.1.1 by Daniel Nichter
Update RISKS section in all tools.
1423
Percona Toolkit is mature, proven in the real world, and well tested,
1424
but all database tools can pose a risk to the system and the database
1425
server.  Before using this tool, please:
1426
1427
=over
1428
1429
=item * Read the tool's documentation
1430
1431
=item * Review the tool's known L<"BUGS">
1432
1433
=item * Test the tool on a non-production server
1434
1435
=item * Backup your production server and verify the backups
1436
1437
=back
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1438
1439
=head1 DESCRIPTION
1440
6 by Daniel Nichter
Change mk- to pt- in all tools.
1441
pt-fifo-split lets you read from a file as though it contains only some of the
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1442
lines in the file.  When you read from it again, it contains the next set of
1443
lines; when you have gone all the way through it, the file disappears.  This
1444
works only on Unix-like operating systems.
1445
1446
You can specify multiple files on the command line.  If you don't specify any,
1447
or if you use the special filename C<->, lines are read from standard input.
1448
1449
=head1 OPTIONS
1450
1451
This tool accepts additional command-line arguments.  Refer to the
1452
L<"SYNOPSIS"> and usage information for details.
1453
1454
=over
1455
1456
=item --config
1457
1458
type: Array
1459
1460
Read this comma-separated list of config files; if specified, this must be the
1461
first option on the command line.
1462
1463
=item --fifo
1464
6 by Daniel Nichter
Change mk- to pt- in all tools.
1465
type: string; default: /tmp/pt-fifo-split
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1466
1467
The name of the fifo from which the lines can be read.
1468
1469
=item --force
1470
1471
Remove the fifo if it exists already, then create it again.
1472
1473
=item --help
1474
1475
Show help and exit.
1476
1477
=item --lines
1478
1479
type: int; default: 1000
1480
1481
The number of lines to read in each chunk.
1482
1483
=item --offset
1484
1485
type: int; default: 0
1486
1487
Begin at the Nth line.  If the argument is 0, all lines are printed to the fifo.
1488
If 1, then beginning at the first line, lines are printed (exactly the same as
1489
0).  If 2, the first line is skipped, and the 2nd and subsequent lines are
1490
printed to the fifo.
1491
1492
=item --pid
1493
1494
type: string
1495
530.1.8 by Daniel Nichter
Use the same blurb for --pid in all tools.
1496
Create the given PID file.  The tool won't start if the PID file already
1497
exists and the PID it contains is different than the current PID.  However,
1498
if the PID file exists and the PID it contains is no longer running, the
1499
tool will overwrite the PID file with the current PID.  The PID file is
1500
removed automatically when the tool exits.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1501
1502
=item --statistics
1503
1504
Print out statistics between chunks.  The statistics are the number of chunks,
1505
the number of lines, elapsed time, and lines per second overall and during the
1506
last chunk.
1507
1508
=item --version
1509
1510
Show version and exit.
1511
1512
=back
1513
1514
=head1 ENVIRONMENT
1515
13 by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT.
1516
The environment variable C<PTDEBUG> enables verbose debugging output to STDERR.
1517
To enable debugging and capture all output to a file, run the tool like:
1518
14 by Daniel Nichter
Replace $TOOL with tool name.
1519
   PTDEBUG=1 pt-fifo-split ... > FILE 2>&1
13 by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT.
1520
1521
Be careful: debugging output is voluminous and can generate several megabytes
1522
of output.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1523
1524
=head1 SYSTEM REQUIREMENTS
1525
1526
You need Perl, DBI, DBD::mysql, and some core packages that ought to be
1527
installed in any reasonably new version of Perl.
1528
1529
=head1 BUGS
1530
14 by Daniel Nichter
Replace $TOOL with tool name.
1531
For a list of known bugs, see L<http://www.percona.com/bugs/pt-fifo-split>.
13 by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT.
1532
1533
Please report bugs at L<https://bugs.launchpad.net/percona-toolkit>.
1534
Include the following information in your bug report:
1535
1536
=over
1537
1538
=item * Complete command-line used to run the tool
1539
1540
=item * Tool L<"--version">
1541
1542
=item * MySQL version of all servers involved
1543
1544
=item * Output from the tool including STDERR
1545
1546
=item * Input files (log/dump/config files, etc.)
1547
1548
=back
1549
1550
If possible, include debugging output by running the tool with C<PTDEBUG>;
1551
see L<"ENVIRONMENT">.
1552
59 by Daniel
Add RISKS section to Bash tools. Re-order all tools' DOWNLOADING section. Remove some unused options.
1553
=head1 DOWNLOADING
1554
1555
Visit L<http://www.percona.com/software/percona-toolkit/> to download the
1556
latest release of Percona Toolkit.  Or, get the latest release from the
1557
command line:
1558
1559
   wget percona.com/get/percona-toolkit.tar.gz
1560
1561
   wget percona.com/get/percona-toolkit.rpm
1562
1563
   wget percona.com/get/percona-toolkit.deb
1564
1565
You can also get individual tools from the latest release:
1566
1567
   wget percona.com/get/TOOL
1568
1569
Replace C<TOOL> with the name of any tool.
1570
13 by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT.
1571
=head1 AUTHORS
1572
1573
Baron Schwartz
1574
1575
=head1 ABOUT PERCONA TOOLKIT
1576
1577
This tool is part of Percona Toolkit, a collection of advanced command-line
548.1.2 by Daniel Nichter
Update the ABOUT PERCONA TOOLKIT secction in all tools.
1578
tools for MySQL developed by Percona.  Percona Toolkit was forked from two
1579
projects in June, 2011: Maatkit and Aspersa.  Those projects were created by
1580
Baron Schwartz and primarily developed by him and Daniel Nichter.  Visit
1581
L<http://www.percona.com/software/> to learn about other free, open-source
1582
software from Percona.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1583
12 by Daniel Nichter
Remove duplicate copyright notices. Add POD and copyright for Aspersa tools. Fix checking for "pt-pmp" instead of "pmp", etc.
1584
=head1 COPYRIGHT, LICENSE, AND WARRANTY
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1585
503.6.1 by Daniel Nichter
s/Percona Inc/Percona Ireland Ltd/g
1586
This program is copyright 2011-2013 Percona Ireland Ltd,
1587
2007-2011 Baron Schwartz.
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1588
1589
THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1590
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1591
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1592
1593
This program is free software; you can redistribute it and/or modify it under
1594
the terms of the GNU General Public License as published by the Free Software
1595
Foundation, version 2; OR the Perl Artistic License.  On UNIX and similar
1596
systems, you can issue `man perlgpl' or `man perlartistic' to read these
1597
licenses.
1598
1599
You should have received a copy of the GNU General Public License along with
1600
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1601
Place, Suite 330, Boston, MA  02111-1307  USA.
1602
1603
=head1 VERSION
1604
580.1.3 by Brian Fraser
Build percona-toolkit-2.2.2
1605
pt-fifo-split 2.2.2
3 by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/.
1606
1607
=cut