Automatically generate bash completions for kubectl

This commit is contained in:
Eric Paris 2015-04-12 13:23:46 -04:00
parent f318da8344
commit ebb0affc21
4 changed files with 103 additions and 137 deletions

View File

@ -0,0 +1,60 @@
/*
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
)
func main() {
// use os.Args instead of "flags" because "flags" will mess up the man pages!
outDir := "contrib/completions/bash/"
if len(os.Args) == 2 {
outDir = os.Args[1]
} else if len(os.Args) > 2 {
fmt.Fprintf(os.Stderr, "usage: %s [output directory]\n", os.Args[0])
os.Exit(1)
}
outDir, err := filepath.Abs(outDir)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
stat, err := os.Stat(outDir)
if err != nil {
fmt.Fprintf(os.Stderr, "output directory %s does not exist\n", outDir)
os.Exit(1)
}
if !stat.IsDir() {
fmt.Fprintf(os.Stderr, "output directory %s is not a directory\n", outDir)
os.Exit(1)
}
outFile := outDir + "/kubectl"
//TODO os.Stdin should really be something like ioutil.Discard, but a Reader
kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
kubectl.GenBashCompletionFile(outFile)
}

View File

@ -149,73 +149,6 @@ __handle_word()
__handle_word
}
# call kubectl get $1,
# use the first column in compgen
# we could use templates, but then would need a template per resource
__kubectl_parse_get()
{
local kubectl_output out
if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
out=($(echo "${kubectl_output}" | awk '{print $1}'))
COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
fi
}
__kubectl_get_resource()
{
if [[ ${#nouns[@]} -eq 0 ]]; then
return 1
fi
__kubectl_parse_get ${nouns[${#nouns[@]} -1]}
if [[ $? -eq 0 ]]; then
return 0
fi
}
# $1 is the name of the pod we want to get the list of containers inside
__kubectl_get_containers()
{
local template
template="{{ range .desiredState.manifest.containers }}{{ .name }} {{ end }}"
__debug ${FUNCNAME} "nouns are ${nouns[@]}"
local len="${#nouns[@]}"
if [[ ${len} -ne 1 ]]; then
return
fi
local last=${nouns[${len} -1]}
local kubectl_out
if kubectl_out=$(kubectl get -o template --template="${template}" pods "${last}" 2>/dev/null); then
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
fi
}
# Require both a pod and a container to be specified
__kubectl_require_pod_and_container()
{
if [[ ${#nouns[@]} -eq 0 ]]; then
__kubectl_parse_get pods
return 0
fi;
__kubectl_get_containers
return 0
}
__custom_func() {
case ${last_command} in
kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
__kubectl_get_resource
return
;;
kubectl_log)
__kubectl_require_pod_and_container
return
;;
*)
;;
esac
}
_kubectl_get()
{
last_command="kubectl_get"
@ -242,19 +175,6 @@ _kubectl_get()
must_have_one_flag=()
must_have_one_noun=()
must_have_one_noun+=("limitrange")
must_have_one_noun+=("resourcequota")
must_have_one_noun+=("persistentvolume")
must_have_one_noun+=("service")
must_have_one_noun+=("event")
must_have_one_noun+=("namespace")
must_have_one_noun+=("pod")
must_have_one_noun+=("secret")
must_have_one_noun+=("replicationcontroller")
must_have_one_noun+=("node")
must_have_one_noun+=("status")
must_have_one_noun+=("persistentvolumeclaim")
must_have_one_noun+=("endpoints")
}
_kubectl_describe()
@ -272,15 +192,6 @@ _kubectl_describe()
must_have_one_flag=()
must_have_one_noun=()
must_have_one_noun+=("persistentvolume")
must_have_one_noun+=("persistentvolumeclaim")
must_have_one_noun+=("pod")
must_have_one_noun+=("service")
must_have_one_noun+=("node")
must_have_one_noun+=("limitrange")
must_have_one_noun+=("resourcequota")
must_have_one_noun+=("replicationcontroller")
must_have_one_noun+=("minion")
}
_kubectl_create()
@ -294,17 +205,11 @@ _kubectl_create()
flags_completion=()
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'")
flags+=("--help")
flags+=("-h")
must_have_one_flag=()
must_have_one_flag+=("--filename=")
must_have_one_flag+=("-f")
must_have_one_noun=()
}
@ -319,19 +224,12 @@ _kubectl_update()
flags_completion=()
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'")
flags+=("--help")
flags+=("-h")
flags+=("--patch=")
must_have_one_flag=()
must_have_one_flag+=("--filename=")
must_have_one_flag+=("-f")
must_have_one_flag+=("--patch=")
must_have_one_noun=()
}
@ -347,11 +245,7 @@ _kubectl_delete()
flags+=("--all")
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'")
flags+=("--help")
flags+=("-h")
flags+=("--selector=")
@ -409,11 +303,7 @@ _kubectl_rolling-update()
flags_completion=()
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'")
flags+=("--help")
flags+=("-h")
flags+=("--poll-interval=")
@ -421,8 +311,6 @@ _kubectl_rolling-update()
flags+=("--update-period=")
must_have_one_flag=()
must_have_one_flag+=("--filename=")
must_have_one_flag+=("-f")
must_have_one_noun=()
}
@ -443,7 +331,6 @@ _kubectl_resize()
flags+=("--resource-version=")
must_have_one_flag=()
must_have_one_flag+=("--replicas=")
must_have_one_noun=()
}
@ -469,10 +356,6 @@ _kubectl_exec()
flags+=("-t")
must_have_one_flag=()
must_have_one_flag+=("--container=")
must_have_one_flag+=("-c")
must_have_one_flag+=("--pod=")
must_have_one_flag+=("-p")
must_have_one_noun=()
}
@ -492,8 +375,6 @@ _kubectl_port-forward()
two_word_flags+=("-p")
must_have_one_flag=()
must_have_one_flag+=("--pod=")
must_have_one_flag+=("-p")
must_have_one_noun=()
}
@ -550,7 +431,6 @@ _kubectl_run-container()
two_word_flags+=("-t")
must_have_one_flag=()
must_have_one_flag+=("--image=")
must_have_one_noun=()
}
@ -566,11 +446,7 @@ _kubectl_stop()
flags+=("--all")
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'")
flags+=("--help")
flags+=("-h")
flags+=("--selector=")
@ -613,7 +489,6 @@ _kubectl_expose()
two_word_flags+=("-t")
must_have_one_flag=()
must_have_one_flag+=("--port=")
must_have_one_noun=()
}

View File

@ -22,7 +22,7 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/gendocs cmd/genman
"${KUBE_ROOT}/hack/build-go.sh" cmd/gendocs cmd/genman cmd/genbashcomp
# Get the absolute path of the directory component of a file, i.e. the
# absolute path of the dirname of $1.
@ -67,28 +67,35 @@ case "$(uname -m)" in
esac
# Find binary
doc_locations=(
locations=(
"${KUBE_ROOT}/_output/dockerized/bin/${host_os}/${host_arch}/gendocs"
"${KUBE_ROOT}/_output/local/bin/${host_os}/${host_arch}/gendocs"
"${KUBE_ROOT}/platforms/${host_os}/${host_arch}/gendocs"
)
gendocs=$( (ls -t "${doc_locations[@]}" 2>/dev/null || true) | head -1 )
man_locations=(
gendocs=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
locations=(
"${KUBE_ROOT}/_output/dockerized/bin/${host_os}/${host_arch}/genman"
"${KUBE_ROOT}/_output/local/bin/${host_os}/${host_arch}/genman"
"${KUBE_ROOT}/platforms/${host_os}/${host_arch}/genman"
)
genman=$( (ls -t "${man_locations[@]}" 2>/dev/null || true) | head -1 )
genman=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
locations=(
"${KUBE_ROOT}/_output/dockerized/bin/${host_os}/${host_arch}/genbashcomp"
"${KUBE_ROOT}/_output/local/bin/${host_os}/${host_arch}/genbashcomp"
"${KUBE_ROOT}/platforms/${host_os}/${host_arch}/genbashcomp"
)
genbashcomp=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
if [[ ! -x "$gendocs" || ! -x "$genman" ]]; then
if [[ ! -x "$gendocs" || ! -x "$genman" || ! -x "$genbashcomp" ]]; then
{
echo "It looks as if you don't have a compiled gendocs or genman binary"
echo "It looks as if you don't have a compiled gendocs, genman, or genbashcomp binary"
echo
echo "If you are running from a clone of the git repo, please run"
echo "'./hack/build-go.sh cmd/gendocs cmd/genman'."
echo "'./hack/build-go.sh cmd/gendocs cmd/genman cmd/genbashcomp'."
} >&2
exit 1
fi
${gendocs} "${KUBE_ROOT}/docs/"
${genman} "${KUBE_ROOT}/docs/man/man1/"
${genbashcomp} "${KUBE_ROOT}/contrib/completions/bash/"

View File

@ -22,7 +22,7 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/gendocs cmd/genman
"${KUBE_ROOT}/hack/build-go.sh" cmd/gendocs cmd/genman cmd/genbashcomp
# Get the absolute path of the directory component of a file, i.e. the
# absolute path of the dirname of $1.
@ -81,12 +81,19 @@ locations=(
)
genman=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
if [[ ! -x "$gendocs" || ! -x "$genman" ]]; then
locations=(
"${KUBE_ROOT}/_output/dockerized/bin/${host_os}/${host_arch}/genbashcomp"
"${KUBE_ROOT}/_output/local/bin/${host_os}/${host_arch}/genbashcomp"
"${KUBE_ROOT}/platforms/${host_os}/${host_arch}/genbashcomp"
)
genbashcomp=$( (ls -t "${locations[@]}" 2>/dev/null || true) | head -1 )
if [[ ! -x "$gendocs" || ! -x "$genman" || ! -x "$genbashcomp" ]]; then
{
echo "It looks as if you don't have a compiled gendocs or genman binary"
echo "It looks as if you don't have a compiled gendocs, genman, or genbashcomp binary"
echo
echo "If you are running from a clone of the git repo, please run"
echo "'./hack/build-go.sh cmd/gendocs cmd/genman'."
echo "'./hack/build-go.sh cmd/gendocs cmd/genman cmd/genbashcomp'."
} >&2
exit 1
fi
@ -109,3 +116,20 @@ else
echo "${DOCROOT} is out of date. Please run hack/run-gendocs.sh"
exit 1
fi
COMPROOT="${KUBE_ROOT}/contrib/completions"
TMP_COMPROOT="${KUBE_ROOT}/contrib/completions_tmp"
cp -a "${COMPROOT}" "${TMP_COMPROOT}"
${genbashcomp} "${TMP_COMPROOT}/bash/"
set +e
diff -Naupr "${COMPROOT}" "${TMP_COMPROOT}"
ret=$?
set -e
rm -rf ${TMP_COMPROOT}
if [ $ret -eq 0 ]
then
echo "${COMPROOT} up to date."
else
echo "${COMPROOT} is out of date. Please run hack/run-gendocs.sh"
exit 1
fi