Merge pull request #265 from sttts/sttts-shellcheck
Run shellcheck on bash completion
This commit is contained in:
		@ -4,6 +4,10 @@ go:
 | 
				
			|||||||
  - 1.4.2
 | 
					  - 1.4.2
 | 
				
			||||||
  - 1.5.1
 | 
					  - 1.5.1
 | 
				
			||||||
  - tip
 | 
					  - tip
 | 
				
			||||||
 | 
					before_install:
 | 
				
			||||||
 | 
					  - mkdir -p bin
 | 
				
			||||||
 | 
					  - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck
 | 
				
			||||||
 | 
					  - chmod +x bin/shellcheck
 | 
				
			||||||
script:
 | 
					script:
 | 
				
			||||||
  - go test -v ./...
 | 
					  - PATH=$PATH:$PWD/bin go test -v ./...
 | 
				
			||||||
  - go build
 | 
					  - go build
 | 
				
			||||||
 | 
				
			|||||||
@ -61,7 +61,7 @@ __contains_word()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__handle_reply()
 | 
					__handle_reply()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    __debug "${FUNCNAME}"
 | 
					    __debug "${FUNCNAME[0]}"
 | 
				
			||||||
    case $cur in
 | 
					    case $cur in
 | 
				
			||||||
        -*)
 | 
					        -*)
 | 
				
			||||||
            if [[ $(type -t compopt) = "builtin" ]]; then
 | 
					            if [[ $(type -t compopt) = "builtin" ]]; then
 | 
				
			||||||
