repo.bash: replace with better version

From https://raw.github.com/aartamonau/repo.bash_completion/master/repo.bash_completion

Change-Id: I7ca5d7eba70244d875c48ce76c999c8a10b88934
This commit is contained in:
Chirayu Desai 2013-04-10 21:11:02 +05:30
parent 7a7185b044
commit d308210b0f
2 changed files with 641 additions and 113 deletions

View File

@ -1,27 +0,0 @@
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,99 +1,654 @@
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the repo-LICENSE file.
# -*- mode: sh; -*-
# Programmable completion for some Chromium OS build scripts.
declare -A CMD_HANDLERS
CMD_HANDLERS=(
["init"]=_repo_init
["help"]=_repo_help
["abandon"]=_repo_abandon
["branch"]=_repo_branch
["branches"]=_repo_branches
["checkout"]=_repo_checkout
["cherry-pick"]=_repo_cherry_pick
["diff"]=_repo_diff
["download"]=_repo_download
["forall"]=_repo_forall
["grep"]=_repo_grep
["list"]=_repo_list
["prune"]=_repo_prune
["rebase"]=_repo_rebase
["selfupdate"]=_repo_selfupdate
["smartsync"]=_repo_smartsync
["stage"]=_repo_stage
["start"]=_repo_start
["status"]=_repo_status
["sync"]=_repo_sync
["upload"]=_repo_upload
["version"]=_repo_version
)
_list_repo_commands() {
local repo=${COMP_WORDS[0]}
"${repo}" help --all | grep -E '^ ' | sed 's/ \([^ ]\+\) .\+/\1/'
# To be populated by command handlers.
declare -a OPTIONS
declare -A ARG_OPTIONS
declare cur
declare prev
_init_cur_prev() {
cur=$(_get_cword "=")
prev=$(_get_cword "=" 1)
_split_longopt
}
_list_repo_branches() {
local repo=${COMP_WORDS[0]}
"${repo}" branches 2>&1 | grep \| | sed 's/[ *][Pp ] *\([^ ]\+\) .*/\1/'
}
_find_repo() {
local dir=$(pwd)
local found=1
_list_repo_projects() {
local repo=${COMP_WORDS[0]}
local manifest=$(mktemp)
"${repo}" manifest -o "${manifest}" >& /dev/null
grep 'project name=' "${manifest}" | sed 's/.\+name="\([^"]\+\)".\+/\1/'
rm -f "${manifest}" >& /dev/null
}
while [ "${dir}" != / ]
do
if [ -f "${dir}/.repo/repo/main.py" ]
then
found=0
break
fi
# Complete the repo <command> argument.
_complete_repo_command() {
[ ${COMP_CWORD} -eq 1 ] || return 1
local command=${COMP_WORDS[1]}
COMPREPLY=($(compgen -W "$(_list_repo_commands)" -- "${command}"))
return 0
}
dir=$(cd "${dir}/.." && pwd)
done
_complete_repo_arg() {
[ ${COMP_CWORD} -gt 1 ] || return 1
local command=${COMP_WORDS[1]}
local current=${COMP_WORDS[COMP_CWORD]}
if [[ ${command} == "abandon" ]]; then
if [[ ${COMP_CWORD} -eq 2 ]]; then
COMPREPLY=($(compgen -W "$(_list_repo_branches)" -- "${current}"))
else
COMPREPLY=($(compgen -W "$(_list_repo_projects)" -- "${current}"))
if [ ${found} -eq 0 ]
then
echo "${dir}"
fi
}
_is_repo_dir() {
local repo_root=$(_find_repo)
[ -n "${repo_root}" ]
}
_gen_comps() {
local completions="$1"
local suffix="${2:- }"
local -i i
local -a tmp=( $(compgen -W "${completions}" -- ${cur}) )
for (( i=0; i < ${#tmp[*]}; i++ ))
do
tmp[$i]="${tmp[$i]}${suffix}"
done
COMPREPLY=(
"${COMPREPLY[@]}"
"${tmp[@]}"
)
}
_strip_colors () {
# taken from http://goo.gl/7KlLZ
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"
}
_no_completion() {
true
}
_command_completion() {
local cmds
if _is_repo_dir
then
cmds=("abandon" "branch" "branches" "checkout" "cherry-pick" "diff"
"download" "forall" "grep" "help" "init" "list" "prune" "rebase"
"selfupdate" "smartsync" "stage" "start" "status" "sync"
"upload" "version")
else
cmds=("help" "init")
fi
_gen_comps "${cmds[*]}"
}
_branch_completion() {
local raw_branches
# separate statement required to be able to access exit code
raw_branches=$(repo branches 2>/dev/null)
if [ $? -eq 0 ]
then
local branches=$(
echo "${raw_branches}" |
_strip_colors | awk 'BEGIN { FS="|" } { print $1 }' | cut -c 3-
)
_gen_comps "${branches}"
fi
}
_dir_completion() {
_filedir -d
}
_project_completion() {
local repo_root=$(_find_repo)
if [ -n "${repo_root}" -a -f "${repo_root}/.repo/project.list" ]
then
local projects=$(cat "${repo_root}/.repo/project.list")
_gen_comps "${projects}"
fi
}
_manifest_completion() {
local repo_root=$(_find_repo)
if [ -n "${repo_root}" ]
then
local manifests_dir="${repo_root}/.repo/manifests"
local git_dir="${manifests_dir}/.git"
local candidates
manifests=$(
git --git-dir "${git_dir}" ls-files "*.xml" 2>/dev/null)
if [ $? -eq 0 ]
then
_gen_comps "${manifests}"
fi
fi
}
_path_cmd_completion() {
_gen_comps "$(compgen -c ${cur})"
}
_is_option() {
local opt="$1"
[[ "${opt}" == -* ]]
}
_is_long_option() {
local opt="$1"
[[ "${opt}" == --* ]]
}
_expects_arg() {
local opt="$1"
if [[ ${ARG_OPTIONS[$opt]} ]]
then
return 0
else
return 1
fi
}
_handle_options() {
if _expects_arg "${prev}"
then
local handler=${ARG_OPTIONS[$prev]}
eval ${handler} "${cur}"
elif _is_option "${cur}"
then
_gen_comps "${OPTIONS[*]}"
local arg_short
local arg_long
for opt in "${!ARG_OPTIONS[@]}"
do
if _is_long_option "${opt}"
then
arg_long="${arg_long} ${opt}"
else
arg_short="${arg_short} ${opt}"
fi
done
_gen_comps "${arg_short}"
_gen_comps "${arg_long}" "="
else
return 1
fi
return 0
fi
if [[ ${command} == "help" ]]; then
[ ${COMP_CWORD} -eq 2 ] && \
COMPREPLY=($(compgen -W "$(_list_repo_commands)" -- "${current}"))
}
_is_known_shortopt() {
local needle="$1"
for opt in ${OPTIONS[@]}
do
if [ "${opt}" = "${needle}" ]
then
return 0
fi
done
return 1
}
_is_known_longopt() {
local needle="$1"
[[ ${ARG_OPTIONS[$1]} ]]
}
_arg_index() {
local -i i=2 # skip repo and command
local -i ix=0
while [ ${i} -lt ${COMP_CWORD} ]
do
if _is_known_shortopt "${COMP_WORDS[i]}"
then
i+=1
elif _is_known_longopt "${COMP_WORDS[i]}"
then
i+=2
elif _is_option "${COMP_WORDS[i]}"
then
i+=1
else
i+=1
ix+=1
fi
done
eval $1="${ix}"
}
_when_ix() {
local ix="$1"
local completion="$2"
_arg_index arg_ix
if [ ${arg_ix} -eq ${ix} ]
then
${completion}
return 0
else
return 1
fi
}
_when_first() {
_when_ix 0 "$1"
}
_when_even() {
local completion="$1"
_arg_index arg_ix
if [ $(( ${arg_ix} % 2 )) -eq 0 ]
then
${completion}
return 0
else
return 1
fi
}
_cmp_opts() {
local opt="$1"
local word="$2"
if _is_option "${opt}" && ! _is_long_option "${opt}"
then
[ "${word}" == "${opt}" ]
else
[[ "${word}" == "${opt}"=* || "${word}" == "${opt}" ]]
fi
}
_before() {
local completion="$1"
local words
shift
_get_comp_words_by_ref -n = words
for word in "${words[@]}"
do
for needle in "$@"
do
if _cmp_opts "${needle}" "${word}"
then
return 1
fi
done
done
${completion}
return 0
fi
if [[ ${command} == "start" ]]; then
[ ${COMP_CWORD} -gt 2 ] && \
COMPREPLY=($(compgen -W "$(_list_repo_projects)" -- "${current}"))
}
_repo_init() {
OPTIONS=(
"-h" "--help"
"-q" "--quite"
"--mirror"
"--no-repo-verify"
)
ARG_OPTIONS=(
["-u"]=_no_completion
["--manifest-url"]=_no_completion
["-b"]=_no_completion
["--manifest-branch"]=_no_completion
["-m"]=_manifest_completion
["--manifest-name"]=_manifest_completion
["--reference"]=_dir_completion
["--repo-url"]=_no_completion
["--repo-branch"]=_no_completion
)
_handle_options
}
_repo_help() {
OPTIONS=(
"-a" "--all"
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _when_first _command_completion
}
_repo_abandon() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _when_first _branch_completion || _project_completion
}
_repo_branch() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options
}
_repo_branches() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options
}
_repo_checkout() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _when_first _branch_completion || _project_completion
}
_repo_cherry_pick() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options
}
_repo_diff() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _project_completion
}
_repo_download() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _when_even _project_completion
}
_repo_forall() {
OPTIONS=(
"-h" "--help"
"-p"
"-v" "--verbose"
)
ARG_OPTIONS=(
["-c"]=_path_cmd_completion
["--command"]=_path_cmd_completion
)
_handle_options || _before _project_completion -c --command || _filedir
}
_repo_grep() {
OPTIONS=(
"-h" "--help"
"--cached"
"-r" "--revision"
"-i" "--ignore-case"
"-a" "--text"
"-I"
"-w" "--word-regexp"
"-v" "--invert-match"
"-G" "--basic-regexp"
"-E" "--extended-regexp"
"-F" "--fixed-strings"
"--all-match"
"--and" "--or" "--not"
"-(" "-)"
"-n"
"-l" "--name-only" "--files-with-matches"
"-L" "--files-without-match"
)
ARG_OPTIONS=(
["-e"]=_no_completion
["-C"]=_no_completion
["-B"]=_no_completion
["-A"]=_no_completion
)
_handle_options || _project_completion
}
_repo_list() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _project_completion
}
_repo_prune() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options || _project_completion
}
_repo_rebase() {
OPTIONS=(
"-h" "--help"
"-i" "--interactive"
"-f" "--force-rebase"
"--no-ff"
"-q" "--quiet"
"--autosquash"
)
ARG_OPTIONS=(
["--whitespace"]=_no_completion
)
_handle_options || _project_completion
}
_repo_selfupdate() {
OPTIONS=(
"-h" "--help"
"--no-repo-verify"
)
ARG_OPTIONS=()
_handle_options
}
_repo_smartsync() {
OPTIONS=(
"-h" "--help"
"-f" "--force-broken"
"-l" "--local-only"
"-n" "--network-only"
"-d" "--detach"
"-q" "--quiet"
"--no-repo-verify"
)
ARG_OPTIONS=(
["-j"]=_no_completion
["--jobs"]=_no_completion
)
_handle_options || _project_completion
}
_repo_stage() {
OPTIONS=(
"-h" "--help"
"-i" "--interactive"
)
ARG_OPTIONS=()
_handle_options || _project_completion
}
_repo_start() {
OPTIONS=(
"-h" "--help"
"--all"
)
ARG_OPTIONS=()
_handle_options || _when_first _branch_completion || _project_completion
}
_repo_status() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=(
["-j"]=_no_completion
["--jobs"]=_no_completion
)
_handle_options || _project_completion
}
_repo_sync() {
OPTIONS=(
"-h" "--help"
"-f" "--force-broken"
"-l" "--local-only"
"-n" "--network-only"
"-d" "--detach"
"-q" "--quiet"
"-s" "--smart-sync"
"--no-repo-verify"
)
ARG_OPTIONS=(
["-j"]=_no_completion
["--jobs"]=_no_completion
)
_handle_options || _project_completion
}
_repo_upload() {
OPTIONS=(
"-h" "--help"
"-t"
"--no-verify"
"--verify"
)
ARG_OPTIONS=(
["--re"]=_no_completion
["--reviewers"]=_no_completion
["--cc"]=_no_completion
["--br"]=_branch_completion
)
_handle_options || _project_completion
}
_repo_version() {
OPTIONS=(
"-h" "--help"
)
ARG_OPTIONS=()
_handle_options
}
_repo() {
COMPREPLY=()
_init_cur_prev
if [ ${COMP_CWORD} -eq 1 ]
then
_command_completion
else
local cmd=${COMP_WORDS[1]}
local handler=${CMD_HANDLERS["${cmd}"]}
if [ -n ${handler} ]
then
eval ${handler}
fi
fi
return 0
fi
return 1
}
# Complete the repo arguments.
_complete_repo() {
COMPREPLY=()
_complete_repo_command && return 0
_complete_repo_arg && return 0
return 0
}
complete -F _complete_repo repo
# Add a way to get the "m" branch from repo easily; used by __git_branch_ps1()
#
# Repo seems to maintain a phony 'm/' remote and it always seems to be the name
# of the manifest branch. This will retrieve it.
__git_m_branch() {
local git_dir=$(git rev-parse --git-dir 2> /dev/null)
if [ -n "${git_dir}" ]; then
echo $(cd ${git_dir}/refs/remotes/m 2> /dev/null && ls)
fi
}
# A "subclass" of __git_ps1 that adds the manifest branch name into the prompt.
# ...if you're on manifest branch "0.11.257.B" and local branch "lo" and
# pass " (%s)", we'll output " (0.11.257.B/lo)". Note that we'll never show
# the manifest branch 'master', since it's so common.
__git_branch_ps1() {
local format_str="${1:- (%s)}"
local m_branch=$(__git_m_branch)
if [ "${m_branch}" != "master" -a -n "${m_branch}" ]; then
format_str=$(printf "${format_str}" "${m_branch}/%s")
fi
# for subshells, prefix the prompt with the shell nesting level
local lshlvl=""
[ ! -z "${SHLVL##*[!0-9]*}" ] && [ ${SHLVL} -gt 1 ] && lshlvl="${SHLVL} "
__git_ps1 "${lshlvl}${format_str}"
}
# Prompt functions should not error when in subshells
export -f __gitdir
export -f __git_ps1
export -f __git_m_branch
export -f __git_branch_ps1
complete -o nospace -F _repo repo