Files
reg/reg-completion.bash
2026-11-05 09:09:02 +03:00

377 lines
14 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================================================
# reg — Docker Registry Client
# bash completion
# ============================================================================
#
# Установка (любой из вариантов):
#
# 1) source ./reg-completion.bash
# 2) cp reg-completion.bash ~/.local/share/bash-completion/completions/reg
# 3) sudo cp reg-completion.bash /usr/share/bash-completion/completions/reg
# 4) echo 'source /path/to/reg-completion.bash' >> ~/.bashrc
#
# При изменении CLI (новые команды, подкоманды, флаги) обновляйте:
# _reg_commands, _reg_*_subcommands, _reg_help_subcommands,
# _reg_opts_<group>_<cmd>, _reg_value_flags, _reg_values_<flag>.
#
# Флаги справки (-h/-help/--help) в опциях намеренно отсутствуют:
# справка доступна только через `reg help <command>`.
# ============================================================================
# --- Справочники команд и флагов --------------------------------------------
_reg_commands="repo blob image manifest auth referrer config export import ping capabilities help"
_reg_global_flags="-r -config -lang -token -user -pass -insecure"
_reg_repo_subcommands="list tree tags info manifest delete find latest prune stats verify"
_reg_blob_subcommands="delete get info"
_reg_image_subcommands="pull push copy config files history"
_reg_manifest_subcommands="rm tag untag exist digest"
_reg_auth_subcommands="login logout status migrate token whoami"
_reg_referrer_subcommands="list"
_reg_config_subcommands="get set unset list"
_reg_help_subcommands="repo blob image manifest auth referrer config export import ping capabilities help"
# Флаги по командам и подкомандам
_reg_opts_repo=""
_reg_opts_repo_list="-a -filter"
_reg_opts_repo_tree="-a -s -h"
_reg_opts_repo_tags="-a -d"
_reg_opts_repo_info="-platform"
_reg_opts_repo_manifest=""
_reg_opts_repo_delete="-f"
_reg_opts_repo_find="-a"
_reg_opts_repo_latest="-a"
_reg_opts_repo_prune="-keep -older-than -dry-run -force-latest"
_reg_opts_repo_stats="-h"
_reg_opts_repo_verify="-deep -jobs -v"
_reg_opts_blob=""
_reg_opts_blob_delete=""
_reg_opts_blob_get="-o -v"
_reg_opts_blob_info=""
_reg_opts_image=""
_reg_opts_image_pull="-o -f -platform -v"
_reg_opts_image_push="-mount-from -chunk-size"
_reg_opts_image_copy="-platform -mount-from"
_reg_opts_image_config="-platform -field -raw"
_reg_opts_image_files="-platform -all -layer -name -n -v"
_reg_opts_image_history="-platform -raw"
_reg_opts_manifest=""
_reg_opts_manifest_rm="-p -f"
_reg_opts_manifest_tag=""
_reg_opts_manifest_untag=""
_reg_opts_manifest_exist=""
_reg_opts_manifest_digest=""
_reg_opts_auth=""
_reg_opts_auth_login="-user -pass"
_reg_opts_auth_logout=""
_reg_opts_auth_status=""
_reg_opts_auth_migrate="-from -to -dry-run -overwrite -registry"
_reg_opts_auth_token="-raw"
_reg_opts_auth_whoami=""
_reg_opts_referrer=""
_reg_opts_referrer_list="-type"
_reg_opts_config=""
_reg_opts_export="-o -platform"
_reg_opts_import=""
_reg_opts_ping="-v"
_reg_opts_capabilities=""
_reg_opts_help=""
# Флаги, принимающие значение (для подсчёта позиционных аргументов)
_reg_value_flags="-r -config -lang -token -user -pass -o -platform -p -mount-from -chunk-size -type -filter -from -to -registry -keep -older-than -jobs -field -layer -name"
# Возможные значения для отдельных флагов
_reg_values_platform="linux/amd64 linux/arm64 linux/arm/v7 linux/386 windows/amd64 darwin/amd64 darwin/arm64"
_reg_values_lang="en ru"
_reg_values_vault="docker local"
_reg_chunk_values="1048576 5242880 10485760"
_reg_jobs_values="1 2 4 8 16 32"
_reg_keep_values="1 3 5 10 20 50"
# --- Вспомогательные функции ------------------------------------------------
# Значение registry= из ~/.reg/reg.conf (если есть).
_reg_registry_from_config() {
local f="$HOME/.reg/reg.conf"
[[ -r "$f" ]] || return 0
local line
while IFS= read -r line; do
case "$line" in
registry=*) echo "${line#registry=}"; return 0 ;;
esac
done < "$f"
}
# Дополнение каталогов (совместимо с наличием/отсутствием bash-completion)
_reg_complete_dir() {
if declare -F _filedir >/dev/null 2>&1; then
_filedir -d
else
COMPREPLY=($(compgen -d -- "$cur"))
fi
}
# Дополнение файлов и каталогов
_reg_complete_file() {
if declare -F _filedir >/dev/null 2>&1; then
_filedir
else
COMPREPLY=($(compgen -f -- "$cur"))
fi
}
# Значения для -platform / -p / -lang / -chunk-size / -r / -from / -to / -jobs / -keep по имени флага
_reg_values_for_flag() {
local flag="$1"
case "$flag" in
-platform|-p) echo "$_reg_values_platform" ;;
-lang) echo "$_reg_values_lang" ;;
-from|-to) echo "$_reg_values_vault" ;;
-chunk-size) echo "$_reg_chunk_values" ;;
-jobs) echo "$_reg_jobs_values" ;;
-keep) echo "$_reg_keep_values" ;;
-r) _reg_registry_from_config ;;
*) : ;;
esac
}
# Флаги для конкретной группы/подкоманды
_reg_opts_for() {
local cmd="$1" sub="$2"
case "$cmd" in
repo)
case "$sub" in
list) echo "$_reg_opts_repo_list" ;;
tree) echo "$_reg_opts_repo_tree" ;;
tags) echo "$_reg_opts_repo_tags" ;;
info) echo "$_reg_opts_repo_info" ;;
manifest) echo "$_reg_opts_repo_manifest" ;;
delete) echo "$_reg_opts_repo_delete" ;;
find) echo "$_reg_opts_repo_find" ;;
latest) echo "$_reg_opts_repo_latest" ;;
prune) echo "$_reg_opts_repo_prune" ;;
stats) echo "$_reg_opts_repo_stats" ;;
verify) echo "$_reg_opts_repo_verify" ;;
*) echo "$_reg_opts_repo" ;;
esac
;;
blob)
case "$sub" in
delete) echo "$_reg_opts_blob_delete" ;;
get) echo "$_reg_opts_blob_get" ;;
info) echo "$_reg_opts_blob_info" ;;
*) echo "$_reg_opts_blob" ;;
esac
;;
image)
case "$sub" in
pull) echo "$_reg_opts_image_pull" ;;
push) echo "$_reg_opts_image_push" ;;
copy) echo "$_reg_opts_image_copy" ;;
config) echo "$_reg_opts_image_config" ;;
files) echo "$_reg_opts_image_files" ;;
history) echo "$_reg_opts_image_history" ;;
*) echo "$_reg_opts_image" ;;
esac
;;
manifest)
case "$sub" in
rm) echo "$_reg_opts_manifest_rm" ;;
tag) echo "$_reg_opts_manifest_tag" ;;
untag) echo "$_reg_opts_manifest_untag" ;;
exist) echo "$_reg_opts_manifest_exist" ;;
digest) echo "$_reg_opts_manifest_digest" ;;
*) echo "$_reg_opts_manifest" ;;
esac
;;
auth)
case "$sub" in
login) echo "$_reg_opts_auth_login" ;;
logout) echo "$_reg_opts_auth_logout" ;;
status) echo "$_reg_opts_auth_status" ;;
migrate) echo "$_reg_opts_auth_migrate" ;;
token) echo "$_reg_opts_auth_token" ;;
whoami) echo "$_reg_opts_auth_whoami" ;;
*) echo "$_reg_opts_auth" ;;
esac
;;
referrer)
case "$sub" in
list) echo "$_reg_opts_referrer_list" ;;
*) echo "$_reg_opts_referrer" ;;
esac
;;
config) echo "$_reg_opts_config" ;;
export) echo "$_reg_opts_export" ;;
import) echo "$_reg_opts_import" ;;
ping) echo "$_reg_opts_ping" ;;
capabilities) echo "$_reg_opts_capabilities" ;;
help) echo "$_reg_opts_help" ;;
# Top-level aliases
pull) echo "$_reg_opts_image_pull" ;;
push) echo "$_reg_opts_image_push" ;;
copy) echo "$_reg_opts_image_copy" ;;
rm) echo "$_reg_opts_manifest_rm" ;;
tag) echo "$_reg_opts_manifest_tag" ;;
untag) echo "$_reg_opts_manifest_untag" ;;
exist) echo "$_reg_opts_manifest_exist" ;;
digest) echo "$_reg_opts_manifest_digest" ;;
login) echo "$_reg_opts_auth_login" ;;
logout) echo "$_reg_opts_auth_logout" ;;
token) echo "$_reg_opts_auth_token" ;;
whoami) echo "$_reg_opts_auth_whoami" ;;
esac
}
# --- Основная функция автодополнения ----------------------------------------
_reg_complete() {
local cur prev
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
# --- Обработка формы --flag=value / -flag=value -------------------------
if [[ "$cur" == -*=* ]]; then
local flag="${cur%%=*}"
local val="${cur#*=}"
local vals
vals="$(_reg_values_for_flag "$flag")"
if [[ -n "$vals" ]]; then
local matches
matches=($(compgen -W "$vals" -- "$val"))
COMPREPLY=("${matches[@]/#/$flag=}")
return 0
fi
fi
# --- Собираем позиционные аргументы до текущего слова -------------------
local -a positionals=()
local skip_next=0 i w f
for ((i=1; i<COMP_CWORD; i++)); do
w="${COMP_WORDS[i]}"
if [[ $skip_next -eq 1 ]]; then
skip_next=0
continue
fi
case "$w" in
-*=*) ;;
*)
local is_value=0
for f in $_reg_value_flags; do
if [[ "$w" == "$f" ]]; then is_value=1; break; fi
done
if [[ $is_value -eq 1 ]]; then
skip_next=1
elif [[ "$w" == -* ]]; then
:
else
positionals+=("$w")
fi
;;
esac
done
local cmd="" subcmd=""
if [[ ${#positionals[@]} -ge 1 ]]; then cmd="${positionals[0]}"; fi
if [[ ${#positionals[@]} -ge 2 ]]; then subcmd="${positionals[1]}"; fi
local npos=${#positionals[@]}
# --- Завершение значения флага (после space) ----------------------------
if [[ "$cur" != -* ]]; then
local vals
vals="$(_reg_values_for_flag "$prev")"
if [[ -n "$vals" ]]; then
COMPREPLY=($(compgen -W "$vals" -- "$cur"))
return 0
fi
case "$prev" in
-o)
_reg_complete_dir
return 0
;;
-config)
_reg_complete_file
return 0
;;
esac
fi
# --- Завершение подкоманд известных групп -------------------------------
if [[ "$npos" -eq 1 ]]; then
case "$cmd" in
repo) COMPREPLY=($(compgen -W "$_reg_repo_subcommands" -- "$cur")); return 0 ;;
blob) COMPREPLY=($(compgen -W "$_reg_blob_subcommands" -- "$cur")); return 0 ;;
image) COMPREPLY=($(compgen -W "$_reg_image_subcommands" -- "$cur")); return 0 ;;
manifest) COMPREPLY=($(compgen -W "$_reg_manifest_subcommands" -- "$cur")); return 0 ;;
auth) COMPREPLY=($(compgen -W "$_reg_auth_subcommands" -- "$cur")); return 0 ;;
referrer) COMPREPLY=($(compgen -W "$_reg_referrer_subcommands" -- "$cur")); return 0 ;;
config) COMPREPLY=($(compgen -W "$_reg_config_subcommands" -- "$cur")); return 0 ;;
esac
fi
# --- Завершение аргументов help -----------------------------------------
if [[ "$cmd" == "help" ]]; then
case "$npos" in
1)
COMPREPLY=($(compgen -W "$_reg_help_subcommands" -- "$cur"))
return 0
;;
2)
case "$subcmd" in
repo) COMPREPLY=($(compgen -W "$_reg_repo_subcommands" -- "$cur")); return 0 ;;
blob) COMPREPLY=($(compgen -W "$_reg_blob_subcommands" -- "$cur")); return 0 ;;
image) COMPREPLY=($(compgen -W "$_reg_image_subcommands" -- "$cur")); return 0 ;;
manifest) COMPREPLY=($(compgen -W "$_reg_manifest_subcommands" -- "$cur")); return 0 ;;
auth) COMPREPLY=($(compgen -W "$_reg_auth_subcommands" -- "$cur")); return 0 ;;
referrer) COMPREPLY=($(compgen -W "$_reg_referrer_subcommands" -- "$cur")); return 0 ;;
config) COMPREPLY=($(compgen -W "$_reg_config_subcommands" -- "$cur")); return 0 ;;
esac
;;
esac
fi
# --- Первый позиционный аргумент push/import: файлы/каталоги ------------
if [[ ( "$cmd" == "push" || "$cmd" == "import" ) && "$npos" -eq 1 && "$cur" != -* ]]; then
_reg_complete_file
return 0
fi
if [[ "$cmd" == "image" && "$subcmd" == "push" && "$npos" -eq 2 && "$cur" != -* ]]; then
_reg_complete_file
return 0
fi
# --- Завершение флагов --------------------------------------------------
if [[ "$cur" == -* ]]; then
local opts
if [[ -z "$cmd" ]]; then
opts="$_reg_global_flags"
else
opts="$(_reg_opts_for "$cmd" "$subcmd")"
fi
if [[ -n "$opts" ]]; then
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
fi
return 0
fi
# --- Пустое слово после команды: подсказываем флаги ---------------------
if [[ -z "$cur" && -n "$cmd" ]]; then
local opts
opts="$(_reg_opts_for "$cmd" "$subcmd")"
if [[ -n "$opts" ]]; then
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
fi
return 0
fi
return 0
}
# --- Регистрация --------------------------------------------------------------
complete -F _reg_complete reg