@ -75,7 +75,7 @@ __handle_reply()
 | 
				
			|||||||
            fi
 | 
					            fi
 | 
				
			||||||
            COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") )
 | 
					            COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") )
 | 
				
			||||||
            if [[ $(type -t compopt) = "builtin" ]]; then
 | 
					            if [[ $(type -t compopt) = "builtin" ]]; then
 | 
				
			||||||
                [[ $COMPREPLY == *= ]] || compopt +o nospace
 | 
					                [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace
 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # complete after --flag=abc
 | 
					            # complete after --flag=abc
 | 
				
			||||||
@ -88,11 +88,13 @@ __handle_reply()
 | 
				
			|||||||
                flag="${cur%%=*}"
 | 
					                flag="${cur%%=*}"
 | 
				
			||||||
                __index_of_word "${flag}" "${flags_with_completion[@]}"
 | 
					                __index_of_word "${flag}" "${flags_with_completion[@]}"
 | 
				
			||||||
                if [[ ${index} -ge 0 ]]; then
 | 
					                if [[ ${index} -ge 0 ]]; then
 | 
				
			||||||
                    COMPREPLY=() PREFIX="" cur="${cur#*=}"
 | 
					                    COMPREPLY=()
 | 
				
			||||||
 | 
					                    PREFIX=""
 | 
				
			||||||
 | 
					                    cur="${cur#*=}"
 | 
				
			||||||
                    ${flags_completion[${index}]}
 | 
					                    ${flags_completion[${index}]}
 | 
				
			||||||
                    if [ -n "${ZSH_VERSION}" ]; then
 | 
					                    if [ -n "${ZSH_VERSION}" ]; then
 | 
				
			||||||
                        # zfs completion needs --flag= prefix
 | 
					                        # zfs completion needs --flag= prefix
 | 
				
			||||||
                        eval COMPREPLY=( "\${COMPREPLY[@]/#/${flag}=}" )
 | 
					                        eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
 | 
				
			||||||
                    fi
 | 
					                    fi
 | 
				
			||||||
                fi
 | 
					                fi
 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
@ -149,7 +151,7 @@ __handle_subdirs_in_dir_flag()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__handle_flag()
 | 
					__handle_flag()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
 | 
					    __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # if a command required a flag, and we found it, unset must_have_one_flag()
 | 
					    # if a command required a flag, and we found it, unset must_have_one_flag()
 | 
				
			||||||
    local flagname=${words[c]}
 | 
					    local flagname=${words[c]}
 | 
				
			||||||
@ -160,15 +162,15 @@ __handle_flag()
 | 
				
			|||||||
        flagname=${flagname%%=*} # strip everything after the =
 | 
					        flagname=${flagname%%=*} # strip everything after the =
 | 
				
			||||||
        flagname="${flagname}=" # but put the = back
 | 
					        flagname="${flagname}=" # but put the = back
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    __debug "${FUNCNAME}: looking for ${flagname}"
 | 
					    __debug "${FUNCNAME[0]}: looking for ${flagname}"
 | 
				
			||||||
    if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then
 | 
					    if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then
 | 
				
			||||||
        must_have_one_flag=()
 | 
					        must_have_one_flag=()
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # keep flag value with flagname as flaghash
 | 
					    # keep flag value with flagname as flaghash
 | 
				
			||||||
    if [ ${flagvalue} ] ; then
 | 
					    if [ -n "${flagvalue}" ] ; then
 | 
				
			||||||
        flaghash[${flagname}]=${flagvalue}
 | 
					        flaghash[${flagname}]=${flagvalue}
 | 
				
			||||||
    elif [ ${words[ $((c+1)) ]} ] ; then
 | 
					    elif [ -n "${words[ $((c+1)) ]}" ] ; then
 | 
				
			||||||
        flaghash[${flagname}]=${words[ $((c+1)) ]}
 | 
					        flaghash[${flagname}]=${words[ $((c+1)) ]}
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        flaghash[${flagname}]="true" # pad "true" for bool flag
 | 
					        flaghash[${flagname}]="true" # pad "true" for bool flag
 | 
				
			||||||
@ -189,7 +191,7 @@ __handle_flag()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__handle_noun()
 | 
					__handle_noun()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
 | 
					    __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
 | 
					    if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
 | 
				
			||||||
        must_have_one_noun=()
 | 
					        must_have_one_noun=()
 | 
				
			||||||
@ -203,20 +205,20 @@ __handle_noun()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__handle_command()
 | 
					__handle_command()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
 | 
					    __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    local next_command
 | 
					    local next_command
 | 
				
			||||||
    if [[ -n ${last_command} ]]; then
 | 
					    if [[ -n ${last_command} ]]; then
 | 
				
			||||||
        next_command="_${last_command}_${words[c]//:/__}"
 | 
					        next_command="_${last_command}_${words[c]//:/__}"
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        if [[ $c -eq 0 ]]; then
 | 
					        if [[ $c -eq 0 ]]; then
 | 
				
			||||||
            next_command="_$(basename ${words[c]//:/__})"
 | 
					            next_command="_$(basename "${words[c]//:/__}")"
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            next_command="_${words[c]//:/__}"
 | 
					            next_command="_${words[c]//:/__}"
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    c=$((c+1))
 | 
					    c=$((c+1))
 | 
				
			||||||
    __debug "${FUNCNAME}: looking for ${next_command}"
 | 
					    __debug "${FUNCNAME[0]}: looking for ${next_command}"
 | 
				
			||||||
    declare -F $next_command >/dev/null && $next_command
 | 
					    declare -F $next_command >/dev/null && $next_command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -226,12 +228,12 @@ __handle_word()
 | 
				
			|||||||
        __handle_reply
 | 
					        __handle_reply
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
 | 
					    __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
 | 
				
			||||||
    if [[ "${words[c]}" == -* ]]; then
 | 
					    if [[ "${words[c]}" == -* ]]; then
 | 
				
			||||||
        __handle_flag
 | 
					        __handle_flag
 | 
				
			||||||
    elif __contains_word "${words[c]}" "${commands[@]}"; then
 | 
					    elif __contains_word "${words[c]}" "${commands[@]}"; then
 | 
				
			||||||
        __handle_command
 | 
					        __handle_command
 | 
				
			||||||
    elif [[ $c -eq 0 ]] && __contains_word "$(basename ${words[c]})" "${commands[@]}"; then
 | 
					    elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then
 | 
				
			||||||
        __handle_command
 | 
					        __handle_command
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        __handle_noun
 | 
					        __handle_noun
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -23,6 +24,26 @@ func check(t *testing.T, found, expected string) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func runShellCheck(s string) error {
 | 
				
			||||||
 | 
						excluded := []string{
 | 
				
			||||||
 | 
							"SC2034", // PREFIX appears unused. Verify it or export it.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", strings.Join(excluded, ","))
 | 
				
			||||||
 | 
						cmd.Stderr = os.Stderr
 | 
				
			||||||
 | 
						cmd.Stdout = os.Stdout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stdin, err := cmd.StdinPipe()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer stdin.Close()
 | 
				
			||||||
 | 
							stdin.Write([]byte(s))
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cmd.Run()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// World worst custom function, just keep telling you to enter hello!
 | 
					// World worst custom function, just keep telling you to enter hello!
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	bashCompletionFunc = `__custom_func() {
 | 
						bashCompletionFunc = `__custom_func() {
 | 
				
			||||||
@ -107,4 +128,13 @@ func TestBashCompletions(t *testing.T) {
 | 
				
			|||||||
	check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
 | 
						check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	checkOmit(t, str, cmdDeprecated.Name())
 | 
						checkOmit(t, str, cmdDeprecated.Name())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if available, run shellcheck against the script
 | 
				
			||||||
 | 
						if err := exec.Command("which", "shellcheck").Run(); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := runShellCheck(str)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("shellcheck failed: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user