feat(stacks): add --static flag to completion command

Bakes the current stack list into the generated completion script instead
of using runtime directory discovery. Useful for remote hosts where the
stacks dir path differs from the local repo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 19:52:55 +02:00
parent 3251f27edb
commit 067d017ea6
+59 -29
View File
@@ -726,6 +726,7 @@ REDIS
# ─── Shell Completion ─────────────────────────────────────────────────────────
_completion_bash() {
local stacks_init="$1" # pre-rendered stacks array initialisation block
cat << 'EOF'
# stacks.sh bash completion — source this file or place in /etc/bash_completion.d/
_stacks_complete() {
@@ -736,19 +737,10 @@ _stacks_complete() {
prev="${COMP_WORDS[COMP_CWORD-1]}"
}
# Locate the stacks dir from the invoked script path
local script="${COMP_WORDS[0]}"
local stacks_dir
stacks_dir="$(cd "$(dirname "$(realpath "$script" 2>/dev/null || echo "$script")")" 2>/dev/null && pwd)"
local -a stacks=()
if [[ -d "$stacks_dir" ]]; then
for d in "$stacks_dir"/*/; do
local n; n="$(basename "$d")"
[[ "$n" == _* ]] && continue
[[ -f "$d/compose.yml" ]] && stacks+=("$n")
done
fi
EOF
echo "$stacks_init"
cat << 'EOF'
local commands="ls ps up down restart pull logs exec run config images top stats compose update backup new completion version help"
local update_subs="install uninstall run status logs next"
@@ -758,7 +750,7 @@ _stacks_complete() {
case "${COMP_WORDS[1]}" in
update) COMPREPLY=( $(compgen -W "$update_subs" -- "$cur") ); return ;;
backup) COMPREPLY=( $(compgen -W "$backup_subs" -- "$cur") ); return ;;
completion) COMPREPLY=( $(compgen -W "bash zsh --install" -- "$cur") ); return ;;
completion) COMPREPLY=( $(compgen -W "bash zsh --install --static" -- "$cur") ); return ;;
new)
case "$prev" in
--db) COMPREPLY=( $(compgen -W "postgres mysql mariadb" -- "$cur") ); return ;;
@@ -803,22 +795,15 @@ EOF
}
_completion_zsh() {
local stacks_init="$1" # pre-rendered stacks array initialisation block
cat << 'EOF'
#compdef stacks.sh stacks
_stacks() {
local script="${words[1]}"
local stacks_dir
stacks_dir="$(cd "$(dirname "$(realpath "$script" 2>/dev/null || echo "$script")")" 2>/dev/null && pwd)"
local -a stacks=()
if [[ -d "$stacks_dir" ]]; then
for d in "$stacks_dir"/*/; do
local n="${d:t}"
[[ "$n" == _* ]] && continue
[[ -f "${d}compose.yml" ]] && stacks+=("$n")
done
fi
EOF
echo "$stacks_init"
cat << 'EOF'
local -a commands=(
'ls:List all stacks with live status'
@@ -916,6 +901,7 @@ _stacks() {
completion)
_arguments \
'--install[Install the completion file]' \
'--static[Bake current stack list into completion script]' \
'1:shell:(bash zsh)'
;;
esac
@@ -928,13 +914,14 @@ EOF
}
cmd_completion() {
local shell="" install=false
local shell="" install=false static=false
for arg in "$@"; do
case "$arg" in
bash|zsh) shell="$arg" ;;
--install) install=true ;;
*) die "Unknown argument: $arg (bash|zsh [--install])" ;;
--static) static=true ;;
*) die "Unknown argument: $arg (bash|zsh [--install] [--static])" ;;
esac
done
@@ -944,10 +931,52 @@ cmd_completion() {
warn "No shell specified, defaulting to: $shell"
fi
# Build the stacks array initialisation block — either dynamic (runtime discovery)
# or static (current list baked in at generation time).
local bash_stacks_init zsh_stacks_init
if $static; then
local -a cur_stacks=()
mapfile -t cur_stacks < <(list_all_stacks)
[[ ${#cur_stacks[@]} -eq 0 ]] && die "No stacks found to bake into completion"
local generated_at
generated_at="$(date '+%Y-%m-%d')"
bash_stacks_init=" # Stacks baked in at generation time (${generated_at}) — rerun to update
local -a stacks=(${cur_stacks[*]})"
zsh_stacks_init=" # Stacks baked in at generation time (${generated_at}) — rerun to update
local -a stacks=(${cur_stacks[*]})"
info "Baking ${#cur_stacks[@]} stacks: ${cur_stacks[*]}"
else
bash_stacks_init=' # Dynamically discover stacks from the script location at completion time
local stacks_dir
stacks_dir="$(cd "$(dirname "$(realpath "$script" 2>/dev/null || echo "$script")")" 2>/dev/null && pwd)"
local -a stacks=()
if [[ -d "$stacks_dir" ]]; then
for d in "$stacks_dir"/*/; do
local n; n="$(basename "$d")"
[[ "$n" == _* ]] && continue
[[ -f "$d/compose.yml" ]] && stacks+=("$n")
done
fi'
zsh_stacks_init=' # Dynamically discover stacks from the script location at completion time
local stacks_dir
stacks_dir="$(cd "$(dirname "$(realpath "$script" 2>/dev/null || echo "$script")")" 2>/dev/null && pwd)"
local -a stacks=()
if [[ -d "$stacks_dir" ]]; then
for d in "$stacks_dir"/*/; do
local n="${d:t}"
[[ "$n" == _* ]] && continue
[[ -f "${d}compose.yml" ]] && stacks+=("$n")
done
fi'
fi
local content
case "$shell" in
bash) content="$(_completion_bash)" ;;
zsh) content="$(_completion_zsh)" ;;
bash) content="$(_completion_bash "$bash_stacks_init")" ;;
zsh) content="$(_completion_zsh "$zsh_stacks_init")" ;;
*) die "Unsupported shell: $shell (bash|zsh)" ;;
esac
@@ -1042,7 +1071,8 @@ ${BOLD}UTILITIES${RESET}
--db postgres|mysql|mariadb Add a database service
--redis Add a Redis service
--no-traefik Expose port instead of Traefik labels
${CYAN}completion${RESET} bash|zsh [--install] Generate/install shell completion
${CYAN}completion${RESET} bash|zsh [--install] [--static] Generate/install shell completion
--static Bake current stack list in (no runtime discovery)
${CYAN}version${RESET} Print version
${CYAN}help${RESET} Show this help