diff --git a/centpkg.spec b/centpkg.spec index 5ab24f5..c67802e 100644 --- a/centpkg.spec +++ b/centpkg.spec @@ -8,15 +8,24 @@ %endif %endif + +%define compdir %(pkg-config --variable=completionsdir bash-completion) +%if "%{compdir}" == "" +%define compdir "/etc/bash_completion.d" +%endif + Name: centpkg Version: 0.5.1 -Release: 2%{?dist} +Release: 3%{?dist} Summary: CentOS utility for working with dist-git License: GPLv2+ URL: https://git.centos.org/centos/centpkg Source0: %{url}/archive/%{version}/centpkg-%{version}.tar.gz BuildArch: noarch +BuildRequires: pkgconfig +BuildRequires: bash-completion + %if %{defined el7} BuildRequires: python-devel BuildRequires: python-setuptools @@ -56,12 +65,13 @@ Provides the centpkg-sig command for working with dist-git. %py_install install -D -p -m 0644 src/centpkg.conf %{buildroot}%{_sysconfdir}/rpkg/centpkg.conf install -D -p -m 0644 src/centpkg-sig.conf %{buildroot}%{_sysconfdir}/rpkg/centpkg-sig.conf - +mv src/centpkg.bash %{buildroot}%{compdir}/centpkg %files %license COPYING %doc README.md %config(noreplace) %{_sysconfdir}/rpkg/centpkg.conf +%(dirname %{compdir}) %{_bindir}/%{name} %{python_sitelib}/%{name} %{python_sitelib}/%{name}-%{version}-py%{python_version}.egg-info @@ -73,6 +83,9 @@ install -D -p -m 0644 src/centpkg-sig.conf %{buildroot}%{_sysconfdir}/rpkg/centp %changelog +* Thur Apr 08 2021 Leonardo Rossetti - 0.5.1-3 +- Add bash completion support + * Thu Mar 25 2021 Carl George - 0.5.1-2 - Add missing el7 requirements diff --git a/src/centpkg.bash b/src/centpkg.bash new file mode 100644 index 0000000..a12fe95 --- /dev/null +++ b/src/centpkg.bash @@ -0,0 +1,390 @@ +# centpkg bash completion + +_centpkg() +{ + COMPREPLY=() + + in_array() + { + local i + for i in $2; do + [[ $i = $1 ]] && return 0 + done + return 1 + } + + _filedir_exclude_paths() + { + _filedir "$@" + for ((i=0; i<=${#COMPREPLY[@]}; i++)); do + [[ ${COMPREPLY[$i]} =~ /?\.git/? ]] && unset COMPREPLY[$i] + done + } + + local cur prev + _get_comp_words_by_ref cur prev + + # global options + + local options="--help -v -q" + local options_value="--dist --release --user --path --user-config --name --namespace" + local commands="build chain-build ci clean clog clone co commit compile \ + container-build diff gimmespec giturl help gitbuildhash import install lint \ + local mockbuild mock-config module-build module-build-cancel \ + module-build-local module-build-info module-build-watch module-overview \ + module-scratch-build \ + new new-sources patch prep pull push retire request-branch request-repo \ + request-tests-repo request-side-tag list-side-tags remove-side-tag \ + scratch-build sources srpm switch-branch tag unused-patches update upload \ + verify-files verrel override fork" + + # parse main options and get command + + local command= + local command_first= + local path= + + local i w + for (( i = 0; i < ${#COMP_WORDS[*]} - 1; i++ )); do + w="${COMP_WORDS[$i]}" + # option + if [[ ${w:0:1} = - ]]; then + if in_array "$w" "$options_value"; then + ((i++)) + [[ "$w" = --path ]] && path="${COMP_WORDS[$i]}" + fi + # command + elif in_array "$w" "$commands"; then + command="$w" + command_first=$((i+1)) + break + fi + done + + # complete base options + + if [[ -z $command ]]; then + if [[ $cur == -* ]]; then + COMPREPLY=( $(compgen -W "$options $options_value" -- "$cur") ) + return 0 + fi + + case "$prev" in + --dist | --release | --user | -u | --config) + ;; + --path) + _filedir_exclude_paths + ;; + --namespace) + COMPREPLY=( $(compgen -W "$(_centpkg_namespaces)" -- "$cur") ) + ;; + *) + COMPREPLY=( $(compgen -W "$commands" -- "$cur") ) + ;; + esac + + return 0 + fi + + # parse command specific options + + local options= + local options_target= options_arches= options_branch= options_string= options_file= options_dir= options_srpm= options_mroot= options_builder= options_namespace= + local options_update_type= options_update_request= + local options_yaml= + local after= after_more= + + case $command in + help|gimmespec|gitbuildhash|giturl|new|push|unused-patches|verrel) + ;; + build) + options="--nowait --background --skip-tag --scratch --skip-remote-rules-validation --fail-fast" + options_arches="--arches" + options_srpm="--srpm" + options_target="--target" + ;; + chain-build) + options="--nowait --background" + options_target="--target" + after="package" + after_more=true + ;; + clean) + options="--dry-run -x" + ;; + clog) + options="--raw" + ;; + clone|co) + options="--branches --anonymous" + options_branch="-b" + after="package" + ;; + commit|ci) + options="--push --clog --raw --tag --with-changelog" + options_string="--message" + options_file="--file" + after="file" + after_more=true + ;; + compile|install) + options="--short-circuit" + options_arches="--arch" + options_dir="--builddir" + ;; + container-build) + options="--scratch --nowait --repo-url --skip-remote-rules-validation" + options_arches="--arches" + options_target="--target" + ;; + diff) + options="--cached" + after="file" + after_more=true + ;; + import) + options="--create" + options_branch="--branch" + after="srpm" + ;; + lint) + options="--info" + options_file="--rpmlintconf" + ;; + list-side-tags) + options="--mine" + options_string="--user --base-tag" + ;; + local) + options="--md5" + options_arches="--arch" + options_string="--with --without" + options_dir="--builddir" + ;; + mock-config) + options="--target" + options_arches="--arch" + ;; + mockbuild) + options="--md5 --no-clean --no-cleanup-after --no-clean-all --shell" + options_string="--with --without" + options_mroot="--root --mock-config" + ;; + module-build) + options="--scratch --watch" + options_string="--optional --requires --buildrequires" + options_yaml="--file" + options_srpm="--srpm" + ;; + module-build-local) + options="--skip-tests" + options_string="--add-local-build --stream --set-default-stream" + options_yaml="--file" + options_srpm="--srpm" + ;; + module-overview) + options="--unfinished" + options_string="--limit" + ;; + module-scratch-build) + options="--watch" + options_string="--optional --requires --buildrequires" + options_yaml="--file" + options_srpm="--srpm" + ;; + patch) + options="--rediff" + options_string="--suffix" + ;; + prep|verify-files) + options_arches="--arch" + options_dir="--builddir" + ;; + pull) + options="--rebase --no-rebase" + ;; + remove-side-tag) + after_more=true + ;; + retire) + after_more=true + ;; + request-branch) + options="--no-git-branch --all-releases --no-auto-module" + options_string="--sl --repo" + ;; + request-repo) + options="--exception --no-initial-commit" + options_string="--description --monitor --upstreamurl --summary" + options_namespace="--namespace" + ;; + request-tests-repo) + options_string="--bug" + ;; + request-side-tag) + options_string="--base-tag" + ;; + scratch-build) + options="--nowait --background" + options_target="--target" + options_arches="--arches" + options_srpm="--srpm" + ;; + sources) + options_dir="--outdir" + ;; + srpm) + options="--md5" + ;; + switch-branch) + options="--list" + after="branch" + ;; + tag) + options="--clog --raw --force --list --delete" + options_string="--message" + options_file="--file" + after_more=true + ;; + upload|new-sources) + after="file" + after_more=true + ;; + update) + options="--not-close-bugs --suggest-reboot --disable-autokarma" + options_string="--notes --bugs --stable-karma --unstable-karma" + options_update_type="--type" + options_update_request="--request" + ;; + esac + + local all_options="--help $options" + local all_options_value="$options_target $options_arches $options_branch \ + $options_string $options_file $options_dir $options_srpm $options_mroot \ + $options_builder $options_namespace $options_update_type $options_update_request \ + $options_yaml" + + # count non-option parameters + + local i w + local last_option= + local after_counter=0 + for (( i = $command_first; i < ${#COMP_WORDS[*]} - 1; i++)); do + w="${COMP_WORDS[$i]}" + if [[ ${w:0:1} = - ]]; then + if in_array "$w" "$all_options"; then + last_option="$w" + continue + elif in_array "$w" "$all_options_value"; then + last_option="$w" + ((i++)) + continue + fi + fi + in_array "$last_option" "$options_arches" || ((after_counter++)) + done + + # completion + + if [[ -n $options_target ]] && in_array "$prev" "$options_target"; then + COMPREPLY=( $(compgen -W "$(_centpkg_target)" -- "$cur") ) + + elif [[ -n $options_arches ]] && in_array "$last_option" "$options_arches"; then + COMPREPLY=( $(compgen -W "$(_centpkg_arch) $all_options" -- "$cur") ) + + elif [[ -n $options_srpm ]] && in_array "$prev" "$options_srpm"; then + _filedir_exclude_paths "*.src.rpm" + + elif [[ -n $options_yaml ]] && in_array "$prev" "$options_yaml"; then + _filedir_exclude_paths "yaml" + + elif [[ -n $options_branch ]] && in_array "$prev" "$options_branch"; then + COMPREPLY=( $(compgen -W "$(_centpkg_branch "$path")" -- "$cur") ) + + elif [[ -n $options_file ]] && in_array "$prev" "$options_file"; then + _filedir_exclude_paths + + elif [[ -n $options_dir ]] && in_array "$prev" "$options_dir"; then + _filedir_exclude_paths -d + + elif [[ -n $options_string ]] && in_array "$prev" "$options_string"; then + COMPREPLY=( ) + + elif [[ -n $options_mroot ]] && in_array "$prev" "$options_mroot"; then + COMPREPLY=( ) + if declare -F _mock_root &>/dev/null; then + _mock_root + elif declare -F _xfunc &>/dev/null; then + _xfunc mock _mock_root + fi + + elif [[ -n $options_namespace ]] && in_array "$prev" "$options_namespace"; then + COMPREPLY=( $(compgen -W "$(_centpkg_namespaces)" -- "$cur") ) + + elif [[ -n $options_update_type ]] && in_array "$prev" "$options_update_type"; then + COMPREPLY=( $(compgen -W "bugfix security enhancement newpackage" -- "$cur") ) + + elif [[ -n $options_update_request ]] && in_array "$prev" "$options_update_request"; then + COMPREPLY=( $(compgen -W "testing stable" -- "$cur") ) + + else + local after_options= + + if [[ $after_counter -eq 0 ]] || [[ $after_more = true ]]; then + case $after in + file) _filedir_exclude_paths ;; + srpm) _filedir_exclude_paths "*.src.rpm" ;; + branch) after_options="$(_centpkg_branch "$path")" ;; + package) after_options="$(_centpkg_package "$cur")";; + esac + fi + + if [[ $cur != -* ]]; then + all_options= + all_options_value= + fi + + COMPREPLY+=( $(compgen -W "$all_options $all_options_value $after_options" -- "$cur" ) ) + fi + + return 0 +} && +complete -F _centpkg centpkg + +_centpkg_target() +{ + koji list-targets --quiet 2>/dev/null | cut -d" " -f1 +} + +_centpkg_arch() +{ + echo "i386 i686 x86_64 armv5tel armv7hl armv7hnl ppc ppc64 ppc64le ppc64p7 s390 s390x" +} + +_centpkg_branch() +{ + local git_options= format="--format %(refname:short)" + [[ -n $1 ]] && git_options="--git-dir=$1/.git" + + git $git_options for-each-ref $format 'refs/remotes' | sed 's,.*/,,' + git $git_options for-each-ref $format 'refs/heads' +} + +_centpkg_package() +{ + repoquery -C --qf=%{sourcerpm} "$1*" 2>/dev/null | sort -u | sed -r 's/(-[^-]*){2}\.src\.rpm$//' +} + +_centpkg_namespaces() +{ + grep "^distgit_namespaces =" /etc/rpkg/centpkg.conf | cut -d'=' -f2 +} + + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh