Commit cffa56ed750ee1e7ca634e316464b0f07f23dce8

Authored by Shrikant Sharat
1 parent 0b4fbaaf6a

Added function to handle argument parsing.

Showing 2 changed files with 160 additions and 0 deletions Side-by-side Diff

... ... @@ -364,6 +364,118 @@ antigen () {
364 364 "antigen-$cmd" "$@"
365 365 }
366 366  
  367 +-antigen-parse-args () {
  368 + # An argument parsing functionality to parse arguments the *antigen* way :).
  369 + # Takes one first argument (called spec), which dictates how to parse and
  370 + # the rest of the arguments are parsed. Outputs a piece of valid shell code
  371 + # that can be passed to `eval` inside a function which creates the arguments
  372 + # and their values as local variables. Suggested use is to set the defaults
  373 + # to all arguments first and then eval the output of this function.
  374 +
  375 + # Spec: Only long argument supported. No support for parsing short options.
  376 + # The spec must have two sections, separated by a `;`.
  377 + # '<positional-arguments>;<keyword-only-arguments>'
  378 + # Positional arguments are passed as just values, like `command a b`.
  379 + # Keyword arguments are passed as a `--name=value` pair, like `command
  380 + # --arg1=a --arg2=b`.
  381 +
  382 + # Each argument in the spec is separated by a `,`. Each keyword argument can
  383 + # end in a `:` to specifiy that this argument wants a value, otherwise it
  384 + # doesn't take a value. (The value in the output when the keyword argument
  385 + # doesn't have a `:` is `true`).
  386 +
  387 + # Arguments in either section can end with a `?` (should come after `:`, if
  388 + # both are present), means optional. FIXME: Not yet implemented.
  389 +
  390 + # See the test file, tests/arg-parser.t for (working) examples.
  391 +
  392 + local spec="$1"
  393 + shift
  394 +
  395 + local code=''
  396 +
  397 + --add-var () {
  398 + test -z "$code" || code="$code\n"
  399 + code="${code}local $1='$2'"
  400 + }
  401 +
  402 + local positional_args="$(echo "$spec" | cut -d\; -f1)"
  403 + local positional_args_count="$(echo $positional_args |
  404 + awk -F, '{print NF}')"
  405 +
  406 + # Set spec values based on the positional arguments.
  407 + local i=1
  408 + while ! [[ -z $1 || $1 == --* ]]; do
  409 +
  410 + if (( $i > $positional_args_count )); then
  411 + echo "Only $positional_args_count positional arguments allowed." >&2
  412 + echo "Found at least one more: '$1'" >&2
  413 + return
  414 + fi
  415 +
  416 + local name_spec="$(echo "$positional_args" | cut -d, -f$i)"
  417 + local name="${${name_spec%\?}%:}"
  418 + local value="$1"
  419 +
  420 + --add-var $name "$value"
  421 +
  422 + shift
  423 + i=$(($i + 1))
  424 + done
  425 +
  426 + local keyword_args="$(echo "$spec" | cut -d\; -f2 | tr , '\n')"
  427 + local keyword_args_count="$(echo $keyword_args | awk -F, '{print NF}')"
  428 +
  429 + # Set spec values from keyword arguments, if any. The remaining arguments
  430 + # are all assumed to be keyword arguments.
  431 + while [[ $1 == --* ]]; do
  432 + # Remove the `--` at the start.
  433 + local arg="${1#--}"
  434 +
  435 + # Get the argument name and value.
  436 + if [[ $arg != *=* ]]; then
  437 + local name="$arg"
  438 + local value=''
  439 + else
  440 + local name="${arg%\=*}"
  441 + local value="${arg#*=}"
  442 + fi
  443 +
  444 + # The specification for this argument, used for validations.
  445 + local arg_line="$(echo "$keyword_args" | grep -m1 "^$name:\??\?")"
  446 +
  447 + # Validate argument and value.
  448 + if [[ -z $arg_line ]]; then
  449 + # This argument is not known to us.
  450 + echo "Unknown argument '$name'." >&2
  451 + return
  452 +
  453 + elif (echo "$arg_line" | grep -qm1 ':') && [[ -z $value ]]; then
  454 + # This argument needs a value, but is not provided.
  455 + echo "Required argument for '$name' not provided." >&2
  456 + return
  457 +
  458 + elif (echo "$arg_line" | grep -vqm1 ':') && [[ ! -z $value ]]; then
  459 + # This argument doesn't need a value, but is provided.
  460 + echo "No argument required for '$name', but provided '$value'." >&2
  461 + return
  462 +
  463 + fi
  464 +
  465 + if [[ -z $value ]]; then
  466 + value=true
  467 + fi
  468 +
  469 + --add-var "${name//-/_}" "$value"
  470 + shift
  471 + done
  472 +
  473 + echo "$code"
  474 +
  475 + unfunction -- --add-var
  476 +
  477 +}
  478 +
367 479 # Echo the bundle specs as in the record. The first line is not echoed since it
368 480 # is a blank line.
369 481 -antigen-echo-record () {
... ... @@ -0,0 +1,48 @@
  1 +Helper alias.
  2 +
  3 + $ alias parse='-antigen-parse-args "url?,loc?;btype:?,no-local-clone?"'
  4 +
  5 +No arguments (since all are specified as optional).
  6 +
  7 + $ parse
  8 + (glob)
  9 +
  10 +One positional argument.
  11 +
  12 + $ parse name
  13 + local url='name'
  14 +
  15 +Two arguments.
  16 +
  17 + $ parse url location
  18 + local url='url'
  19 + local loc='location'
  20 +
  21 +Three arguments.
  22 +
  23 + $ parse url location crap
  24 + Only 2 positional arguments allowed.
  25 + Found at least one more: 'crap'
  26 +
  27 +Keywordo magic.
  28 +
  29 + $ parse url location --btype=1 --no-local-clone
  30 + local url='url'
  31 + local loc='location'
  32 + local btype='1'
  33 + local no_local_clone='true'
  34 +
  35 +Unknown keyword argument.
  36 +
  37 + $ parse --me=genius
  38 + Unknown argument 'me'.
  39 +
  40 +Missed value for keyword argument.
  41 +
  42 + $ parse --btype
  43 + Required argument for 'btype' not provided.
  44 +
  45 +Provide value for keyword argument, that shouldn't be there.
  46 +
  47 + $ parse --no-local-clone=yes
  48 + No argument required for 'no-local-clone', but provided 'yes'.