#!/bin/bash set -e # output colors (ANSI) RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' REPO_URL="https://github.com/bmf-san/ggc" INSTALL_DIR="$HOME/.local/bin" BINARY_NAME="ggc" print_info() { echo -e "${BLUE}[INFO]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } command_exists() { command -v "$1" >/dev/null 2>&1 } get_latest_version() { if command_exists curl; then curl -s "https://api.github.com/repos/bmf-san/ggc/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' elif command_exists wget; then wget -qO- "https://api.github.com/repos/bmf-san/ggc/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' else echo "" fi } detect_platform() { local os arch case "$(uname -s)" in Linux*) os="linux" ;; Darwin*) os="darwin" ;; CYGWIN*|MINGW*|MSYS*) os="windows" ;; *) os="unknown" ;; esac case "$(uname -m)" in x86_64|amd64) arch="amd64" ;; arm64|aarch64) arch="arm64" ;; armv7l) arch="arm" ;; i386|i686) arch="386" ;; *) arch="unknown" ;; esac echo "${os}_${arch}" } install_from_source() { print_info "Installing ggc from source (recommended for full version info)..." if ! command_exists go; then print_error "Go is not installed. Please install Go first." return 1 fi if ! command_exists git; then print_error "Git is not installed. Please install Git first." return 1 fi local temp_dir temp_dir=$(mktemp -d) print_info "Cloning repository to $temp_dir..." if ! git clone "$REPO_URL" "$temp_dir"; then print_error "Failed to clone repository" rm -rf "$temp_dir" return 1 fi cd "$temp_dir" print_info "Building ggc with full version information..." # Try to build with make first (preferred for version info) if [ -f "Makefile" ]; then print_info "Using Makefile for build (includes version information)..." if make build; then print_success "Built successfully with make" else print_warning "Make build failed, trying go build..." if ! go build -o ggc .; then print_error "Build failed" cd .. rm -rf "$temp_dir" return 1 fi fi else print_info "No Makefile found, using go build..." if ! go build -o ggc .; then print_error "Build failed" cd .. rm -rf "$temp_dir" return 1 fi fi # Create install directory mkdir -p "$INSTALL_DIR" # Move binary to install directory if ! mv ggc "$INSTALL_DIR/$BINARY_NAME"; then print_error "Failed to move binary to install directory" cd .. rm -rf "$temp_dir" return 1 fi chmod +x "$INSTALL_DIR/$BINARY_NAME" print_success "ggc installed successfully to $INSTALL_DIR/$BINARY_NAME" print_info "This installation includes full version and commit information" # Check if install directory is in PATH if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then print_warning "Install directory not in PATH. Adding it automatically..." add_to_path "$INSTALL_DIR" fi cd .. rm -rf "$temp_dir" return 0 } install_with_go() { print_warning "Installing ggc using 'go install' (fallback method)..." print_warning "Note: This method provides limited version information compared to source installation" print_warning "Version may show as development build." if ! command_exists go; then print_error "Go is not installed. Please install Go first." return 1 fi print_info "Running go install..." if ! go install github.com/bmf-san/ggc/v7@latest; then print_error "go install failed" return 1 fi local gobin gobin=$(go env GOBIN) if [ -z "$gobin" ]; then gobin="$(go env GOPATH)/bin" fi if [ -f "$gobin/ggc" ]; then print_success "ggc installed successfully to $gobin/ggc" print_warning "This installation has limited version information due to go install limitations" if ! echo "$PATH" | grep -q "$gobin"; then print_warning "Go bin directory not in PATH. Adding it automatically..." add_to_path "$gobin" fi return 0 else print_error "Installation failed - binary not found" return 1 fi } create_fish_completion() { local fish_completions_dir="$HOME/.config/fish/completions" local fish_completion_file="$fish_completions_dir/ggc.fish" # Create completions directory if it doesn't exist mkdir -p "$fish_completions_dir" # Create the fish completion loader cat > "$fish_completion_file" << 'EOF' # Fish completion loader for ggc function __ggc_load_completion # Try to find the ggc.fish completion file in go modules set -l gopath (go env GOPATH 2>/dev/null) if test -z "$gopath" return 1 end # Look for completion file in go modules for completion_file in "$gopath"/pkg/mod/github.com/bmf-san/ggc/v7@*/tools/completions/ggc.fish if test -f "$completion_file" source "$completion_file" return 0 end end # Fallback: find completion file set -l completion_file (find "$gopath/pkg/mod/github.com/bmf-san" -name "ggc.fish" -path "*/tools/completions/*" 2>/dev/null | head -1) if test -n "$completion_file"; and test -f "$completion_file" source "$completion_file" return 0 end return 1 end # Load completion if go is available if command -v go >/dev/null 2>&1 __ggc_load_completion end EOF print_success "Created fish completion loader at $fish_completion_file" } setup_shell_completion() { print_info "Setting up shell completion..." # better way to detect shell using basename local current_shell current_shell=$(basename "$SHELL" 2>/dev/null || echo "unknown") local bash_completion_line bash_completion_line=$(cat <<-'EOF' # ggc completion loader load_ggc_completion() { local gopath completion_file gopath=$(go env GOPATH 2>/dev/null) if [ -z "$gopath" ]; then return 1 fi for completion_file in "$gopath"/pkg/mod/github.com/bmf-san/ggc/v7@*/tools/completions/ggc.bash; do if [ -f "$completion_file" ]; then source "$completion_file" return 0 fi done completion_file=$(find "$gopath/pkg/mod/github.com/bmf-san" -name "ggc.bash" -path "*/tools/completions/*" 2>/dev/null | head -1) if [ -n "$completion_file" ] && [ -f "$completion_file" ]; then source "$completion_file" return 0 fi return 1 } # Load completion if go is available if command -v go >/dev/null 2>&1; then load_ggc_completion fi EOF ) local zsh_completion_line zsh_completion_line=$(cat <<-'EOF' # ggc completion loader for zsh load_ggc_completion() { local gopath completion_file gopath=$(go env GOPATH 2>/dev/null) if [ -z "$gopath" ]; then return 1 fi for completion_file in "$gopath"/pkg/mod/github.com/bmf-san/ggc/v7@*/tools/completions/ggc.zsh; do if [ -f "$completion_file" ]; then source "$completion_file" return 0 fi done completion_file=$(find "$gopath/pkg/mod/github.com/bmf-san" -name "ggc.zsh" -path "*/tools/completions/*" 2>/dev/null | head -1) if [ -n "$completion_file" ] && [ -f "$completion_file" ]; then source "$completion_file" return 0 fi return 1 } # Load completion if go is available if command -v go >/dev/null 2>&1; then load_ggc_completion fi EOF ) case "$current_shell" in bash) local bash_profile="$HOME/.bashrc" if [[ "$OSTYPE" == "darwin"* ]]; then # macOS typically uses ~/.bash_profile bash_profile="$HOME/.bash_profile" if [ ! -f "$bash_profile" ] && [ -f "$HOME/.bashrc" ]; then bash_profile="$HOME/.bashrc" fi fi if [ -f "$bash_profile" ]; then if ! grep -q "load_ggc_completion" "$bash_profile"; then echo "" >> "$bash_profile" echo "$bash_completion_line" >> "$bash_profile" print_success "Added ggc completion to $bash_profile" print_info "Restart your terminal or run 'source $bash_profile' to enable completion" else print_info "ggc completion already configured in $bash_profile" fi else print_warning "Could not find $bash_profile. Please add the following manually:" echo "$bash_completion_line" fi ;; zsh) local zsh_profile="$HOME/.zshrc" if [ -f "$zsh_profile" ]; then if ! grep -q "load_ggc_completion" "$zsh_profile"; then echo "" >> "$zsh_profile" echo "$zsh_completion_line" >> "$zsh_profile" print_success "Added ggc completion to $zsh_profile" print_info "Restart your terminal or run 'source $zsh_profile' to enable completion" else print_info "ggc completion already configured in $zsh_profile" fi else print_warning "Could not find $zsh_profile. Please add the following manually:" echo "$zsh_completion_line" fi ;; fish) print_info "Fish shell detected. Creating native fish completion..." create_fish_completion print_info "Fish completion installed. Restart your terminal or run 'fish' to enable completion" ;; *) print_info "Shell completion setup for $current_shell not automated." print_info "To enable shell completion, run this ggc command and add the output to your shell profile:" echo "ggc completion $current_shell" ;; esac } add_to_path() { local path_to_add="$1" local current_shell current_shell=$(basename "$SHELL" 2>/dev/null || echo "unknown") local path_line="export PATH=\$PATH:$path_to_add" case "$current_shell" in bash) local bash_profile="$HOME/.bashrc" if [[ "$OSTYPE" == "darwin"* ]]; then # macOS typically uses ~/.bash_profile bash_profile="$HOME/.bash_profile" if [ ! -f "$bash_profile" ] && [ -f "$HOME/.bashrc" ]; then bash_profile="$HOME/.bashrc" fi fi if [ -f "$bash_profile" ]; then if ! grep -q "PATH.*$path_to_add" "$bash_profile"; then { echo "" echo "# ggc PATH" echo "$path_line" } >> "$bash_profile" print_success "Added $path_to_add to PATH in $bash_profile" print_info "Restart your terminal or run 'source $bash_profile' to use ggc" else print_info "PATH already contains $path_to_add in $bash_profile" fi else print_warning "Could not find $bash_profile. Please add the following manually:" echo " $path_line" fi ;; zsh) local zsh_profile="$HOME/.zshrc" if [ -f "$zsh_profile" ]; then if ! grep -q "PATH.*$path_to_add" "$zsh_profile"; then { echo "" echo "# ggc PATH" echo "$path_line" } >> "$zsh_profile" print_success "Added $path_to_add to PATH in $zsh_profile" print_info "Restart your terminal or run 'source $zsh_profile' to use ggc" else print_info "PATH already contains $path_to_add in $zsh_profile" fi else print_warning "Could not find $zsh_profile. Please add the following manually:" echo " $path_line" fi ;; fish) local fish_config="$HOME/.config/fish/config.fish" local fish_path_line="set -gx PATH \$PATH $path_to_add" if [ -f "$fish_config" ]; then if ! grep -q "PATH.*$path_to_add" "$fish_config"; then { echo "" echo "# ggc PATH" echo "$fish_path_line" } >> "$fish_config" print_success "Added $path_to_add to PATH in $fish_config" print_info "Restart your terminal to use ggc" else print_info "PATH already contains $path_to_add in $fish_config" fi else print_warning "Could not find $fish_config. Please add the following manually:" echo " $fish_path_line" fi ;; *) print_warning "Automatic PATH setup for $current_shell not supported." print_info "Please add the following to your shell profile:" echo " $path_line" ;; esac } check_dependencies() { local missing_deps=() if ! command_exists go; then missing_deps+=("go") fi if ! command_exists git; then missing_deps+=("git") fi if [ ${#missing_deps[@]} -gt 0 ]; then print_error "Missing required dependencies: ${missing_deps[*]}" print_info "For source installation (recommended), you need both Go and Git" print_info "For fallback installation, you only need Go (but with limited version info)" return 1 fi return 0 } main() { echo "ggc Installation Script" echo "-----------------------" print_info "Installation directory: $INSTALL_DIR" installation_success=false # Check if we have the basic requirements if command_exists go && command_exists git; then print_info "✅ Go and Git detected - proceeding with source installation" print_info "This will provide full version and commit information" if install_from_source; then installation_success=true else print_warning "❌ Source installation failed" print_info "Falling back to 'go install' method..." if install_with_go; then installation_success=true fi fi elif command_exists go; then print_warning "⚠️ Git not found - source installation unavailable" print_info "Falling back to 'go install' method (limited version info)" if install_with_go; then installation_success=true fi else print_error "❌ Go is not installed" print_error "Please install Go first: https://golang.org/doc/install" print_info "For best results, also install Git for source installation" exit 1 fi if [ "$installation_success" = true ]; then echo "" print_success "✅ Installation completed successfully!" # Test the installation local installed_binary if [ -f "$INSTALL_DIR/$BINARY_NAME" ]; then installed_binary="$INSTALL_DIR/$BINARY_NAME" else local gobin gobin=$(go env GOBIN 2>/dev/null) if [ -z "$gobin" ]; then gobin="$(go env GOPATH)/bin" fi if [ -f "$gobin/ggc" ]; then installed_binary="$gobin/ggc" fi fi if [ -n "$installed_binary" ]; then print_info "Testing installation..." if "$installed_binary" version >/dev/null 2>&1; then print_success "✅ ggc is working correctly" else print_warning "⚠️ ggc installed but version command failed" fi fi print_info "Run 'ggc --help' or just 'ggc' to get started" echo "" setup_shell_completion else print_error "❌ Installation failed" print_info "Please check the error messages above and try again" exit 1 fi } main "$@"