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 ───────────────────────────────────────────────────────── # ─── Shell Completion ─────────────────────────────────────────────────────────
_completion_bash() { _completion_bash() {
local stacks_init="$1" # pre-rendered stacks array initialisation block
cat << 'EOF' cat << 'EOF'
# stacks.sh bash completion — source this file or place in /etc/bash_completion.d/ # stacks.sh bash completion — source this file or place in /etc/bash_completion.d/
_stacks_complete() { _stacks_complete() {
@@ -736,19 +737,10 @@ _stacks_complete() {
prev="${COMP_WORDS[COMP_CWORD-1]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
} }
# Locate the stacks dir from the invoked script path
local script="${COMP_WORDS[0]}" local script="${COMP_WORDS[0]}"
local stacks_dir EOF
stacks_dir="$(cd "$(dirname "$(realpath "$script" 2>/dev/null || echo "$script")")" 2>/dev/null && pwd)" echo "$stacks_init"
cat << 'EOF'
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
local commands="ls ps up down restart pull logs exec run config images top stats compose update backup new completion version help" 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" local update_subs="install uninstall run status logs next"
@@ -758,7 +750,7 @@ _stacks_complete() {
case "${COMP_WORDS[1]}" in case "${COMP_WORDS[1]}" in
update) COMPREPLY=( $(compgen -W "$update_subs" -- "$cur") ); return ;; update) COMPREPLY=( $(compgen -W "$update_subs" -- "$cur") ); return ;;
backup) COMPREPLY=( $(compgen -W "$backup_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) new)
case "$prev" in case "$prev" in
--db) COMPREPLY=( $(compgen -W "postgres mysql mariadb" -- "$cur") ); return ;; --db) COMPREPLY=( $(compgen -W "postgres mysql mariadb" -- "$cur") ); return ;;
@@ -803,22 +795,15 @@ EOF
} }
_completion_zsh() { _completion_zsh() {
local stacks_init="$1" # pre-rendered stacks array initialisation block
cat << 'EOF' cat << 'EOF'
#compdef stacks.sh stacks #compdef stacks.sh stacks
_stacks() { _stacks() {
local script="${words[1]}" local script="${words[1]}"
local stacks_dir EOF
stacks_dir="$(cd "$(dirname "$(realpath "$script" 2>/dev/null || echo "$script")")" 2>/dev/null && pwd)" echo "$stacks_init"
cat << 'EOF'
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
local -a commands=( local -a commands=(
'ls:List all stacks with live status' 'ls:List all stacks with live status'
@@ -916,6 +901,7 @@ _stacks() {
completion) completion)
_arguments \ _arguments \
'--install[Install the completion file]' \ '--install[Install the completion file]' \
'--static[Bake current stack list into completion script]' \
'1:shell:(bash zsh)' '1:shell:(bash zsh)'
;; ;;
esac esac
@@ -928,13 +914,14 @@ EOF
} }
cmd_completion() { cmd_completion() {
local shell="" install=false local shell="" install=false static=false
for arg in "$@"; do for arg in "$@"; do
case "$arg" in case "$arg" in
bash|zsh) shell="$arg" ;; bash|zsh) shell="$arg" ;;
--install) install=true ;; --install) install=true ;;
*) die "Unknown argument: $arg (bash|zsh [--install])" ;; --static) static=true ;;
*) die "Unknown argument: $arg (bash|zsh [--install] [--static])" ;;
esac esac
done done
@@ -944,10 +931,52 @@ cmd_completion() {
warn "No shell specified, defaulting to: $shell" warn "No shell specified, defaulting to: $shell"
fi 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 local content
case "$shell" in case "$shell" in
bash) content="$(_completion_bash)" ;; bash) content="$(_completion_bash "$bash_stacks_init")" ;;
zsh) content="$(_completion_zsh)" ;; zsh) content="$(_completion_zsh "$zsh_stacks_init")" ;;
*) die "Unsupported shell: $shell (bash|zsh)" ;; *) die "Unsupported shell: $shell (bash|zsh)" ;;
esac esac
@@ -1042,7 +1071,8 @@ ${BOLD}UTILITIES${RESET}
--db postgres|mysql|mariadb Add a database service --db postgres|mysql|mariadb Add a database service
--redis Add a Redis service --redis Add a Redis service
--no-traefik Expose port instead of Traefik labels --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}version${RESET} Print version
${CYAN}help${RESET} Show this help ${CYAN}help${RESET} Show this help