Created
August 21, 2018 01:48
-
-
Save APIUM/d5b2a49f3092ac39b648a7831c99046d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-antigen-parse-args () { | |
576 # An argument parsing functionality to parse arguments the *antigen* way :). | |
577 # Takes one first argument (called spec), which dictates how to parse and | |
578 # the rest of the arguments are parsed. Outputs a piece of valid shell code | |
579 # that can be passed to `eval` inside a function which creates the arguments | |
580 # and their values as local variables. Suggested use is to set the defaults | |
581 # to all arguments first and then eval the output of this function. | |
582 | |
583 # Spec: Only long argument supported. No support for parsing short options. | |
584 # The spec must have two sections, separated by a `;`. | |
585 # '<positional-arguments>;<keyword-only-arguments>' | |
586 # Positional arguments are passed as just values, like `command a b`. | |
587 # Keyword arguments are passed as a `--name=value` pair, like `command | |
588 # --arg1=a --arg2=b`. | |
589 | |
590 # Each argument in the spec is separated by a `,`. Each keyword argument can | |
591 # end in a `:` to specifiy that this argument wants a value, otherwise it | |
592 # doesn't take a value. (The value in the output when the keyword argument | |
593 # doesn't have a `:` is `true`). | |
594 | |
595 # Arguments in either section can end with a `?` (should come after `:`, if | |
596 # both are present), means optional. FIXME: Not yet implemented. | |
597 | |
598 # See the test file, tests/arg-parser.t for (working) examples. | |
599 | |
600 local spec="$1" | |
601 shift | |
602 | |
603 # Sanitize the spec | |
604 spec="$(echo "$spec" | tr '\n' ' ' | sed 's/[[:space:]]//g')" | |
605 | |
606 local code='' | |
607 | |
608 --add-var () { | |
609 test -z "$code" || code="$code\n" | |
610 code="${code}local $1='$2'" | |
611 } | |
612 | |
613 local positional_args="$(echo "$spec" | cut -d\; -f1)" | |
614 local positional_args_count="$(echo $positional_args | | |
615 awk -F, '{print NF}')" | |
616 | |
617 # Set spec values based on the positional arguments. | |
618 local i=1 | |
619 while [[ -n $1 && $1 != --* ]]; do | |
620 | |
621 if (( $i > $positional_args_count )); then | |
622 echo "Only $positional_args_count positional arguments allowed." >&2 | |
623 echo "Found at least one more: '$1'" >&2 | |
624 return | |
625 fi | |
626 | |
627 local name_spec="$(echo "$positional_args" | cut -d, -f$i)" | |
628 local name="${${name_spec%\?}%:}" | |
629 local value="$1" | |
630 | |
631 if echo "$code" | grep -l "^local $name=" &> /dev/null; then | |
632 echo "Argument '$name' repeated with the value '$value'". >&2 | |
633 return | |
634 fi | |
635 | |
636 --add-var $name "$value" | |
637 | |
638 shift | |
639 i=$(($i + 1)) | |
640 done | |
641 | |
642 local keyword_args="$( | |
643 # Positional arguments can double up as keyword arguments too. | |
644 echo "$positional_args" | tr , '\n' | | |
645 while read line; do | |
646 if [[ $line == *\? ]]; then | |
647 echo "${line%?}:?" | |
648 else | |
649 echo "$line:" | |
650 fi | |
651 done | |
652 | |
653 # Specified keyword arguments. | |
654 echo "$spec" | cut -d\; -f2 | tr , '\n' | |
655 )" | |
656 local keyword_args_count="$(echo $keyword_args | awk -F, '{print NF}')" | |
657 | |
658 # Set spec values from keyword arguments, if any. The remaining arguments | |
659 # are all assumed to be keyword arguments. | |
660 while [[ $1 == --* ]]; do | |
661 # Remove the `--` at the start. | |
662 local arg="${1#--}" | |
663 | |
664 # Get the argument name and value. | |
665 if [[ $arg != *=* ]]; then | |
666 local name="$arg" | |
667 local value='' | |
668 else | |
669 local name="${arg%\=*}" | |
670 local value="${arg#*=}" | |
671 fi | |
672 | |
673 if echo "$code" | grep -l "^local $name=" &> /dev/null; then | |
674 echo "Argument '$name' repeated with the value '$value'". >&2 | |
675 return | |
676 fi | |
677 | |
678 # The specification for this argument, used for validations. | |
679 local arg_line="$(echo "$keyword_args" | | |
680 egrep "^$name:?\??" | head -n1)" | |
681 | |
682 # Validate argument and value. | |
683 if [[ -z $arg_line ]]; then | |
684 # This argument is not known to us. | |
685 echo "Unknown argument '$name'." >&2 | |
686 return | |
687 | |
688 elif (echo "$arg_line" | grep -l ':' &> /dev/null) && | |
689 [[ -z $value ]]; then | |
690 # This argument needs a value, but is not provided. | |
691 echo "Required argument for '$name' not provided." >&2 | |
692 return | |
693 | |
694 elif (echo "$arg_line" | grep -vl ':' &> /dev/null) && | |
695 [[ -n $value ]]; then | |
696 # This argument doesn't need a value, but is provided. | |
697 echo "No argument required for '$name', but provided '$value'." >&2 | |
698 return | |
699 | |
700 fi | |
701 | |
702 if [[ -z $value ]]; then | |
703 value=true | |
704 fi | |
705 | |
706 --add-var "${name//-/_}" "$value" | |
707 shift | |
708 done | |
709 | |
710 echo "$code" | |
711 | |
712 unfunction -- --add-var | |
713 | |
714 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment