diff --git a/install.sh b/install.sh index deb242a..9cb2e83 100755 --- a/install.sh +++ b/install.sh @@ -36,6 +36,7 @@ step() { printf ' %s→%s %s\n' "$C_CYAN" "$C_RESET" "$*"; } ok() { printf ' %s✓%s %s\n' "$C_GREEN" "$C_RESET" "$*"; } warn() { printf ' %s!%s %s\n' "$C_YELLOW" "$C_RESET" "$*"; } err() { printf ' %s✗%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; exit 1; } +has() { command -v "$1" >/dev/null 2>&1; } banner() { [ -t 1 ] || return 0 @@ -68,6 +69,22 @@ esac step "Detected ${os}/${arch}" +# --------------------------------------------------------------------------- +# Detect existing install +# --------------------------------------------------------------------------- +existing_path="$INSTALL_DIR/$BINARY" +existing_version="" +if [ -x "$existing_path" ]; then + existing_version=$("$existing_path" --version 2>/dev/null | head -n1 | tr -d '[:space:]' || true) + case "$existing_version" in + v*|dev|"") ;; + *) existing_version="v$existing_version" ;; + esac + if [ -n "$existing_version" ]; then + step "Found existing ${BINARY} ${C_BOLD}${existing_version}${C_RESET}" + fi +fi + # --------------------------------------------------------------------------- # Resolve version (latest by default) # --------------------------------------------------------------------------- @@ -84,7 +101,16 @@ case "$VERSION" in esac ver_clean="${VERSION#v}" -step "Resolved version ${C_BOLD}${VERSION}${C_RESET}" +if [ -z "$existing_version" ]; then + install_mode=install + step "Resolved version ${C_BOLD}${VERSION}${C_RESET}" +elif [ "$existing_version" = "$VERSION" ]; then + install_mode=reinstall + step "Resolved version ${C_BOLD}${VERSION}${C_RESET} (already up to date — reinstalling)" +else + install_mode=update + step "Updating ${C_BOLD}${existing_version}${C_RESET} → ${C_BOLD}${VERSION}${C_RESET}" +fi # --------------------------------------------------------------------------- # Build URLs and download @@ -107,9 +133,9 @@ fi if curl -fsSL "$checksum_url" -o "$tmp/checksums.txt" 2>/dev/null; then expected=$(grep " ${asset}\$" "$tmp/checksums.txt" | awk '{print $1}') if [ -n "$expected" ]; then - if command -v sha256sum >/dev/null 2>&1; then + if has sha256sum; then actual=$(sha256sum "$tmp/$asset" | awk '{print $1}') - elif command -v shasum >/dev/null 2>&1; then + elif has shasum; then actual=$(shasum -a 256 "$tmp/$asset" | awk '{print $1}') else warn "no sha256 tool found — skipping checksum verification" @@ -133,10 +159,18 @@ tar -xzf "$tmp/$asset" -C "$tmp" [ -f "$tmp/$BINARY" ] || err "archive did not contain a '$BINARY' binary" mkdir -p "$INSTALL_DIR" -mv "$tmp/$BINARY" "$INSTALL_DIR/$BINARY" -chmod +x "$INSTALL_DIR/$BINARY" +if has install; then + install -m 0755 "$tmp/$BINARY" "$INSTALL_DIR/$BINARY" +else + mv "$tmp/$BINARY" "$INSTALL_DIR/$BINARY" + chmod +x "$INSTALL_DIR/$BINARY" +fi -ok "Installed ${C_BOLD}${BINARY} ${VERSION}${C_RESET} to ${INSTALL_DIR}/${BINARY}" +case "$install_mode" in + reinstall) ok "Reinstalled ${C_BOLD}${BINARY} ${VERSION}${C_RESET} to ${INSTALL_DIR}/${BINARY}" ;; + update) ok "Updated ${C_BOLD}${BINARY}${C_RESET} ${existing_version} → ${C_BOLD}${VERSION}${C_RESET} at ${INSTALL_DIR}/${BINARY}" ;; + *) ok "Installed ${C_BOLD}${BINARY} ${VERSION}${C_RESET} to ${INSTALL_DIR}/${BINARY}" ;; +esac # --------------------------------------------------------------------------- # PATH hint @@ -160,7 +194,9 @@ esac # to the curl pipe — we read input from /dev/tty instead. print_next_steps() { printf '\n %sNext steps%s\n' "$C_BOLD" "$C_RESET" - printf ' %schatwoot auth login%s log in to your Chatwoot instance\n' "$C_CYAN" "$C_RESET" + if [ ! -f "$HOME/.chatwoot/config.yaml" ]; then + printf ' %schatwoot auth login%s log in to your Chatwoot instance\n' "$C_CYAN" "$C_RESET" + fi printf ' %schatwoot --help%s see all commands\n\n' "$C_CYAN" "$C_RESET" } @@ -180,43 +216,102 @@ case "${SHELL##*/}" in ;; esac -printf '\n %sSet up tab completion for %s?%s [Y/n] ' "$C_BOLD" "$shell_kind" "$C_RESET" -if ! read -r response < /dev/tty; then - echo - print_next_steps - exit 0 -fi -case "$response" in - n|N|no|NO|No) - step "Skipped completion setup" - print_next_steps - exit 0 - ;; -esac - +# Skip the prompt entirely if completion is already configured. +completion_configured=false case "$shell_kind" in bash) - dir="${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions" - mkdir -p "$dir" - "$INSTALL_DIR/$BINARY" completion bash -c > "$dir/$BINARY" - ok "Added bash completion to ${dir}/${BINARY} — restart your shell to enable" + completion_dir="${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions" + completion_path="$completion_dir/$BINARY" + [ -f "$completion_path" ] && completion_configured=true ;; fish) - dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions" - mkdir -p "$dir" - "$INSTALL_DIR/$BINARY" completion fish -c > "$dir/$BINARY.fish" - ok "Added fish completion to ${dir}/${BINARY}.fish" + completion_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish/completions" + completion_path="$completion_dir/$BINARY.fish" + [ -f "$completion_path" ] && completion_configured=true ;; zsh) rc="${ZDOTDIR:-$HOME}/.zshrc" - line="source <(\"$INSTALL_DIR/$BINARY\" completion zsh -c)" - if [ -f "$rc" ] && grep -Fq "$line" "$rc"; then - step "zsh completion already present in ${rc}" - else - printf '\n# chatwoot CLI completion\n%s\n' "$line" >> "$rc" - ok "Added zsh completion to ${rc} — restart your shell to enable" + completion_path="$rc" + zsh_line="source <(\"$INSTALL_DIR/$BINARY\" completion zsh -c)" + if [ -f "$rc" ] && grep -Fq "$zsh_line" "$rc"; then + completion_configured=true fi ;; esac +if [ "$completion_configured" = true ]; then + printf '\n' + step "${shell_kind} completion already configured in ${completion_path} — skipping" +else + printf '\n %sSet up tab completion for %s?%s [Y/n] ' "$C_BOLD" "$shell_kind" "$C_RESET" + if ! read -r response < /dev/tty; then + echo + response=n + fi + case "$response" in + n|N|no|NO|No) + step "Skipped completion setup" + ;; + *) + case "$shell_kind" in + bash) + mkdir -p "$completion_dir" + "$INSTALL_DIR/$BINARY" completion bash -c > "$completion_path" + ok "Added bash completion to ${completion_path} — restart your shell to enable" + ;; + fish) + mkdir -p "$completion_dir" + "$INSTALL_DIR/$BINARY" completion fish -c > "$completion_path" + ok "Added fish completion to ${completion_path}" + ;; + zsh) + printf '\n# chatwoot CLI completion\n%s\n' "$zsh_line" >> "$rc" + ok "Added zsh completion to ${rc} — restart your shell to enable" + ;; + esac + ;; + esac +fi + +# --------------------------------------------------------------------------- +# Optional: 'cw' alias +# --------------------------------------------------------------------------- +case "$shell_kind" in + bash) + alias_rc="$HOME/.bashrc" + alias_line="alias cw='$BINARY'" + ;; + zsh) + alias_rc="${ZDOTDIR:-$HOME}/.zshrc" + alias_line="alias cw='$BINARY'" + ;; + fish) + alias_rc="${XDG_CONFIG_HOME:-$HOME/.config}/fish/config.fish" + alias_line="alias cw '$BINARY'" + ;; +esac + +alias_configured=false +[ -f "$alias_rc" ] && grep -Fq "$alias_line" "$alias_rc" && alias_configured=true + +if [ "$alias_configured" = true ]; then + step "'cw' alias already configured in ${alias_rc} — skipping" +else + printf "\n %sCreate 'cw' alias for %s?%s [Y/n] " "$C_BOLD" "$BINARY" "$C_RESET" + if ! read -r response < /dev/tty; then + echo + response=n + fi + case "$response" in + n|N|no|NO|No) + step "Skipped 'cw' alias setup" + ;; + *) + mkdir -p "$(dirname "$alias_rc")" + printf '\n# chatwoot CLI alias\n%s\n' "$alias_line" >> "$alias_rc" + ok "Added 'cw' alias to ${alias_rc} — restart your shell to enable" + ;; + esac +fi + print_next_steps