From cab3bb6eab5ee415821007d0677422934c2a1570 Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Mon, 23 Jan 2012 10:54:43 -0700 Subject: [PATCH] Update parse_options.sh in pt-stalk. --- bin/pt-stalk | 281 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 183 insertions(+), 98 deletions(-) diff --git a/bin/pt-stalk b/bin/pt-stalk index 1968cb85..1c4fdbbd 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -49,21 +49,26 @@ die() { # ########################################################################### + + + set -u -ARGV="" # Non-option args (probably input files) -EXT_ARGV="" # Everything after -- (args for an external command) -OPT_ERRS=0 # How many command line option errors -OPT_VERSION="no" # If --version was specified -OPT_HELP="no" # If --help was specified +ARGV="" # Non-option args (probably input files) +EXT_ARGV="" # Everything after -- (args for an external command) +HAVE_EXT_ARGV="" # Got --, everything else is put into EXT_ARGV +OPT_ERRS=0 # How many command line option errors +OPT_VERSION="no" # If --version was specified +OPT_HELP="no" # If --help was specified +PO_DIR="$TMPDIR/po" # Directory with program option spec files usage() { local file="$1" local usage=$(grep '^Usage: ' "$file") - echo $usage >&2 - echo >&2 - echo "For more information, 'man $TOOL' or 'perldoc $file'." >&2 + echo $usage + echo + echo "For more information, 'man $TOOL' or 'perldoc $file'." } usage_or_errors() { @@ -77,20 +82,20 @@ usage_or_errors() { if [ "$OPT_HELP" = "yes" ]; then usage "$file" - echo >&2 - echo "Command line options:" >&2 - echo >&2 + echo + echo "Command line options:" + echo for opt in $(ls $TMPDIR/po/); do local desc=$(cat $TMPDIR/po/$opt | grep '^desc:' | sed -e 's/^desc://') - echo "--$opt" >&2 - echo " $desc" >&2 - echo >&2 + echo "--$opt" + echo " $desc" + echo done return 1 fi if [ $OPT_ERRS -gt 0 ]; then - echo >&2 + echo usage "$file" return 1 fi @@ -102,54 +107,70 @@ parse_options() { local file="$1" shift - if [ ! -d "$TMPDIR/po/" ]; then - mkdir "$TMPDIR/po/" + ARGV="" + EXT_ARGV="" + HAVE_EXT_ARGV="" + OPT_ERRS=0 + OPT_VERSION="no" + OPT_HELP="no" + PO_DIR="$TMPDIR/po" + + if [ ! -d "$PO_DIR" ]; then + mkdir "$PO_DIR" if [ $? -ne 0 ]; then - echo "Cannot mkdir $TMPDIR/po/" >&2 + echo "Cannot mkdir $PO_DIR" >&2 exit 1 fi fi - rm -rf "$TMPDIR"/po/* + rm -rf "$PO_DIR"/* if [ $? -ne 0 ]; then - echo "Cannot rm -rf $TMPDIR/po/*" >&2 + echo "Cannot rm -rf $PO_DIR/*" >&2 exit 1 fi - - ( - export PO_DIR="$TMPDIR/po" - cat "$file" | perl -ne ' - BEGIN { $/ = ""; } - next unless $_ =~ m/^=head1 OPTIONS/; - while ( defined(my $para = <>) ) { - last if $para =~ m/^=head1/; + + _parse_pod "$file" + _eval_po + _parse_config_files + _parse_command_line "$@" +} + +_parse_pod() { + local file="$1" + + cat "$file" | PO_DIR="$PO_DIR" perl -ne ' + BEGIN { $/ = ""; } + next unless $_ =~ m/^=head1 OPTIONS/; + while ( defined(my $para = <>) ) { + last if $para =~ m/^=head1/; + chomp; + if ( $para =~ m/^=item --(\S+)/ ) { + my $opt = $1; + my $file = "$ENV{PO_DIR}/$opt"; + open my $opt_fh, ">", $file or die "Cannot open $file: $!"; + print $opt_fh "long:$opt\n"; + $para = <>; chomp; - if ( $para =~ m/^=item --(\S+)/ ) { - my $opt = $1; - my $file = "$ENV{PO_DIR}/$opt"; - open my $opt_fh, ">", $file or die "Cannot open $file: $!"; - print $opt_fh "long:$opt\n"; + if ( $para =~ m/^[a-z ]+:/ ) { + map { + chomp; + my ($attrib, $val) = split(/: /, $_); + print $opt_fh "$attrib:$val\n"; + } split(/; /, $para); $para = <>; chomp; - if ( $para =~ m/^[a-z ]+:/ ) { - map { - chomp; - my ($attrib, $val) = split(/: /, $_); - print $opt_fh "$attrib:$val\n"; - } split(/; /, $para); - $para = <>; - chomp; - } - my ($desc) = $para =~ m/^([^?.]+)/; - print $opt_fh "desc:$desc.\n"; - close $opt_fh; } + my ($desc) = $para =~ m/^([^?.]+)/; + print $opt_fh "desc:$desc.\n"; + close $opt_fh; } - last; - ' - ) + } + last; + ' +} - for opt_spec in $(ls "$TMPDIR/po/"); do +_eval_po() { + for opt_spec in $(ls "$PO_DIR"); do local opt="" local default_val="" local neg=0 @@ -175,13 +196,13 @@ parse_options() { fi ;; *) - echo "Invalid attribute in $TMPDIR/po/$opt_spec: $line" >&2 + echo "Invalid attribute in $PO_DIR/$opt_spec: $line" >&2 exit 1 esac - done < "$TMPDIR/po/$opt_spec" + done < "$PO_DIR/$opt_spec" if [ -z "$opt" ]; then - echo "No long attribute in option spec $TMPDIR/po/$opt_spec" >&2 + echo "No long attribute in option spec $PO_DIR/$opt_spec" >&2 exit 1 fi @@ -194,69 +215,133 @@ parse_options() { eval "OPT_${opt}"="$default_val" done +} - for opt; do - if [ $# -eq 0 ]; then - break # no more opts +_parse_config_files() { + for config_file in "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf" + do + test -f "$config_file" || continue + + while read config_opt; do + + echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue + + config_opt="$(echo "$config_opt" | sed -e 's/^[ ]*//' -e 's/[ ]*\$//' -e 's/[ ]*=[ ]*/=/' -e 's/[ ]*#.*$//')" + + if ! [ "$HAVE_EXT_ARGV" ]; then + config_opt="--$config_opt" + fi + _parse_command_line "$config_opt" + done < "$config_file" + + HAVE_EXT_ARGV="" # reset for each file + + done +} + +_parse_command_line() { + local opt="" + local val="" + local next_opt_is_val="" + local opt_is_ok="" + local opt_is_negated="" + local real_opt="" + local required_arg="" + + for opt in "$@"; do + if [ "$opt" = "--" -o "$opt" = "----" ]; then + HAVE_EXT_ARGV=1 + continue fi - opt=$1 - if [ "$opt" = "--" ]; then - shift - EXT_ARGV="$@" - break - fi - shift - if [ $(expr "$opt" : "-") -eq 0 ]; then - if [ -z "$ARGV" ]; then - ARGV="$opt" + if [ "$HAVE_EXT_ARGV" ]; then + if [ "$EXT_ARGV" ]; then + EXT_ARGV="$EXT_ARGV $opt" else - ARGV="$ARGV $opt" + EXT_ARGV="$opt" fi continue fi - local real_opt="$opt" - - if $(echo $opt | grep -q '^--no-'); then - neg=1 - opt=$(echo $opt | sed 's/^--no-//') - else - neg=0 - opt=$(echo $opt | sed 's/^-*//') - fi - - if [ -f "$TMPDIR/po/$opt" ]; then - spec="$TMPDIR/po/$opt" - else - spec=$(grep "^short form:-$opt\$" "$TMPDIR"/po/* | cut -d ':' -f 1) - if [ -z "$spec" ]; then - OPT_ERRS=$(($OPT_ERRS + 1)) - echo "Unknown option: $real_opt" >&2 - continue - fi - fi - - local required_arg=$(cat $spec | awk -F: '/^type:/{print $2}') - if [ -n "$required_arg" ]; then - if [ $# -eq 0 ]; then + if [ "$next_opt_is_val" ]; then + next_opt_is_val="" + if [ $# -eq 0 ] || [ $(expr "$opt" : "-") -eq 1 ]; then OPT_ERRS=$(($OPT_ERRS + 1)) echo "$real_opt requires a $required_arg argument" >&2 continue - else - val="$1" - shift fi + val="$opt" + opt_is_ok=1 else - if [ $neg -eq 0 ]; then - val="yes" + if [ $(expr "$opt" : "-") -eq 0 ]; then + if [ -z "$ARGV" ]; then + ARGV="$opt" + else + ARGV="$ARGV $opt" + fi + continue + fi + + real_opt="$opt" + + if $(echo $opt | grep -q '^--no-'); then + opt_is_negated=1 + opt=$(echo $opt | sed 's/^--no-//') else - val="no" + opt_is_negated="" + opt=$(echo $opt | sed 's/^-*//') + fi + + if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then + val="$(echo $opt | awk -F= '{print $2}')" + opt="$(echo $opt | awk -F= '{print $1}')" + fi + + if [ -f "$TMPDIR/po/$opt" ]; then + spec="$TMPDIR/po/$opt" + else + spec=$(grep "^short form:-$opt\$" "$TMPDIR"/po/* | cut -d ':' -f 1) + if [ -z "$spec" ]; then + OPT_ERRS=$(($OPT_ERRS + 1)) + echo "Unknown option: $real_opt" >&2 + continue + fi + fi + + required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}') + if [ "$required_arg" ]; then + if [ "$val" ]; then + opt_is_ok=1 + else + next_opt_is_val=1 + fi + else + if [ "$val" ]; then + OPT_ERRS=$(($OPT_ERRS + 1)) + echo "Option $real_opt does not take a value" >&2 + continue + fi + if [ "$opt_is_negated" ]; then + val="" + else + val="yes" + fi + opt_is_ok=1 fi fi - opt=$(cat $spec | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr [:lower:] [:upper:]) + if [ "$opt_is_ok" ]; then + opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr [:lower:] [:upper:]) - eval "OPT_$opt"="$val" + eval "OPT_$opt"="'$val'" + + opt="" + val="" + next_opt_is_val="" + opt_is_ok="" + opt_is_negated="" + real_opt="" + required_arg="" + fi done }