diff --git a/.goreleaser.yaml b/.goreleaser.yaml index b1efbec13..bab5c161f 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -182,6 +182,7 @@ brews: install: | bin.install "aicr" bin.install "aicr-attestation.sigstore.json" if File.exist? "aicr-attestation.sigstore.json" + generate_completions_from_executable(bin/"aicr", "completion") test: | assert_match version.to_s, shell_output("#{bin}/aicr version") caveats: | diff --git a/docs/user/installation.md b/docs/user/installation.md index 61cda62a0..107cc7a3f 100644 --- a/docs/user/installation.md +++ b/docs/user/installation.md @@ -40,6 +40,7 @@ This script: - Detects your OS and architecture automatically - Downloads the appropriate binary from GitHub releases - Installs to `/usr/local/bin/aicr` by default (use `-d ` for a custom location) +- Installs shell completions for bash, zsh, and fish (set `AICR_NO_COMPLETIONS=1` to skip) - Verifies the installation - Uses `GITHUB_TOKEN` environment variable for authenticated API calls (avoids rate limits) @@ -99,26 +100,41 @@ Expected output shows version information and available commands. ## Post-Installation -### Shell Completion (Optional) +### Shell Completion -Enable shell auto-completion for command and flag names: +Tab completion for commands and flags is installed automatically by both the Homebrew formula and the install script. No manual setup is required. + +**Opt out** (install script only): set `AICR_NO_COMPLETIONS=1` before running the script: -**Bash:** ```shell -# Add to ~/.bashrc -source <(aicr completion bash) +AICR_NO_COMPLETIONS=1 curl -sfL https://raw.githubusercontent.com/NVIDIA/aicr/main/install | bash -s -- ``` -**Zsh:** +**Manual setup** (build from source or `go install`): + +Bash: ```shell -# Add to ~/.zshrc -source <(aicr completion zsh) +aicr completion bash > "${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions/aicr" +``` + +Zsh: +```shell +aicr completion zsh > "${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions/_aicr" ``` -**Fish:** +Fish: ```shell -# Add to ~/.config/fish/config.fish -aicr completion fish | source +aicr completion fish > ~/.config/fish/completions/aicr.fish +``` + +Alternatively, source completions dynamically in your shell RC file (evaluates on every shell start): + +```shell +# Bash (~/.bashrc) +source <(aicr completion bash) + +# Zsh (~/.zshrc) +source <(aicr completion zsh) ``` ## Container Images @@ -180,8 +196,15 @@ nvidia-smi # Remove binary sudo rm /usr/local/bin/aicr -# Remove shell completion (if configured) -# Remove the source line from your shell RC file +# Remove shell completions (remove whichever exist) +sudo rm -f /usr/share/bash-completion/completions/aicr +sudo rm -f /usr/local/share/zsh/site-functions/_aicr +sudo rm -f /opt/homebrew/share/zsh/site-functions/_aicr +sudo rm -f /opt/homebrew/etc/bash_completion.d/aicr +sudo rm -f /usr/local/etc/bash_completion.d/aicr +rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions/aicr" +rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/zsh/site-functions/_aicr" +rm -f "${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions/aicr.fish" ``` ## Getting Help diff --git a/install b/install index aa9d22d12..e5922eddb 100755 --- a/install +++ b/install @@ -30,7 +30,8 @@ Install utility for $BIN_NAME Usage: $0 [-d install_dir] Environment Variables: - GITHUB_TOKEN GitHub token to avoid API rate limits (no special scopes required) + GITHUB_TOKEN GitHub token to avoid API rate limits (no special scopes required) + AICR_NO_COMPLETIONS Set to 1 to skip shell completion installation Examples: $0 # Install to /usr/local/bin @@ -106,6 +107,97 @@ get_archive_name() { echo "${BIN_NAME}_${ver}_${2}_${3}.tar.gz" # version, os, arch } +# ============================================================================== +# Shell Completion Setup +# ============================================================================== + +write_completion() { + local bin_path="$1" shell="$2" target="$3" + local target_dir tmp_file + target_dir=$(dirname "$target") + mkdir -p "$target_dir" 2>/dev/null || sudo mkdir -p "$target_dir" 2>/dev/null || return 1 + tmp_file=$(mktemp) || return 1 + if ! "$bin_path" completion "$shell" > "$tmp_file" 2>/dev/null || [[ ! -s "$tmp_file" ]]; then + rm -f "$tmp_file" + return 1 + fi + chmod 644 "$tmp_file" + if [[ -w "$target_dir" ]]; then + mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; } + else + sudo mv "$tmp_file" "$target" || { rm -f "$tmp_file"; return 1; } + fi +} + +setup_bash_completions() { + local bin_path="$1" os="$2" xdg_data="$3" + local sys_dir + if [[ "$os" == "darwin" ]]; then + local brew_prefix="/usr/local" + [[ -d /opt/homebrew ]] && brew_prefix="/opt/homebrew" + sys_dir="${brew_prefix}/etc/bash_completion.d" + else + sys_dir="/usr/share/bash-completion/completions" + fi + + if write_completion "$bin_path" bash "${sys_dir}/aicr"; then + ok "Bash completions installed" + elif write_completion "$bin_path" bash "${xdg_data}/bash-completion/completions/aicr"; then + ok "Bash completions installed (user-local)" + else + warn "Could not install bash completions" + fi +} + +setup_zsh_completions() { + local bin_path="$1" os="$2" xdg_data="$3" + local sys_dir + if [[ "$os" == "darwin" ]]; then + local brew_prefix="/usr/local" + [[ -d /opt/homebrew ]] && brew_prefix="/opt/homebrew" + sys_dir="${brew_prefix}/share/zsh/site-functions" + else + sys_dir="/usr/local/share/zsh/site-functions" + fi + + if write_completion "$bin_path" zsh "${sys_dir}/_aicr"; then + ok "Zsh completions installed" + elif write_completion "$bin_path" zsh "${xdg_data}/zsh/site-functions/_aicr"; then + ok "Zsh completions installed (user-local)" + else + warn "Could not install zsh completions" + fi +} + +setup_fish_completions() { + local bin_path="$1" + local sys_dir="/usr/share/fish/vendor_completions.d" + local user_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions" + + if [[ -d "$sys_dir" ]] && write_completion "$bin_path" fish "${sys_dir}/aicr.fish"; then + ok "Fish completions installed" + elif [[ -d "${user_dir%/*}" ]] && write_completion "$bin_path" fish "${user_dir}/aicr.fish"; then + ok "Fish completions installed (user-local)" + fi +} + +setup_completions() { + if [[ "${AICR_NO_COMPLETIONS:-0}" == "1" ]]; then + info "Skipping shell completion setup (AICR_NO_COMPLETIONS=1)" + return 0 + fi + + local bin_path="${INSTALL_DIR}/${BIN_NAME}" + local os xdg_data + os=$(get_os) + xdg_data="${XDG_DATA_HOME:-$HOME/.local/share}" + step "Setting up shell completions..." + + setup_bash_completions "$bin_path" "$os" "$xdg_data" + setup_zsh_completions "$bin_path" "$os" "$xdg_data" + setup_fish_completions "$bin_path" +} + # ============================================================================== # GitHub API Functions # ============================================================================== @@ -313,6 +405,9 @@ main() { [[ -f "${INSTALL_DIR}/${BIN_NAME}-attestation.sigstore.json" ]] && \ msg "Attestation: ${INSTALL_DIR}/${BIN_NAME}-attestation.sigstore.json" + # Install shell completions + setup_completions || warn "Shell completion setup failed (non-fatal)" + # Fetch latest Sigstore trusted root for offline verification. # The trusted root enables 'aicr verify' to check attestation signatures # without contacting Sigstore infrastructure. If this fails (e.g., no network),