diff --git a/cmd/genbashcomp/gen_kubectl_bash_comp.go b/cmd/genbashcomp/gen_kubectl_bash_comp.go new file mode 100644 index 00000000000..aec7dc6f80e --- /dev/null +++ b/cmd/genbashcomp/gen_kubectl_bash_comp.go @@ -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) +} diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 4cde434f47e..201d9acea2d 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -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=() } diff --git a/hack/run-gendocs.sh b/hack/run-gendocs.sh index 912ce64a9c3..2676714eaa7 100755 --- a/hack/run-gendocs.sh +++ b/hack/run-gendocs.sh @@ -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/" diff --git a/hack/verify-gendocs.sh b/hack/verify-gendocs.sh index 33ba6babf60..a663a2ceafc 100755 --- a/hack/verify-gendocs.sh +++ b/hack/verify-gendocs.sh @@ -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