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

« back to all changes in this revision

Viewing changes to bin/pt-sift

  • Committer: Daniel Nichter
  • Date: 2013-04-04 20:59:02 UTC
  • mto: This revision was merged to the branch mainline in revision 569.
  • Revision ID: daniel@percona.com-20130404205902-ycfb2zwwuwavbdwz
Add --version and --help to pt-sift.

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
5
5
# notices and disclaimers.
6
6
 
7
 
usage() {
8
 
   if [ "${OPT_ERR}" ]; then
9
 
      echo "Error: $OPT_ERR" >&2
10
 
   fi
11
 
   echo "Usage: pt-sift FILE|PREFIX|DIRECTORY" >&2
12
 
   echo "For more information, 'man pt-sift' or 'perldoc $0'." >&2
 
7
# ###########################################################################
 
8
# log_warn_die package
 
9
# This package is a copy without comments from the original.  The original
 
10
# with comments and its test file can be found in the Bazaar repository at,
 
11
#   lib/bash/log_warn_die.sh
 
12
#   t/lib/bash/log_warn_die.sh
 
13
# See https://launchpad.net/percona-toolkit for more information.
 
14
# ###########################################################################
 
15
 
 
16
 
 
17
set -u
 
18
 
 
19
PTFUNCNAME=""
 
20
PTDEBUG="${PTDEBUG:-""}"
 
21
EXIT_STATUS=0
 
22
 
 
23
ts() {
 
24
   TS=$(date +%F-%T | tr ':-' '_')
 
25
   echo "$TS $*"
 
26
}
 
27
 
 
28
info() {
 
29
   [ ${OPT_VERBOSE:-3} -ge 3 ] && ts "$*"
 
30
}
 
31
 
 
32
log() {
 
33
   [ ${OPT_VERBOSE:-3} -ge 2 ] && ts "$*"
 
34
}
 
35
 
 
36
warn() {
 
37
   [ ${OPT_VERBOSE:-3} -ge 1 ] && ts "$*" >&2
 
38
   EXIT_STATUS=1
 
39
}
 
40
 
 
41
die() {
 
42
   ts "$*" >&2
 
43
   EXIT_STATUS=1
13
44
   exit 1
14
45
}
15
46
 
 
47
_d () {
 
48
   [ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(ts "$*")" >&2
 
49
}
 
50
 
 
51
# ###########################################################################
 
52
# End log_warn_die package
 
53
# ###########################################################################
 
54
 
16
55
# ###########################################################################
17
56
# tmpdir package
18
57
# This package is a copy without comments from the original.  The original
55
94
# ###########################################################################
56
95
 
57
96
# ###########################################################################
 
97
# parse_options package
 
98
# This package is a copy without comments from the original.  The original
 
99
# with comments and its test file can be found in the Bazaar repository at,
 
100
#   lib/bash/parse_options.sh
 
101
#   t/lib/bash/parse_options.sh
 
102
# See https://launchpad.net/percona-toolkit for more information.
 
103
# ###########################################################################
 
104
 
 
105
 
 
106
 
 
107
 
 
108
 
 
109
set -u
 
110
 
 
111
ARGV=""           # Non-option args (probably input files)
 
112
EXT_ARGV=""       # Everything after -- (args for an external command)
 
113
HAVE_EXT_ARGV=""  # Got --, everything else is put into EXT_ARGV
 
114
OPT_ERRS=0        # How many command line option errors
 
115
OPT_VERSION=""    # If --version was specified
 
116
OPT_HELP=""       # If --help was specified
 
117
PO_DIR=""         # Directory with program option spec files
 
118
 
 
119
usage() {
 
120
   local file="$1"
 
121
 
 
122
   local usage="$(grep '^Usage: ' "$file")"
 
123
   echo $usage
 
124
   echo
 
125
   echo "For more information, 'man $TOOL' or 'perldoc $file'."
 
126
}
 
127
 
 
128
usage_or_errors() {
 
129
   local file="$1"
 
130
 
 
131
   if [ "$OPT_VERSION" ]; then
 
132
      local version=$(grep '^pt-[^ ]\+ [0-9]' "$file")
 
133
      echo "$version"
 
134
      return 1
 
135
   fi
 
136
 
 
137
   if [ "$OPT_HELP" ]; then
 
138
      usage "$file"
 
139
      echo
 
140
      echo "Command line options:"
 
141
      echo
 
142
      perl -e '
 
143
         use strict;
 
144
         use warnings FATAL => qw(all);
 
145
         my $lcol = 20;         # Allow this much space for option names.
 
146
         my $rcol = 80 - $lcol; # The terminal is assumed to be 80 chars wide.
 
147
         my $name;
 
148
         while ( <> ) {
 
149
            my $line = $_;
 
150
            chomp $line;
 
151
            if ( $line =~ s/^long:/  --/ ) {
 
152
               $name = $line;
 
153
            }
 
154
            elsif ( $line =~ s/^desc:// ) {
 
155
               $line =~ s/ +$//mg;
 
156
               my @lines = grep { $_      }
 
157
                           $line =~ m/(.{0,$rcol})(?:\s+|\Z)/g;
 
158
               if ( length($name) >= $lcol ) {
 
159
                  print $name, "\n", (q{ } x $lcol);
 
160
               }
 
161
               else {
 
162
                  printf "%-${lcol}s", $name;
 
163
               }
 
164
               print join("\n" . (q{ } x $lcol), @lines);
 
165
               print "\n";
 
166
            }
 
167
         }
 
168
      ' "$PO_DIR"/*
 
169
      echo
 
170
      echo "Options and values after processing arguments:"
 
171
      echo
 
172
      (
 
173
         cd "$PO_DIR"
 
174
         for opt in *; do
 
175
            local varname="OPT_$(echo "$opt" | tr a-z- A-Z_)"
 
176
            eval local varvalue=\$$varname
 
177
            if ! grep -q "type:" "$PO_DIR/$opt" >/dev/null; then
 
178
               if [ "$varvalue" -a "$varvalue" = "yes" ];
 
179
                  then varvalue="TRUE"
 
180
               else
 
181
                  varvalue="FALSE"
 
182
               fi
 
183
            fi
 
184
            printf -- "  --%-30s %s" "$opt" "${varvalue:-(No value)}"
 
185
            echo
 
186
         done
 
187
      )
 
188
      return 1
 
189
   fi
 
190
 
 
191
   if [ $OPT_ERRS -gt 0 ]; then
 
192
      echo
 
193
      usage "$file"
 
194
      return 1
 
195
   fi
 
196
 
 
197
   return 0
 
198
}
 
199
 
 
200
option_error() {
 
201
   local err="$1"
 
202
   OPT_ERRS=$(($OPT_ERRS + 1))
 
203
   echo "$err" >&2
 
204
}
 
205
 
 
206
parse_options() {
 
207
   local file="$1"
 
208
   shift
 
209
 
 
210
   ARGV=""
 
211
   EXT_ARGV=""
 
212
   HAVE_EXT_ARGV=""
 
213
   OPT_ERRS=0
 
214
   OPT_VERSION=""
 
215
   OPT_HELP=""
 
216
   PO_DIR="$PT_TMPDIR/po"
 
217
 
 
218
   if [ ! -d "$PO_DIR" ]; then
 
219
      mkdir "$PO_DIR"
 
220
      if [ $? -ne 0 ]; then
 
221
         echo "Cannot mkdir $PO_DIR" >&2
 
222
         exit 1
 
223
      fi
 
224
   fi
 
225
 
 
226
   rm -rf "$PO_DIR"/*
 
227
   if [ $? -ne 0 ]; then
 
228
      echo "Cannot rm -rf $PO_DIR/*" >&2
 
229
      exit 1
 
230
   fi
 
231
 
 
232
   _parse_pod "$file"  # Parse POD into program option (po) spec files
 
233
   _eval_po            # Eval po into existence with default values
 
234
 
 
235
   if [ $# -ge 2 ] &&  [ "$1" = "--config" ]; then
 
236
      shift  # --config
 
237
      local user_config_files="$1"
 
238
      shift  # that ^
 
239
      local IFS=","
 
240
      for user_config_file in $user_config_files; do
 
241
         _parse_config_files "$user_config_file"
 
242
      done
 
243
   else
 
244
      _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf"
 
245
   fi
 
246
 
 
247
   _parse_command_line "${@:-""}"
 
248
}
 
249
 
 
250
_parse_pod() {
 
251
   local file="$1"
 
252
 
 
253
   cat "$file" | PO_DIR="$PO_DIR" perl -ne '
 
254
      BEGIN { $/ = ""; }
 
255
      next unless $_ =~ m/^=head1 OPTIONS/;
 
256
      while ( defined(my $para = <>) ) {
 
257
         last if $para =~ m/^=head1/;
 
258
         chomp;
 
259
         if ( $para =~ m/^=item --(\S+)/ ) {
 
260
            my $opt  = $1;
 
261
            my $file = "$ENV{PO_DIR}/$opt";
 
262
            open my $opt_fh, ">", $file or die "Cannot open $file: $!";
 
263
            print $opt_fh "long:$opt\n";
 
264
            $para = <>;
 
265
            chomp;
 
266
            if ( $para =~ m/^[a-z ]+:/ ) {
 
267
               map {
 
268
                  chomp;
 
269
                  my ($attrib, $val) = split(/: /, $_);
 
270
                  print $opt_fh "$attrib:$val\n";
 
271
               } split(/; /, $para);
 
272
               $para = <>;
 
273
               chomp;
 
274
            }
 
275
            my ($desc) = $para =~ m/^([^?.]+)/;
 
276
            print $opt_fh "desc:$desc.\n";
 
277
            close $opt_fh;
 
278
         }
 
279
      }
 
280
      last;
 
281
   '
 
282
}
 
283
 
 
284
_eval_po() {
 
285
   local IFS=":"
 
286
   for opt_spec in "$PO_DIR"/*; do
 
287
      local opt=""
 
288
      local default_val=""
 
289
      local neg=0
 
290
      local size=0
 
291
      while read key val; do
 
292
         case "$key" in
 
293
            long)
 
294
               opt=$(echo $val | sed 's/-/_/g' | tr '[:lower:]' '[:upper:]')
 
295
               ;;
 
296
            default)
 
297
               default_val="$val"
 
298
               ;;
 
299
            "short form")
 
300
               ;;
 
301
            type)
 
302
               [ "$val" = "size" ] && size=1
 
303
               ;;
 
304
            desc)
 
305
               ;;
 
306
            negatable)
 
307
               if [ "$val" = "yes" ]; then
 
308
                  neg=1
 
309
               fi
 
310
               ;;
 
311
            *)
 
312
               echo "Invalid attribute in $opt_spec: $line" >&2
 
313
               exit 1
 
314
         esac 
 
315
      done < "$opt_spec"
 
316
 
 
317
      if [ -z "$opt" ]; then
 
318
         echo "No long attribute in option spec $opt_spec" >&2
 
319
         exit 1
 
320
      fi
 
321
 
 
322
      if [ $neg -eq 1 ]; then
 
323
         if [ -z "$default_val" ] || [ "$default_val" != "yes" ]; then
 
324
            echo "Option $opt_spec is negatable but not default: yes" >&2
 
325
            exit 1
 
326
         fi
 
327
      fi
 
328
 
 
329
      if [ $size -eq 1 -a -n "$default_val" ]; then
 
330
         default_val=$(size_to_bytes $default_val)
 
331
      fi
 
332
 
 
333
      eval "OPT_${opt}"="$default_val"
 
334
   done
 
335
}
 
336
 
 
337
_parse_config_files() {
 
338
 
 
339
   for config_file in "${@:-""}"; do
 
340
      test -f "$config_file" || continue
 
341
 
 
342
      while read config_opt; do
 
343
 
 
344
         echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue
 
345
 
 
346
         config_opt="$(echo "$config_opt" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/[ ]*=[ ]*/=/' -e 's/[ ]*#.*$//')"
 
347
 
 
348
         [ "$config_opt" = "" ] && continue
 
349
 
 
350
         if ! [ "$HAVE_EXT_ARGV" ]; then
 
351
            config_opt="--$config_opt"
 
352
         fi
 
353
 
 
354
         _parse_command_line "$config_opt"
 
355
 
 
356
      done < "$config_file"
 
357
 
 
358
      HAVE_EXT_ARGV=""  # reset for each file
 
359
 
 
360
   done
 
361
}
 
362
 
 
363
_parse_command_line() {
 
364
   local opt=""
 
365
   local val=""
 
366
   local next_opt_is_val=""
 
367
   local opt_is_ok=""
 
368
   local opt_is_negated=""
 
369
   local real_opt=""
 
370
   local required_arg=""
 
371
   local spec=""
 
372
 
 
373
   for opt in "${@:-""}"; do
 
374
      if [ "$opt" = "--" -o "$opt" = "----" ]; then
 
375
         HAVE_EXT_ARGV=1
 
376
         continue
 
377
      fi
 
378
      if [ "$HAVE_EXT_ARGV" ]; then
 
379
         if [ "$EXT_ARGV" ]; then
 
380
            EXT_ARGV="$EXT_ARGV $opt"
 
381
         else
 
382
            EXT_ARGV="$opt"
 
383
         fi
 
384
         continue
 
385
      fi
 
386
 
 
387
      if [ "$next_opt_is_val" ]; then
 
388
         next_opt_is_val=""
 
389
         if [ $# -eq 0 ] || [ $(expr "$opt" : "\-") -eq 1 ]; then
 
390
            option_error "$real_opt requires a $required_arg argument"
 
391
            continue
 
392
         fi
 
393
         val="$opt"
 
394
         opt_is_ok=1
 
395
      else
 
396
         if [ $(expr "$opt" : "\-") -eq 0 ]; then
 
397
            if [ -z "$ARGV" ]; then
 
398
               ARGV="$opt"
 
399
            else
 
400
               ARGV="$ARGV $opt"
 
401
            fi
 
402
            continue
 
403
         fi
 
404
 
 
405
         real_opt="$opt"
 
406
 
 
407
         if $(echo $opt | grep '^--no[^-]' >/dev/null); then
 
408
            local base_opt=$(echo $opt | sed 's/^--no//')
 
409
            if [ -f "$PT_TMPDIR/po/$base_opt" ]; then
 
410
               opt_is_negated=1
 
411
               opt="$base_opt"
 
412
            else
 
413
               opt_is_negated=""
 
414
               opt=$(echo $opt | sed 's/^-*//')
 
415
            fi
 
416
         else
 
417
            if $(echo $opt | grep '^--no-' >/dev/null); then
 
418
               opt_is_negated=1
 
419
               opt=$(echo $opt | sed 's/^--no-//')
 
420
            else
 
421
               opt_is_negated=""
 
422
               opt=$(echo $opt | sed 's/^-*//')
 
423
            fi
 
424
         fi
 
425
 
 
426
         if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
 
427
            val="$(echo $opt | awk -F= '{print $2}')"
 
428
            opt="$(echo $opt | awk -F= '{print $1}')"
 
429
         fi
 
430
 
 
431
         if [ -f "$PT_TMPDIR/po/$opt" ]; then
 
432
            spec="$PT_TMPDIR/po/$opt"
 
433
         else
 
434
            spec=$(grep "^short form:-$opt\$" "$PT_TMPDIR"/po/* | cut -d ':' -f 1)
 
435
            if [ -z "$spec"  ]; then
 
436
               option_error "Unknown option: $real_opt"
 
437
               continue
 
438
            fi
 
439
         fi
 
440
 
 
441
         required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}')
 
442
         if [ "$required_arg" ]; then
 
443
            if [ "$val" ]; then
 
444
               opt_is_ok=1
 
445
            else
 
446
               next_opt_is_val=1
 
447
            fi
 
448
         else
 
449
            if [ "$val" ]; then
 
450
               option_error "Option $real_opt does not take a value"
 
451
               continue
 
452
            fi 
 
453
            if [ "$opt_is_negated" ]; then
 
454
               val=""
 
455
            else
 
456
               val="yes"
 
457
            fi
 
458
            opt_is_ok=1
 
459
         fi
 
460
      fi
 
461
 
 
462
      if [ "$opt_is_ok" ]; then
 
463
         opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr '[:lower:]' '[:upper:]')
 
464
 
 
465
         if grep "^type:size" "$spec" >/dev/null; then
 
466
            val=$(size_to_bytes $val)
 
467
         fi
 
468
 
 
469
         eval "OPT_$opt"="'$val'"
 
470
 
 
471
         opt=""
 
472
         val=""
 
473
         next_opt_is_val=""
 
474
         opt_is_ok=""
 
475
         opt_is_negated=""
 
476
         real_opt=""
 
477
         required_arg=""
 
478
         spec=""
 
479
      fi
 
480
   done
 
481
}
 
482
 
 
483
size_to_bytes() {
 
484
   local size="$1"
 
485
   echo $size | perl -ne '%f=(B=>1, K=>1_024, M=>1_048_576, G=>1_073_741_824, T=>1_099_511_627_776); m/^(\d+)([kMGT])?/i; print $1 * $f{uc($2 || "B")};'
 
486
}
 
487
 
 
488
# ###########################################################################
 
489
# End parse_options package
 
490
# ###########################################################################
 
491
 
 
492
# ###########################################################################
58
493
# Global variables
59
494
# ###########################################################################
60
495
 
106
541
   # prefix.  The outcome of this block of code should be that BASEDIR is the
107
542
   # directory where the files live, without a trailing slash; and PREFIX is
108
543
   # either empty or a timestamp, such as "2011_02_08_16_58_07".
109
 
   if [ $# -gt 1 ]; then
110
 
      OPT_ERR="Specify only one PREFIX or DIR"
111
 
      usage
112
 
   fi
113
 
 
114
544
   if [ $# -eq 1 ]; then
115
545
      if [ -d "$1" ]; then
116
546
         BASEDIR="$1"
147
577
      fi 
148
578
   done
149
579
 
150
 
   # Make a secure tmpdir.
151
 
   mk_tmpdir
152
 
 
153
580
   # We need to generate a list of timestamps, and ask the user to choose one if
154
581
   # there is no PREFIX yet.  NOTE: we rely on the "-df" files here.
155
582
   (
580
1007
            ;;
581
1008
      esac
582
1009
   done
583
 
 
584
 
   rm_tmpdir
585
1010
}
586
1011
 
587
1012
# Execute the program if it was not included from another file.  This makes it
588
1013
# possible to include without executing, and thus test.
589
1014
if    [ "${0##*/}" = "$TOOL" ] \
590
1015
   || [ "${0##*/}" = "bash" -a "${_:-""}" = "$0" ]; then
591
 
    main "${@:-""}"
 
1016
 
 
1017
   mk_tmpdir
 
1018
 
 
1019
   parse_options "$0" "${@:-""}"
 
1020
   if [ -z "$OPT_HELP" -a -z "$OPT_VERSION" ]; then
 
1021
      if [ $# -gt 1 ]; then
 
1022
         option_error "Specify only one PREFIX or DIR"
 
1023
      fi
 
1024
   fi
 
1025
   usage_or_errors "$0"
 
1026
   po_status=$?
 
1027
   if [ $po_status -ne 0 ]; then
 
1028
      [ $OPT_ERRS -gt 0 ] && exit 1
 
1029
      exit 0
 
1030
   fi
 
1031
 
 
1032
   main "${@:-""}"
 
1033
 
 
1034
   rm_tmpdir
592
1035
fi
593
1036
 
594
1037
# ############################################################################
644
1087
 
645
1088
=over
646
1089
 
647
 
=item d
 
1090
=item * d
648
1091
 
649
1092
Sets the action to start the L<pt-diskstats> tool on the sample's disk
650
1093
performance statistics.
651
1094
 
652
 
=item i
 
1095
=item * i
653
1096
 
654
1097
Sets the action to view the first INNODB STATUS sample in less.
655
1098
 
656
 
=item m
 
1099
=item * m
657
1100
 
658
1101
Displays the first 4 samples of SHOW STATUS counters side by side with the
659
1102
L<pt-mext> tool.
660
1103
 
661
 
=item n
 
1104
=item * n
662
1105
 
663
1106
Summarizes the first sample of netstat data in two ways: by originating host,
664
1107
and by connection state.
665
1108
 
666
 
=item j
 
1109
=item * j
667
1110
 
668
1111
Select the next timestamp as the active sample.
669
1112
 
670
 
=item k
 
1113
=item * k
671
1114
 
672
1115
Select the previous timestamp as the active sample.
673
1116
 
674
 
=item q
 
1117
=item * q
675
1118
 
676
1119
Quit the program.
677
1120
 
678
 
=item 1
 
1121
=item * 1
679
1122
 
680
1123
Sets the action for each sample to the default, which is to view a summary
681
1124
of the sample.
682
1125
 
683
 
=item 0
 
1126
=item * 0
684
1127
 
685
1128
Sets the action to just list the files in the sample.
686
1129
 
687
 
=item *
 
1130
=item * *
688
1131
 
689
1132
Sets the action to view all of the sample's files in the less program.
690
1133
 
692
1135
 
693
1136
=head1 OPTIONS
694
1137
 
695
 
This tool does not have any command-line options.
 
1138
=over
 
1139
 
 
1140
=item --help
 
1141
 
 
1142
Show help and exit.
 
1143
 
 
1144
=item --version
 
1145
 
 
1146
Show version and exit.
 
1147
 
 
1148
=back
696
1149
 
697
1150
=head1 ENVIRONMENT
698
1151