Merge pull request from sttts/sttts-shellcheck

Run shellcheck on bash completion
This commit is contained in:
Eric Paris 2016-04-03 09:08:35 -05:00
commit 4c05eb1145
3 changed files with 51 additions and 15 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
}
} }