diff --git a/.gitignore b/.gitignore index 66c267c..4c43963 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ .dotfiles/.zcompdump-* .dotfiles/.zsh_history +# LazyVim Docker configuration +.lazyvim-docker-config + # Backup files backups/ *.backup diff --git a/Makefile b/Makefile index df259c5..1eab486 100644 --- a/Makefile +++ b/Makefile @@ -172,19 +172,19 @@ install-remote: @echo "$(BLUE)LazyVim Docker - Remote Installation$(NC)" @echo "" @echo "To install LazyVim Docker remotely (recommended):" - @echo "$(GREEN)curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash$(NC)" + @echo "$(GREEN)curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash$(NC)" @echo "" @echo "This will:" @echo " • Download and install LazyVim Docker to ~/.local/share/lazyvim-docker" @echo " • Create global 'lazy' command" - @echo " • Build Docker environment" + @echo " • Build Docker environment with smart defaults" @echo " • No repository cloning required - everything is automated" remote-install: install-remote test-remote-scripts: @echo "$(BLUE)Testing remote installation scripts...$(NC)" - @bash -n scripts/remote-install.sh && echo "$(GREEN)✓ remote-install.sh syntax OK$(NC)" + @bash -n scripts/start.sh && echo "$(GREEN)✓ start.sh syntax OK$(NC)" @bash -n scripts/remote-uninstall.sh && echo "$(GREEN)✓ remote-uninstall.sh syntax OK$(NC)" @bash -n scripts/remote-update.sh && echo "$(GREEN)✓ remote-update.sh syntax OK$(NC)" @echo "$(GREEN)All remote scripts passed syntax check!$(NC)" diff --git a/README.md b/README.md index b631bff..6b99c93 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,15 @@ A professional Dockerized environment for LazyVim (advanced Neovim configuration ## 🚀 Quick Start ### 🌐 Remote Installation (Recommended) -Install directly without cloning the repository - no manual setup needed: +Install directly without cloning the repository - automatic setup with smart defaults: ```bash -# One-line installation -curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash +# One-line installation with automatic configuration +curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash # Then use from anywhere lazy enter # Enter LazyVim development environment +lazy configure # Customize your setup (optional) ``` ### 📦 Traditional Installation @@ -31,6 +32,19 @@ make build # Build the environment make enter # Enter the container ``` +### 🗑️ Uninstallation +Complete removal when you no longer need LazyVim Docker: + +```bash +# Interactive uninstall (asks for confirmation) +lazy uninstall + +# Or run directly +curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-uninstall.sh | bash +``` + +**Removes everything**: Docker containers, installation files, global commands, and shell configurations in one step. + --- ## ✨ Features @@ -83,11 +97,11 @@ make destroy # ⚠️ DANGEROUS: Removes everything LazyVim Docker provides three main remote scripts for easy management: ### 📥 Installation Script -**`remote-install.sh`** - Complete setup in one command +**`start.sh`** - Automatic setup with smart defaults ```bash -# Full installation with Docker build -curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash +# Full installation with automatic configuration +curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash ``` **What it does:** @@ -96,6 +110,7 @@ curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scrip - ✅ Creates global `lazy` command in `~/.local/bin` - ✅ Adds `~/.local/bin` to your PATH automatically - ✅ Builds Docker environment (may take a few minutes) +- ✅ Uses smart defaults for timezone and directories - ✅ Creates shell configuration backups ### 🔄 Update Script @@ -118,30 +133,37 @@ curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scrip - ✅ Optionally rebuilds Docker containers ### 🗑️ Uninstallation Script -**`remote-uninstall.sh`** - Complete cleanup +**`remote-uninstall.sh`** - Complete and safe cleanup ```bash -# Uninstall everything with prompts +# Interactive uninstall with confirmation prompt lazy uninstall -# Or run directly +# Or run directly with prompts curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-uninstall.sh | bash ``` -**What it does:** -- ✅ Stops and removes Docker containers/images -- ✅ Removes installation directory (`~/.local/share/lazyvim-docker`) +**What it does when you confirm:** +- ✅ Stops and removes all Docker containers and images +- ✅ Removes installation directory (`~/.local/share/lazyvim-docker`) - ✅ Removes global `lazy` command -- ✅ Optionally cleans PATH modifications from shell configs -- ✅ Creates backups before making changes -- ✅ Interactive prompts for safety +- ✅ Removes shell configuration entries (`.zshrc`, `.bashrc`, etc.) +- ✅ Removes PATH modifications automatically +- ✅ Creates timestamped backups before making changes +- ✅ **Everything is removed in one confirmation** - no additional prompts + +**Safety Features:** +- 🛡️ **Interactive confirmation** - Shows exactly what will be removed +- 🛡️ **Non-interactive safety** - Cancels by default when piped unless forced +- 🛡️ **Automatic backups** - Creates backups of modified configuration files +- 🛡️ **Clear messaging** - Shows progress and results of each step --- ## 🔬 Script Details & Technical Info -### 📥 remote-install.sh -**Purpose**: Complete LazyVim Docker setup without repository cloning +### 📥 start.sh +**Purpose**: Complete LazyVim Docker setup with automatic configuration **Requirements Check:** - Docker (with compose support) @@ -184,26 +206,27 @@ curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scrip - Backup created before update in `~/.local/share/lazyvim-docker-backup-[timestamp]` ### 🗑️ remote-uninstall.sh -**Purpose**: Complete removal of LazyVim Docker installation +**Purpose**: Complete and safe removal of LazyVim Docker installation **Removal Process:** -1. Stops all running containers -2. Removes Docker containers and images -3. Removes Docker volumes -4. Removes installation directory -5. Removes global `lazy` command -6. Optionally cleans PATH from shell configs -7. Creates backups before deletion - -**Interactive Prompts:** -- Confirm complete uninstall -- Choose to remove PATH modifications -- Option to keep or remove project files - -**Cleanup Scope:** -- Docker: containers, images, volumes -- Files: installation directory, global command -- Config: PATH modifications (optional) +1. Shows exactly what will be removed +2. **Single confirmation prompt** - no additional questions +3. Stops all running containers +4. Removes Docker containers, images, and volumes +5. Removes installation directory (`~/.local/share/lazyvim-docker`) +6. Removes global `lazy` command and shell integrations +7. Removes PATH modifications automatically +8. Creates timestamped backups before any changes + +**Smart Detection:** +- **Interactive mode**: Shows confirmation prompt when run manually +- **Automatic backup**: Creates `.backup.[timestamp]` files before modifying shell configs + +**Complete Cleanup:** +- ✅ Docker: containers, images, volumes +- ✅ Files: installation directory, global command +- ✅ Config: shell entries and PATH modifications +- ✅ **Everything removed in one confirmation** - streamlined process --- @@ -220,7 +243,7 @@ curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scrip ```bash # From your existing repo directory make destroy && cd .. && rm -rf lazyvim-docker -curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash +curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash ``` **From Remote to Traditional:** @@ -235,8 +258,8 @@ git clone https://github.com/manghidev/lazyvim-docker.git && cd lazyvim-docker & ### Remote Installation Workflow (Recommended) ```bash -# 1. Install once (5-10 minutes) -curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash +# 1. Install once (5-10 minutes) - automatic setup +curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash # 2. Daily usage from anywhere cd ~/Projects/my-project @@ -245,6 +268,7 @@ lazy enter # Start coding immediately # 3. Management commands lazy status # Check if running lazy stop # Stop when done +lazy configure # Customize setup (optional) lazy update # Update weekly/monthly ``` @@ -265,8 +289,6 @@ For detailed workflow and troubleshooting: **[📖 Container Lifecycle Guide](do --- -## 🔧 Advanced Configuration - ## 🔧 Configuration ### 🎯 Easy Configuration (Recommended) @@ -364,8 +386,8 @@ lazy build # Update to fix issues lazy update -# Nuclear option -lazy uninstall && curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash +# Nuclear option - complete reinstall +lazy uninstall && curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash ``` --- diff --git a/VERSION b/VERSION index f0bb29e..3a3cd8c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.0 +1.3.1 diff --git a/scripts/build.sh b/scripts/build.sh index 83923f3..c244b46 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -22,19 +22,19 @@ DOTFILES_DIR=".dotfiles" # Functions log_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } # Check if VERSION file exists diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 5c9dda4..07717ec 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -17,18 +17,18 @@ NC='\033[0m' # Validate bump type if [[ ! "$BUMP_TYPE" =~ ^(patch|minor|major)$ ]]; then - echo -e "${RED}Error: Invalid bump type. Use: patch, minor, or major${NC}" + printf "${RED}Error: Invalid bump type. Use: patch, minor, or major${NC}\n" exit 1 fi # Read current version if [[ ! -f "$VERSION_FILE" ]]; then - echo -e "${RED}Error: VERSION file not found${NC}" + printf "${RED}Error: VERSION file not found${NC}\n" exit 1 fi CURRENT_VERSION=$(cat "$VERSION_FILE") -echo -e "${BLUE}Current version: $CURRENT_VERSION${NC}" +printf "${BLUE}Current version: $CURRENT_VERSION${NC}\n" # Parse version components IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION" @@ -56,13 +56,13 @@ NEW_VERSION="$MAJOR.$MINOR.$PATCH" # Write new version echo "$NEW_VERSION" > "$VERSION_FILE" -echo -e "${GREEN}Version bumped to: $NEW_VERSION${NC}" +printf "${GREEN}Version bumped to: $NEW_VERSION${NC}\n" # Git commit if in a git repository if git rev-parse --git-dir > /dev/null 2>&1; then - echo -e "${YELLOW}Committing version bump...${NC}" + printf "${YELLOW}Committing version bump...${NC}\n" git add "$VERSION_FILE" git commit -m "Bump version to $NEW_VERSION" git tag "v$NEW_VERSION" - echo -e "${GREEN}Version committed and tagged${NC}" + printf "${GREEN}Version committed and tagged${NC}\n" fi diff --git a/scripts/check-timezone.sh b/scripts/check-timezone.sh index 1d5d217..b029572 100755 --- a/scripts/check-timezone.sh +++ b/scripts/check-timezone.sh @@ -12,24 +12,24 @@ NC='\033[0m' CONTAINER_NAME="lazyvim" -echo -e "${BLUE}Checking timezone configuration...${NC}" -echo "" +printf "${BLUE}Checking timezone configuration...${NC}\n" +printf "\n" if docker ps | grep -q "$CONTAINER_NAME"; then - echo -e "${GREEN}Container timezone information:${NC}" - echo "Current time in container:" + printf "${GREEN}Container timezone information:${NC}\n" + printf "Current time in container:\n" docker exec "$CONTAINER_NAME" date - echo "" - echo "Timezone file:" - docker exec "$CONTAINER_NAME" cat /etc/timezone 2>/dev/null || echo "Timezone file not found" - echo "" - echo "TZ environment variable:" - docker exec "$CONTAINER_NAME" env | grep TZ || echo "TZ variable not set" - echo "" - echo -e "${GREEN}Local system time for comparison:${NC}" + printf "\n" + printf "Timezone file:\n" + docker exec "$CONTAINER_NAME" cat /etc/timezone 2>/dev/null || printf "Timezone file not found\n" + printf "\n" + printf "TZ environment variable:\n" + docker exec "$CONTAINER_NAME" env | grep TZ || printf "TZ variable not set\n" + printf "\n" + printf "${GREEN}Local system time for comparison:${NC}\n" date else - echo "Container '$CONTAINER_NAME' is not running." - echo "Please start the container first with: make start" + printf "Container '%s' is not running.\n" "$CONTAINER_NAME" + printf "Please start the container first with: make start\n" exit 1 fi diff --git a/scripts/configure.sh b/scripts/configure.sh index ac5a6b6..5debaba 100755 --- a/scripts/configure.sh +++ b/scripts/configure.sh @@ -1,7 +1,12 @@ #!/bin/bash -# LazyVim Docker - Configuration Script -# This script helps reconfigure directories and timezone +# LazyVim Docker - Enhanced Configuration Script v2.0 +# Features: +# - Prevents duplicate directory mounts +# - Allows easy unmounting of directories from menu +# - Remembers user decisions (won't ask again for Documents if already configured) +# - Shows clear numbered list of mounted directories +# - Persistent preferences management set -e @@ -11,36 +16,308 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' +PURPLE='\033[0;35m' +GRAY='\033[0;37m' NC='\033[0m' +# Configuration file to store user preferences +CONFIG_FILE=".lazyvim-docker-config" + # Functions log_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}ℹ️ ${NC} %s\n" "$1" } log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}✅ ${NC} %s\n" "$1" } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}⚠️ ${NC} %s\n" "$1" } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}❌ ${NC} %s\n" "$1" +} + +log_step() { + printf "${PURPLE}🔧 ${NC} %s\n" "$1" } print_header() { - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║ LazyVim Docker - Configuration ║${NC}" - echo -e "${CYAN}║ Reconfigure Directories & Timezone ║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" + printf "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}\n" + printf "${CYAN}║ LazyVim Docker - Smart Configuration Tool ║${NC}\n" + printf "${CYAN}║ Improved Directory & Timezone Manager v2.0 ║${NC}\n" + printf "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}\n" + printf "\n" +} + +# Load user preferences +load_config() { + if [[ -f "$CONFIG_FILE" ]]; then + source "$CONFIG_FILE" + log_info "Loaded previous configuration" + else + log_info "First time configuration" + fi +} + +# Save user preferences +save_config() { + cat > "$CONFIG_FILE" << EOF +# LazyVim Docker Configuration - Auto-generated +# Last updated: $(date) +DOCUMENTS_DECISION="${DOCUMENTS_DECISION:-}" +PROJECTS_DECISION="${PROJECTS_DECISION:-}" +PROJECTS_PATH="${PROJECTS_PATH:-}" +LAST_TIMEZONE="${LAST_TIMEZONE:-}" +EOF + log_info "Configuration saved to $CONFIG_FILE" } -# Configure timezone +# Check if a directory mount already exists in docker-compose.yml +is_mount_exists() { + local host_path="$1" + + # Normalize path for comparison (resolve $HOME, relative paths, etc.) + local normalized_path="$host_path" + if [[ "$host_path" =~ ^\$HOME ]]; then + normalized_path="${host_path/\$HOME/$HOME}" + fi + + # Check if mount exists in volumes section (non-commented line) + local in_volumes_section=false + while IFS= read -r line; do + # Check if we're entering volumes section + if [[ "$line" =~ ^[[:space:]]*volumes:[[:space:]]*$ ]]; then + in_volumes_section=true + continue + fi + + # Check if we're leaving volumes section (next main section) + if [[ "$in_volumes_section" == "true" ]] && [[ "$line" =~ ^[[:space:]]*[a-zA-Z_-]+:[[:space:]]*$ ]] && [[ ! "$line" =~ volumes: ]]; then + in_volumes_section=false + continue + fi + + # Check for mount within volumes section (non-commented) + if [[ "$in_volumes_section" == "true" ]] && [[ ! "$line" =~ ^[[:space:]]*# ]] && \ + ([[ "$line" =~ "$host_path:" ]] || [[ "$line" =~ "$normalized_path:" ]]); then + return 0 # Mount exists + fi + done < docker-compose.yml + + return 1 # Mount doesn't exist +} + +# Get all current mounts in a structured way +get_current_mounts() { + local show_numbers="${1:-false}" + local counter=1 + local mounts_found=false + local mounts_data=() + + printf "${CYAN}📁 Current Directory Mounts:${NC}\n" + printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + + # Parse docker-compose.yml for volume mounts - look in volumes section + local in_volumes_section=false + while IFS= read -r line; do + # Check if we're entering volumes section + if [[ "$line" =~ ^[[:space:]]*volumes:[[:space:]]*$ ]]; then + in_volumes_section=true + continue + fi + + # Check if we're leaving volumes section (next main section) + if [[ "$in_volumes_section" == "true" ]] && [[ "$line" =~ ^[[:space:]]*[a-zA-Z_-]+:[[:space:]]*$ ]] && [[ ! "$line" =~ volumes: ]]; then + in_volumes_section=false + continue + fi + + # Process volume mounts only within volumes section + if [[ "$in_volumes_section" == "true" ]] && [[ "$line" =~ ^[[:space:]]*-[[:space:]]+([^:]+):([^:]+)$ ]]; then + local host_path="${BASH_REMATCH[1]}" + local container_path="${BASH_REMATCH[2]}" + + # Skip ONLY system caches and configs, NOT user dotfiles + if [[ "$container_path" =~ (/root/\.cache|/home/developer/\.cache|/tmp|cache|\.npm|\.pip|\.yarn) ]]; then + continue + fi + + # Expand environment variables for display + local display_host_path="$host_path" + if [[ "$host_path" =~ ^\$HOME ]]; then + display_host_path="${host_path/\$HOME/$HOME}" + fi + + # Store mount data for potential removal + mounts_data+=("$host_path:$container_path") + + # Show numbered list if requested + if [[ "$show_numbers" == "true" ]]; then + printf "${YELLOW}%2d.${NC} " "$counter" + else + printf " ${PURPLE}•${NC} " + fi + + printf "${GREEN}Host:${NC} %s\n" "$display_host_path" + printf " ${CYAN}→${NC} Container: %s\n" "$container_path" + + # Check if directory or file exists + if [[ -e "$display_host_path" ]]; then + if [[ -d "$display_host_path" ]]; then + printf " ${BLUE}Status:${NC} ${GREEN}✅ Directory Exists${NC}\n" + elif [[ -f "$display_host_path" ]]; then + printf " ${BLUE}Status:${NC} ${GREEN}✅ File Exists${NC}\n" + else + printf " ${BLUE}Status:${NC} ${GREEN}✅ Exists${NC}\n" + fi + else + # For dotfiles that are created by the container, provide helpful info + if [[ "$display_host_path" =~ \.dotfiles/\.(zshrc|p10k\.zsh)$ ]]; then + printf " ${BLUE}Status:${NC} ${YELLOW}⚡ Will be auto-created on first run${NC}\n" + elif [[ "$display_host_path" =~ \.dotfiles/\.config/(nvim|lazygit)$ ]]; then + printf " ${BLUE}Status:${NC} ${YELLOW}⚡ Will be auto-created with configs${NC}\n" + else + printf " ${BLUE}Status:${NC} ${RED}❌ Missing${NC}\n" + fi + fi + printf "\n" + + counter=$((counter + 1)) + mounts_found=true + fi + done < docker-compose.yml + + if [[ "$mounts_found" != "true" ]]; then + printf " ${GRAY}No custom directory mounts configured${NC}\n" + printf "\n" + fi + + printf "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" + + # Export mounts data for removal function + export CURRENT_MOUNTS_DATA="${mounts_data[*]}" + + # Return 0 always to avoid script termination + echo "$((counter - 1))" > /tmp/mount_count + return 0 +} + +# Add a directory mount (prevents duplicates) +add_directory_mount() { + local host_path="$1" + local container_path="$2" + + # Check if mount already exists + if is_mount_exists "$host_path"; then + log_warning "Mount already exists: $host_path" + return 1 + fi + + # Check if directory exists + if [[ ! -d "$host_path" ]]; then + log_error "Directory does not exist: $host_path" + return 1 + fi + + # Add mount after the Documents line or at the appropriate place in volumes section + if grep -q "Documents:" docker-compose.yml; then + # Add after Documents line with proper formatting + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/\$HOME\/Documents:/a\\ + - $host_path:$container_path\\ +" docker-compose.yml + else + sed -i "/\$HOME\/Documents:/a\\ + - $host_path:$container_path" docker-compose.yml + fi + else + # Find the end of mount directories section and add there + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/# - \$HOME\/Documents:/a\\ + - $host_path:$container_path\\ +" docker-compose.yml + else + sed -i "/# - \$HOME\/Documents:/a\\ + - $host_path:$container_path" docker-compose.yml + fi + fi + + log_success "Added mount: $host_path → $container_path" + return 0 +} + +# Remove a directory mount by line number +remove_directory_mount() { + local selection="$1" + + # Get current mounts data directly + local mounts_data=() + local counter=1 + + # Parse docker-compose.yml for volume mounts - look in volumes section + local in_volumes_section=false + while IFS= read -r line; do + # Check if we're entering volumes section + if [[ "$line" =~ ^[[:space:]]*volumes:[[:space:]]*$ ]]; then + in_volumes_section=true + continue + fi + + # Check if we're leaving volumes section (next main section) + if [[ "$in_volumes_section" == "true" ]] && [[ "$line" =~ ^[[:space:]]*[a-zA-Z_-]+:[[:space:]]*$ ]] && [[ ! "$line" =~ volumes: ]]; then + in_volumes_section=false + continue + fi + + # Process volume mounts only within volumes section + if [[ "$in_volumes_section" == "true" ]] && [[ "$line" =~ ^[[:space:]]*-[[:space:]]+([^:]+):([^:]+)$ ]]; then + local host_path="${BASH_REMATCH[1]}" + local container_path="${BASH_REMATCH[2]}" + + # Skip ONLY system caches and configs, NOT user dotfiles + if [[ "$container_path" =~ (/root/\.cache|/home/developer/\.cache|/tmp|cache|\.npm|\.pip|\.yarn) ]]; then + continue + fi + + # Store mount data for potential removal + mounts_data+=("$host_path:$container_path") + counter=$((counter + 1)) + fi + done < docker-compose.yml + + if [[ ${#mounts_data[@]} -eq 0 ]]; then + log_warning "No mounts available to remove" + return 1 + fi + + # Validate selection + if [[ ! "$selection" =~ ^[0-9]+$ ]] || [[ "$selection" -lt 1 ]] || [[ "$selection" -gt "${#mounts_data[@]}" ]]; then + log_error "Invalid selection: $selection" + return 1 + fi + + # Get the mount to remove (1-indexed to 0-indexed) + local mount_to_remove="${mounts_data[$((selection - 1))]}" + local host_path="${mount_to_remove%:*}" + local container_path="${mount_to_remove#*:}" + + # Remove the mount line from docker-compose.yml + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "\|^[[:space:]]*- $host_path:$container_path|d" docker-compose.yml + else + sed -i "\|^[[:space:]]*- $host_path:$container_path|d" docker-compose.yml + fi + + log_success "Removed mount: $host_path → $container_path" + return 0 +} + +# Configure timezone with memory configure_timezone() { - log_info "Configuring timezone..." + log_step "Configuring timezone..." # Detect system timezone local system_tz="" @@ -53,258 +330,366 @@ configure_timezone() { fi # Get current timezone from docker-compose.yml - local current_tz=$(grep "TIMEZONE:" docker-compose.yml | awk '{print $2}' || echo "") - - # Default timezone if detection fails - local default_tz="${system_tz:-${current_tz:-America/Mexico_City}}" - - echo "Current system timezone: ${system_tz:-"Could not detect"}" - echo "Current container timezone: ${current_tz:-"Not set"}" - echo "" - echo "Available timezone examples:" - echo " - America/New_York (EST/EDT)" - echo " - America/Los_Angeles (PST/PDT)" - echo " - America/Chicago (CST/CDT)" - echo " - America/Mexico_City (CST/CDT)" - echo " - Europe/London (GMT/BST)" - echo " - Europe/Madrid (CET/CEST)" - echo " - Europe/Paris (CET/CEST)" - echo " - Asia/Tokyo (JST)" - echo " - Asia/Shanghai (CST)" - echo "" - - read -p "Enter your timezone [$default_tz]: " user_tz - user_tz=${user_tz:-$default_tz} - - # Update timezone in docker-compose.yml + local current_tz=$(grep "TIMEZONE:" docker-compose.yml | awk '{print $2}' 2>/dev/null || echo "") + local default_tz="${system_tz:-America/Mexico_City}" + + printf "🌍 Timezone Configuration:\n" + printf " Current in container: %s\n" "${current_tz:-"Not set"}" + printf " System timezone: %s\n" "${system_tz:-"Could not detect"}" + printf "\n" + + # If we have a previous timezone decision and it matches current, skip + if [[ -n "$LAST_TIMEZONE" ]] && [[ "$LAST_TIMEZONE" == "$current_tz" ]]; then + log_info "Timezone already configured: $current_tz" + return 0 + fi + + printf "Available timezone examples:\n" + printf " - America/New_York\n" + printf " - America/Los_Angeles\n" + printf " - America/Mexico_City\n" + printf " - Europe/London\n" + printf " - Europe/Madrid\n" + printf " - Asia/Tokyo\n" + printf "\n" + + read -p "Enter timezone [$default_tz]: " timezone + timezone=${timezone:-$default_tz} + + # Update docker-compose.yml if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "s/TIMEZONE: .*/TIMEZONE: $user_tz/" docker-compose.yml - sed -i '' "s/TZ=.*/TZ=$user_tz/" docker-compose.yml + sed -i '' "s|TIMEZONE:.*|TIMEZONE: $timezone|" docker-compose.yml else - sed -i "s/TIMEZONE: .*/TIMEZONE: $user_tz/" docker-compose.yml - sed -i "s/TZ=.*/TZ=$user_tz/" docker-compose.yml + sed -i "s|TIMEZONE:.*|TIMEZONE: $timezone|" docker-compose.yml fi - log_success "Timezone configured: $user_tz" + LAST_TIMEZONE="$timezone" + log_success "Timezone set to: $timezone" } -# Configure directories -configure_directories() { - log_info "Configuring directories to mount..." - - # Detect OS - local os_type="" +# Configure Documents directory with smart state +configure_documents_directory() { local default_docs="$HOME/Documents" - local default_projects="" - if [[ "$OSTYPE" == "darwin"* ]]; then - os_type="macOS" - default_projects="$HOME/Developer" - else - os_type="Linux" - default_projects="$HOME/Projects" + printf "📄 Documents Directory Configuration:\n" + + # Check if Documents directory exists + if [[ ! -d "$default_docs" ]]; then + log_warning "Documents directory not found: $default_docs" + return 0 fi - echo "Detected OS: $os_type" - echo "The container will mount directories so you can access your files inside the development environment." - echo "" - - # Show current mounts - echo "Current volume mounts in docker-compose.yml:" - grep -E "^\s*-\s+.*:.*$" docker-compose.yml | grep -v "cache\|npm\|pip" | sed 's/^/ /' - echo "" - - # Configure Documents directory - echo "📁 Documents Directory:" - if [[ -d "$default_docs" ]]; then - read -p "Mount Documents directory ($default_docs)? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - # Ensure Documents is enabled + # Check current state in docker-compose.yml + local is_enabled=$(grep -v "^[[:space:]]*#" docker-compose.yml | grep -q "\$HOME/Documents:" && printf "yes" || printf "no") + + # If we have a previous decision and current state matches, skip asking + if [[ -n "$DOCUMENTS_DECISION" ]]; then + if [[ "$DOCUMENTS_DECISION" == "yes" ]] && [[ "$is_enabled" == "yes" ]]; then + log_info "Documents directory already enabled: $default_docs" + return 0 + elif [[ "$DOCUMENTS_DECISION" == "no" ]] && [[ "$is_enabled" == "no" ]]; then + log_info "Documents directory already disabled (user preference)" + return 0 + fi + fi + + printf " Path: %s\n" "$default_docs" + printf " Status: %s\n" "$([ "$is_enabled" == "yes" ] && printf "✅ Enabled" || printf "❌ Disabled")" + printf "\n" + + local reply + read -p "Mount Documents directory? [Y/n]: " reply + + case "$reply" in + [nN][oO]|[nN]) + # Disable Documents mounting if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' 's|^ # - \$HOME/Documents:| - \$HOME/Documents:|' docker-compose.yml + sed -i '' 's|^[[:space:]]*- \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml else - sed -i 's|^ # - \$HOME/Documents:| - \$HOME/Documents:|' docker-compose.yml + sed -i 's|^[[:space:]]*- \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml fi - log_info "Documents directory will be mounted at /home/developer/Documents" - else - # Comment out the Documents line + DOCUMENTS_DECISION="no" + log_success "Documents directory mounting disabled" + ;; + *) + # Enable Documents mounting if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' 's|^ - \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml + sed -i '' 's|^[[:space:]]*#[[:space:]]*- \$HOME/Documents:| - \$HOME/Documents:|' docker-compose.yml else - sed -i 's|^ - \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml + sed -i 's|^[[:space:]]*#[[:space:]]*- \$HOME/Documents:| - \$HOME/Documents:|' docker-compose.yml fi - log_info "Documents directory mounting disabled" - fi + DOCUMENTS_DECISION="yes" + log_success "Documents directory mounting enabled" + ;; + esac +} + +# Configure Projects directory with smart state +configure_projects_directory() { + local default_projects="" + + if [[ "$OSTYPE" == "darwin"* ]]; then + default_projects="$HOME/Developer" + else + default_projects="$HOME/Projects" fi - # Configure Projects directory - echo "" - echo "💻 Projects Directory:" - local has_projects=$(grep -c "Projects:/home/developer/Projects" docker-compose.yml || echo "0") - - if [[ $has_projects -gt 0 ]]; then - local current_projects=$(grep "Projects:/home/developer/Projects" docker-compose.yml | sed 's/.*- //' | sed 's/:.*//') - echo "Current Projects directory: $current_projects" - read -p "Keep current Projects directory? (Y/n): " -n 1 -r - echo - if [[ $REPLY =~ ^[Nn]$ ]]; then - # Remove current projects line - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' '/Projects:\/home\/developer\/Projects/d' docker-compose.yml - else - sed -i '/Projects:\/home\/developer\/Projects/d' docker-compose.yml - fi - has_projects=0 + printf "\n" + printf "💻 Projects Directory Configuration:\n" + + # Get current Projects mount if exists + local current_projects=$(grep -v "^[[:space:]]*#" docker-compose.yml | grep "Projects:/home/developer/Projects" | sed 's/.*- //' | sed 's/:.*//' || printf "") + + # If we have a previous decision and current state matches, skip asking + if [[ -n "$PROJECTS_DECISION" ]]; then + if [[ "$PROJECTS_DECISION" == "yes" ]] && [[ -n "$current_projects" ]]; then + log_info "Projects directory already configured: $current_projects" + return 0 + elif [[ "$PROJECTS_DECISION" == "no" ]] && [[ -z "$current_projects" ]]; then + log_info "Projects directory already disabled (user preference)" + return 0 fi fi - if [[ $has_projects -eq 0 ]]; then - read -p "Do you want to mount a Projects directory? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - read -p "Enter path to your projects directory [$default_projects]: " projects_dir - projects_dir=${projects_dir:-$default_projects} - - if [[ -d "$projects_dir" ]]; then - # Add projects directory to docker-compose.yml after Documents line + if [[ -n "$current_projects" ]]; then + printf " Current: %s\n" "$current_projects" + printf " Status: ✅ Enabled\n" + else + printf " Default: %s\n" "$default_projects" + printf " Status: ❌ Not configured\n" + fi + printf "\n" + + local reply + read -p "Mount Projects directory? [Y/n]: " reply + + case "$reply" in + [nN][oO]|[nN]) + # Remove Projects mounting + if [[ -n "$current_projects" ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "/\$HOME\/Documents:/a\\ - - $projects_dir:/home/developer/Projects" docker-compose.yml + sed -i '' "\|$current_projects.*Projects|d" docker-compose.yml else - sed -i "/\$HOME\/Documents:/a\\ - - $projects_dir:/home/developer/Projects" docker-compose.yml + sed -i "\|$current_projects.*Projects|d" docker-compose.yml fi - log_success "Projects directory added: $projects_dir -> /home/developer/Projects" + log_success "Projects directory mounting removed" + fi + PROJECTS_DECISION="no" + ;; + *) + local projects_path + if [[ -n "$current_projects" ]]; then + read -p "Projects directory path [$current_projects]: " projects_path + projects_path=${projects_path:-$current_projects} else - log_warning "Directory $projects_dir does not exist, you can create it and rebuild later" + read -p "Projects directory path [$default_projects]: " projects_path + projects_path=${projects_path:-$default_projects} fi - fi - fi + + if [[ -d "$projects_path" ]]; then + # Remove existing Projects mount first + if [[ -n "$current_projects" ]]; then + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "\|$current_projects.*Projects|d" docker-compose.yml + else + sed -i "\|$current_projects.*Projects|d" docker-compose.yml + fi + fi + + # Add new Projects mount + add_directory_mount "$projects_path" "/home/developer/Projects" + + PROJECTS_DECISION="yes" + PROJECTS_PATH="$projects_path" + log_success "Projects directory configured: $projects_path" + else + log_error "Directory does not exist: $projects_path" + PROJECTS_DECISION="no" + fi + ;; + esac +} + +# Interactive menu for additional directories +configure_additional_directories() { + printf "\n" + printf "📂 Additional Directory Management:\n" + printf "\n" - # Configure additional directories - echo "" - echo "📂 Additional Directories:" - read -p "Do you want to add/modify additional directories? (y/N): " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "" - echo "Options:" - echo " 1. Add a new directory" - echo " 2. Remove a directory mount" - echo " 3. Done" - echo "" + while true; do + printf "Choose an option:\n" + printf " ${GREEN}1.${NC} Add custom directory mount\n" + printf " ${YELLOW}2.${NC} Remove directory mount\n" + printf " ${BLUE}3.${NC} List current mounts\n" + printf " ${PURPLE}4.${NC} Add multiple directories at once\n" + printf " ${RED}5.${NC} Continue with configuration\n" + printf "\n" - while true; do - read -p "Select option (1-3): " -n 1 -r - echo - case $REPLY in - 1) - read -p "Enter directory path to mount: " custom_dir - if [[ -d "$custom_dir" ]]; then - local mount_name=$(basename "$custom_dir") - read -p "Mount as [/home/developer/$mount_name]: " container_path - container_path=${container_path:-"/home/developer/$mount_name"} - - # Add custom directory to docker-compose.yml - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "/\$HOME\/Documents:/a\\ - - $custom_dir:$container_path" docker-compose.yml - else - sed -i "/\$HOME\/Documents:/a\\ - - $custom_dir:$container_path" docker-compose.yml - fi - log_success "Added: $custom_dir -> $container_path" - else - log_warning "Directory $custom_dir does not exist" + read -p "Select option (1-5): " choice + printf "\n" + + case "$choice" in + 1) + read -p "Enter directory path to mount: " custom_dir + if [[ -z "$custom_dir" ]]; then + log_warning "No directory specified" + continue + fi + + # Expand ~ to $HOME + if [[ "$custom_dir" =~ ^~ ]]; then + custom_dir="${custom_dir/#\~/$HOME}" + fi + + if [[ ! -d "$custom_dir" ]]; then + log_error "Directory does not exist: $custom_dir" + continue + fi + + local mount_name=$(basename "$custom_dir") + read -p "Mount as [/home/developer/$mount_name]: " container_path + container_path=${container_path:-"/home/developer/$mount_name"} + + if add_directory_mount "$custom_dir" "$container_path"; then + printf "\n" + log_success "Mount added successfully!" + else + printf "\n" + log_error "Failed to add mount" + fi + ;; + 2) + printf "Select directory mount to remove:\n" + printf "\n" + + # Get and show numbered list + get_current_mounts "true" + local mount_count=$(cat /tmp/mount_count 2>/dev/null || echo "0") + + if [[ "$mount_count" -eq 0 ]]; then + printf "\n" + log_warning "No mounts available to remove" + continue + fi + + printf "\n" + read -p "Enter number to remove (or 'cancel'): " selection + + if [[ "$selection" == "cancel" ]] || [[ "$selection" == "c" ]]; then + log_info "Removal cancelled" + continue + fi + + if remove_directory_mount "$selection"; then + printf "\n" + log_success "Mount removed successfully!" + else + printf "\n" + log_error "Failed to remove mount" + fi + ;; + 3) + get_current_mounts "false" + ;; + 4) + printf "Enter multiple directories (one per line, empty line to finish):\n" + local dirs_to_add=() + while true; do + read -p "Directory path: " dir_path + if [[ -z "$dir_path" ]]; then + break fi - ;; - 2) - echo "Current custom mounts (excluding system directories):" - grep -E "^\s*-\s+.*:.*$" docker-compose.yml | grep -v -E "(cache|npm|pip|Documents|\.dotfiles)" | nl - read -p "Enter line number to remove (or 'cancel'): " line_num - if [[ "$line_num" =~ ^[0-9]+$ ]]; then - # This is complex, let's just show instructions - log_info "Please manually edit docker-compose.yml to remove unwanted mounts" + + # Expand ~ to $HOME + if [[ "$dir_path" =~ ^~ ]]; then + dir_path="${dir_path/#\~/$HOME}" fi - ;; - 3) - break - ;; - *) - echo "Invalid option. Please select 1, 2, or 3." - ;; - esac - echo "" - done - fi - - log_success "Directory configuration completed" + + if [[ -d "$dir_path" ]]; then + dirs_to_add+=("$dir_path") + printf " ${GREEN}✓${NC} Added to queue: $dir_path\n" + else + printf " ${RED}✗${NC} Directory not found: $dir_path\n" + fi + done + + if [[ ${#dirs_to_add[@]} -gt 0 ]]; then + printf "\nAdding ${#dirs_to_add[@]} directories...\n" + for dir in "${dirs_to_add[@]}"; do + local mount_name=$(basename "$dir") + local container_path="/home/developer/$mount_name" + if add_directory_mount "$dir" "$container_path"; then + log_success "Added: $dir → $container_path" + else + log_error "Failed to add: $dir" + fi + done + printf "\n" + log_success "Batch addition completed!" + else + log_info "No directories were added" + fi + ;; + 5) + break + ;; + *) + log_warning "Invalid option. Please select 1-5." + ;; + esac + printf "\n" + done } -# Main function +# Main configuration flow main() { print_header - # Check if we're in the right directory - if [[ ! -f "docker-compose.yml" ]]; then - log_error "This script must be run from the lazyvim-docker directory" - echo "If you installed remotely, use: lazy configure" - exit 1 - fi + # Load previous configuration + load_config - log_info "This will help you reconfigure your LazyVim Docker environment." - echo "" - - # Show current configuration - local current_tz=$(grep "TIMEZONE:" docker-compose.yml | awk '{print $2}' || echo "Not set") - echo "Current Configuration:" - echo " Timezone: $current_tz" - echo " Container: $(docker ps -q -f name=lazyvim >/dev/null 2>&1 && echo "Running" || echo "Stopped")" - echo "" - - # Ask what to configure - echo "What would you like to configure?" - echo " 1. Timezone only" - echo " 2. Directory mounts only" - echo " 3. Both timezone and directories" - echo " 4. Exit" - echo "" - - read -p "Select option (1-4): " -n 1 -r - echo - case $REPLY in - 1) - configure_timezone - ;; - 2) - configure_directories - ;; - 3) - configure_timezone - echo "" - configure_directories - ;; - 4) - log_info "Configuration cancelled" - exit 0 - ;; - *) - log_error "Invalid option selected" - exit 1 - ;; - esac + log_step "Starting LazyVim Docker configuration..." + printf "\n" + + # Configure timezone + configure_timezone + printf "\n" + + # Configure directories + log_step "Configuring directory mounts..." + printf "\n" + + # Configure Documents directory (with memory) + configure_documents_directory - echo "" + # Configure Projects directory (with memory) + configure_projects_directory + + # Configure additional directories (interactive menu) + configure_additional_directories + + # Save configuration + save_config + + printf "\n" log_success "Configuration completed!" - echo "" - echo "Next steps:" - echo " 1. Rebuild container: make build" - echo " 2. Or restart if already built: make restart" - echo " 3. Enter container: make enter" - echo "" - echo "Changes will take effect after rebuilding/restarting the container." + printf "\n" + printf "Next steps:\n" + printf " ${CYAN}1.${NC} Run: ${GREEN}make build${NC} or ${GREEN}lazy build${NC} to rebuild the container\n" + printf " ${CYAN}2.${NC} Run: ${GREEN}make start${NC} or ${GREEN}lazy start${NC} to start LazyVim\n" + printf "\n" + printf "Your mounted directories will be available inside the container at:\n" + get_current_mounts "false" + printf "\n" + + # Clean up temp files + rm -f /tmp/mount_count + + # Exit successfully + exit 0 } -# Run main function -main "$@" +# Run main function only if script is executed directly (not sourced) +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/scripts/destroy.sh b/scripts/destroy.sh index 298a1d4..9ed44e5 100755 --- a/scripts/destroy.sh +++ b/scripts/destroy.sh @@ -20,19 +20,19 @@ CONTAINER_NAME="lazyvim" # Functions log_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } # Confirmation prompt diff --git a/scripts/health-check.sh b/scripts/health-check.sh index 507aaa9..07ab90b 100755 --- a/scripts/health-check.sh +++ b/scripts/health-check.sh @@ -17,30 +17,30 @@ CONTAINER_NAME="lazyvim" # Functions log_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } print_header() { - echo -e "${BLUE}=== LazyVim Docker Health Check ===${NC}" - echo "" + printf "${BLUE}=== LazyVim Docker Health Check ===${NC}\n" + printf "\n" } print_separator() { - echo "" - echo "-----------------------------------" - echo "" + printf "\n" + printf -- "-----------------------------------\n" + printf "\n" } # Main health check function @@ -52,7 +52,7 @@ health_check() { if docker info >/dev/null 2>&1; then log_success "Docker is running" DOCKER_VERSION=$(docker --version) - echo " Version: $DOCKER_VERSION" + printf " Version: %s\n" "$DOCKER_VERSION" else log_error "Docker is not running or not installed" return 1 @@ -65,7 +65,7 @@ health_check() { if docker compose version >/dev/null 2>&1; then log_success "Docker Compose is available" COMPOSE_VERSION=$(docker compose version --short) - echo " Version: $COMPOSE_VERSION" + printf " Version: %s\n" "$COMPOSE_VERSION" else log_error "Docker Compose is not available" return 1 @@ -79,7 +79,7 @@ health_check() { if [ "$CONTAINER_STATE" = "missing" ]; then log_warning "Container does not exist" - echo " Use 'make build' to create it" + printf " Use 'make build' to create it\n" elif [ "$CONTAINER_STATE" = "running" ]; then log_success "Container is running" @@ -87,8 +87,8 @@ health_check() { log_info "Checking container health..." CONTAINER_HEALTH=$(docker inspect "$CONTAINER_NAME" --format='{{.State.Health.Status}}' 2>/dev/null || echo "No health check") - echo " Status: $CONTAINER_STATE" - echo " Health: $CONTAINER_HEALTH" + printf " Status: %s\n" "$CONTAINER_STATE" + printf " Health: %s\n" "$CONTAINER_HEALTH" # Check if we can execute commands in the container if docker exec "$CONTAINER_NAME" echo "Container accessible" >/dev/null 2>&1; then @@ -98,7 +98,7 @@ health_check() { fi else log_warning "Container exists but is stopped ($CONTAINER_STATE)" - echo " Use 'make start' to start it" + printf " Use 'make start' to start it\n" fi print_separator @@ -124,14 +124,14 @@ health_check() { DOTFILES=(".dotfiles/.zshrc" ".dotfiles/.p10k.zsh" ".dotfiles/.config/nvim" ".dotfiles/.config/lazygit") for file in "${DOTFILES[@]}"; do if [[ -e "$file" ]]; then - echo " ✓ $file" + printf " ✓ %s\n" "$file" else log_warning "Missing: $file" fi done else log_warning "Dotfiles directory does not exist" - echo " It will be created automatically when you build the environment" + printf " It will be created automatically when you build the environment\n" fi print_separator @@ -154,13 +154,13 @@ health_check() { if [ "$FINAL_CONTAINER_STATE" = "running" ]; then log_success "Environment is ready to use!" - echo " Use 'make enter' to access the container" + printf " Use 'make enter' to access the container\n" elif [ "$FINAL_CONTAINER_STATE" = "missing" ]; then log_info "Environment is not built" - echo " Use 'make build' to create the container" + printf " Use 'make build' to create the container\n" else log_info "Environment is not running" - echo " Use 'make start' to start the existing container" + printf " Use 'make start' to start the existing container\n" fi } diff --git a/scripts/init.sh b/scripts/init.sh index 373d506..ac11264 100755 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -20,19 +20,19 @@ CONTAINER_NAME="lazyvim" # Functions log_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } # Check if Docker is running diff --git a/scripts/install-global-commands.sh b/scripts/install-global-commands.sh old mode 100755 new mode 100644 index 933bad9..0be3965 --- a/scripts/install-global-commands.sh +++ b/scripts/install-global-commands.sh @@ -14,23 +14,25 @@ NC='\033[0m' # Functions log_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } # Get the absolute path of the lazyvim-docker directory LAZYVIM_DOCKER_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Remove the /scripts part from the path +LAZYVIM_DOCKER_PATH="$(dirname "$LAZYVIM_DOCKER_PATH")" log_info "LazyVim Docker Global Commands Installer" echo "" @@ -46,8 +48,8 @@ echo " lazy uninstall -> Complete uninstall" echo "" # Check if we're in the correct directory -if [[ ! -f "Makefile" ]] || [[ ! -f "docker-compose.yml" ]]; then - log_error "This script must be run from the lazyvim-docker directory" +if [[ ! -f "$LAZYVIM_DOCKER_PATH/Makefile" ]] || [[ ! -f "$LAZYVIM_DOCKER_PATH/docker-compose.yml" ]]; then + log_error "LazyVim Docker project not found at: $LAZYVIM_DOCKER_PATH" exit 1 fi @@ -59,8 +61,12 @@ install_zsh() { # Remove existing installation if present if grep -q "$marker_start" "$shell_config" 2>/dev/null; then - log_info "Removing existing installation..." - sed -i.bak "/$marker_start/,/$marker_end/d" "$shell_config" + log_info "Removing existing installation from Zsh..." + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/$marker_start/,/$marker_end/d" "$shell_config" + else + sed -i "/$marker_start/,/$marker_end/d" "$shell_config" + fi fi log_info "Installing global commands for Zsh..." @@ -94,14 +100,12 @@ lazy() { echo " logs Show container logs" echo " backup Backup configurations" echo " version Show version" + echo " configure Reconfigure directories and timezone" echo " uninstall Remove global commands" echo "" echo "Examples:" echo " lazy enter # Enter LazyVim from anywhere" - echo " lazy status # Check container status" - echo " lazy health # Run full diagnostics" - echo " lazy uninstall # Remove global commands" - echo "" + echo " lazy build # Build the environment" return 0 fi @@ -115,7 +119,7 @@ lazy() { ;; uninstall) echo "🗑️ Running uninstaller..." - (cd "\$lazyvim_docker_path" && bash uninstall-global-commands.sh) + (cd "\$lazyvim_docker_path" && ./scripts/uninstall-global-commands.sh) ;; *) echo "❌ Unknown command: \$cmd" @@ -125,15 +129,13 @@ lazy() { esac } -# Tab completion for lazy command -_lazy_completion() { +# Tab completion for lazy command (Zsh) +_lazy_zsh_completion() { local commands=(help start enter stop status health build restart destroy clean quick logs backup configure version uninstall) - _describe 'commands' commands + _describe 'lazy commands' commands } -if [[ -n "\$ZSH_VERSION" ]]; then - compdef _lazy_completion lazy -fi +compdef _lazy_zsh_completion lazy $marker_end EOF @@ -148,8 +150,12 @@ install_bash() { # Remove existing installation if present if grep -q "$marker_start" "$shell_config" 2>/dev/null; then - log_info "Removing existing installation..." - sed -i.bak "/$marker_start/,/$marker_end/d" "$shell_config" + log_info "Removing existing installation from Bash..." + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/$marker_start/,/$marker_end/d" "$shell_config" + else + sed -i "/$marker_start/,/$marker_end/d" "$shell_config" + fi fi log_info "Installing global commands for Bash..." @@ -182,17 +188,13 @@ lazy() { echo " quick Quick start (build + enter)" echo " logs Show container logs" echo " backup Backup configurations" - echo " configure Reconfigure directories and timezone" echo " version Show version" + echo " configure Reconfigure directories and timezone" echo " uninstall Remove global commands" echo "" echo "Examples:" echo " lazy enter # Enter LazyVim from anywhere" - echo " lazy status # Check container status" - echo " lazy health # Run full diagnostics" - echo " lazy configure # Reconfigure directories and timezone" - echo " lazy uninstall # Remove global commands" - echo "" + echo " lazy build # Build the environment" return 0 fi @@ -206,7 +208,7 @@ lazy() { ;; uninstall) echo "🗑️ Running uninstaller..." - (cd "\$lazyvim_docker_path" && bash uninstall-global-commands.sh) + (cd "\$lazyvim_docker_path" && ./scripts/uninstall-global-commands.sh) ;; *) echo "❌ Unknown command: \$cmd" @@ -216,7 +218,7 @@ lazy() { esac } -# Tab completion for lazy command (basic) +# Tab completion for lazy command (Bash) _lazy_completion() { local cur="\${COMP_WORDS[COMP_CWORD]}" local commands="help start enter stop status health build restart destroy clean quick logs backup configure version uninstall" @@ -230,34 +232,52 @@ EOF log_success "Bash configuration updated!" } -# Detect current shell and install accordingly -if [[ -n "$ZSH_VERSION" ]]; then - install_zsh -elif [[ -n "$BASH_VERSION" ]]; then +# Main installation function +install_global_commands() { + log_info "Installing global commands for both Bash and Zsh..." + + # Ensure shell config files exist + touch "$HOME/.bashrc" "$HOME/.zshrc" + + # Install for both shells install_bash -else - log_warning "Unsupported shell. Installing for Zsh by default..." install_zsh -fi + + echo "" + log_success "✓ Global 'lazy' commands installed!" + echo "" + log_info "Commands installed for both Bash and Zsh:" + echo " • Bash: $HOME/.bashrc" + echo " • Zsh: $HOME/.zshrc" + echo "" + log_info "Usage:" + echo " lazy enter # Enter LazyVim development environment" + echo " lazy help # Show all available commands" + echo "" + log_info "To activate:" + echo " • Restart your terminal, or" + echo " • Run: source ~/.bashrc (for Bash)" + echo " • Run: source ~/.zshrc (for Zsh)" + echo "" + + # Detect current shell and provide specific activation command + local current_shell="" + if [[ -n "$ZSH_VERSION" ]]; then + current_shell="zsh" + printf "${GREEN}For your current Zsh session, run: source ~/.zshrc${NC}\n" + elif [[ -n "$BASH_VERSION" ]]; then + current_shell="bash" + printf "${GREEN}For your current Bash session, run: source ~/.bashrc${NC}\n" + elif [[ "$SHELL" == *"zsh"* ]]; then + current_shell="zsh" + printf "${GREEN}For your current Zsh session, run: source ~/.zshrc${NC}\n" + else + current_shell="bash" + printf "${GREEN}For your current Bash session, run: source ~/.bashrc${NC}\n" + fi + + echo "" +} -echo "" -log_success "Global commands installed successfully!" -echo "" -log_info "To start using the commands:" -echo "" -if [[ -n "$ZSH_VERSION" ]]; then - echo " source ~/.zshrc" -else - echo " source ~/.bashrc" -fi -echo "" -log_info "Or restart your terminal." -echo "" -log_info "Then you can use from anywhere:" -echo " ${GREEN}lazy enter${NC} # Enter LazyVim" -echo " ${GREEN}lazy status${NC} # Check status" -echo " ${GREEN}lazy health${NC} # Run diagnostics" -echo " ${GREEN}lazy${NC} # Show all commands" -echo "" -log_warning "Note: The 'lazy' command will always execute from:" -echo " $LAZYVIM_DOCKER_PATH" +# Run the installation +install_global_commands diff --git a/scripts/remote-install.sh b/scripts/remote-install.sh deleted file mode 100755 index d0d4600..0000000 --- a/scripts/remote-install.sh +++ /dev/null @@ -1,449 +0,0 @@ -#!/bin/bash - -# LazyVim Docker - Remote Installation Script -# This script downloads and installs LazyVim Docker environment directly from GitHub -# Usage: curl -fsSL https://raw.githubusercontent.com/USER/lazyvim-docker/main/scripts/remote-install.sh | bash - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color - -# Configuration -REPO_URL="https://github.com/manghidev/lazyvim-docker" -REPO_NAME="lazyvim-docker" -INSTALL_DIR="$HOME/.local/share/lazyvim-docker" -BIN_DIR="$HOME/.local/bin" -TEMP_DIR="/tmp/lazyvim-docker-install" - -# Print functions -print_header() { - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║ LazyVim Docker - Remote Installer ║${NC}" - echo -e "${CYAN}║ Easy One-Command Setup ║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" -} - -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" -} - -print_step() { - echo -e "${PURPLE}[STEP]${NC} $1" -} - -# Check if command exists -command_exists() { - command -v "$1" >/dev/null 2>&1 -} - -# Check system requirements -check_requirements() { - print_step "Checking system requirements..." - - local missing_deps=() - - if ! command_exists curl; then - missing_deps+=("curl") - fi - - if ! command_exists git; then - missing_deps+=("git") - fi - - if ! command_exists docker; then - missing_deps+=("docker") - fi - - if ! command_exists docker && ! docker compose version >/dev/null 2>&1; then - print_warning "Docker or Docker Compose not found." - if ! docker compose version >/dev/null 2>&1; then - missing_deps+=("docker") - fi - fi - - if [ ${#missing_deps[@]} -ne 0 ]; then - print_error "Missing required dependencies: ${missing_deps[*]}" - echo "" - print_info "Please install the missing dependencies and try again:" - echo "" - if [[ "$OSTYPE" == "darwin"* ]]; then - echo " brew install ${missing_deps[*]}" - elif [[ "$OSTYPE" == "linux"* ]]; then - echo " # Ubuntu/Debian:" - echo " sudo apt-get update && sudo apt-get install -y ${missing_deps[*]}" - echo "" - echo " # CentOS/RHEL:" - echo " sudo yum install -y ${missing_deps[*]}" - fi - echo "" - exit 1 - fi - - print_success "All requirements satisfied!" -} - -# Create necessary directories -create_directories() { - print_step "Creating installation directories..." - - mkdir -p "$INSTALL_DIR" - mkdir -p "$BIN_DIR" - mkdir -p "$TEMP_DIR" - - print_success "Directories created successfully" -} - -# Download the repository -download_repository() { - print_step "Downloading LazyVim Docker repository..." - - # Remove temp directory if it exists - rm -rf "$TEMP_DIR" - - # Clone the repository to temp directory - if git clone --depth 1 "$REPO_URL" "$TEMP_DIR" >/dev/null 2>&1; then - print_success "Repository downloaded successfully" - else - print_error "Failed to download repository from $REPO_URL" - exit 1 - fi -} - -# Install the application -install_application() { - print_step "Installing LazyVim Docker..." - - # Remove existing installation - if [ -d "$INSTALL_DIR" ]; then - print_info "Removing existing installation..." - rm -rf "$INSTALL_DIR" - fi - - # Move from temp to install directory - mv "$TEMP_DIR" "$INSTALL_DIR" - - # Make scripts executable - chmod +x "$INSTALL_DIR/scripts/"*.sh - chmod +x "$INSTALL_DIR/Makefile" - - print_success "Application installed to $INSTALL_DIR" -} - -# Create global commands -create_global_commands() { - print_step "Creating global commands..." - - # Create the main lazy command - cat > "$BIN_DIR/lazy" << 'EOF' -#!/bin/bash - -# LazyVim Docker - Global Command -# This script provides global access to LazyVim Docker functionality - -LAZYVIM_INSTALL_DIR="$HOME/.local/share/lazyvim-docker" - -# Check if installation exists -if [ ! -d "$LAZYVIM_INSTALL_DIR" ]; then - echo "❌ LazyVim Docker not found. Please reinstall:" - echo " curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash" - exit 1 -fi - -# Change to install directory and run make command -cd "$LAZYVIM_INSTALL_DIR" - -# Handle special commands -case "$1" in - uninstall) - echo "🗑️ Uninstalling LazyVim Docker..." - bash "$LAZYVIM_INSTALL_DIR/scripts/remote-uninstall.sh" - ;; - update) - echo "🔄 Updating LazyVim Docker..." - bash "$LAZYVIM_INSTALL_DIR/scripts/remote-update.sh" - ;; - *) - # Pass all other commands to make - make "$@" - ;; -esac -EOF - - chmod +x "$BIN_DIR/lazy" - - # Add bin directory to PATH if not already there - add_to_path - - print_success "Global command 'lazy' created" -} - -# Add bin directory to PATH -add_to_path() { - local shell_config="" - local path_line="export PATH=\"\$HOME/.local/bin:\$PATH\"" - - # Determine shell config file - if [[ -n "$ZSH_VERSION" ]]; then - shell_config="$HOME/.zshrc" - elif [[ -n "$BASH_VERSION" ]]; then - shell_config="$HOME/.bashrc" - # Also check .bash_profile on macOS - if [[ "$OSTYPE" == "darwin"* ]] && [[ -f "$HOME/.bash_profile" ]]; then - shell_config="$HOME/.bash_profile" - fi - else - # Default to .bashrc - shell_config="$HOME/.bashrc" - fi - - # Add to PATH if not already there - if ! grep -q "$HOME/.local/bin" "$shell_config" 2>/dev/null; then - echo "" >> "$shell_config" - echo "# LazyVim Docker - Add local bin to PATH" >> "$shell_config" - echo "$path_line" >> "$shell_config" - print_info "Added $HOME/.local/bin to PATH in $shell_config" - fi -} - -# Configure timezone -configure_timezone() { - print_step "Configuring timezone..." - - # Detect system timezone - local system_tz="" - if command -v timedatectl >/dev/null 2>&1; then - system_tz=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "") - elif [[ -f /etc/timezone ]]; then - system_tz=$(cat /etc/timezone 2>/dev/null || echo "") - elif [[ "$OSTYPE" == "darwin"* ]]; then - system_tz=$(ls -la /etc/localtime 2>/dev/null | sed 's/.*zoneinfo\///' || echo "") - fi - - # Default timezone if detection fails - local default_tz="${system_tz:-America/Mexico_City}" - - echo "Current system timezone detected: ${system_tz:-"Could not detect"}" - echo "Available timezone examples:" - echo " - America/New_York" - echo " - America/Los_Angeles" - echo " - America/Mexico_City" - echo " - Europe/London" - echo " - Europe/Madrid" - echo " - Asia/Tokyo" - echo "" - - read -p "Enter your timezone [$default_tz]: " user_tz - user_tz=${user_tz:-$default_tz} - - # Update timezone in docker-compose.yml - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "s/TIMEZONE: .*/TIMEZONE: $user_tz/" docker-compose.yml - sed -i '' "s/TZ=.*/TZ=$user_tz/" docker-compose.yml - else - sed -i "s/TIMEZONE: .*/TIMEZONE: $user_tz/" docker-compose.yml - sed -i "s/TZ=.*/TZ=$user_tz/" docker-compose.yml - fi - - print_success "Timezone configured: $user_tz" -} - -# Configure directories -configure_directories() { - print_step "Configuring directories to mount..." - - # Detect OS - local os_type="" - local default_docs="$HOME/Documents" - local default_projects="" - - if [[ "$OSTYPE" == "darwin"* ]]; then - os_type="macOS" - default_projects="$HOME/Developer" - else - os_type="Linux" - default_projects="$HOME/Projects" - fi - - echo "Detected OS: $os_type" - echo "The container will mount directories so you can access your files inside the development environment." - echo "" - - # Configure Documents directory - echo "📁 Documents Directory:" - if [[ -d "$default_docs" ]]; then - read -p "Mount Documents directory ($default_docs)? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - print_info "Documents directory will be mounted at /home/developer/Documents" - else - # Comment out the Documents line - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' 's|^ - \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml - else - sed -i 's|^ - \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml - fi - print_info "Documents directory mounting disabled" - fi - fi - - # Configure Projects directory - echo "" - echo "💻 Projects Directory:" - read -p "Do you want to mount a Projects directory? (Y/n): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - read -p "Enter path to your projects directory [$default_projects]: " projects_dir - projects_dir=${projects_dir:-$default_projects} - - if [[ -d "$projects_dir" ]]; then - # Add projects directory to docker-compose.yml - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "/\$HOME\/Documents:/a\\ - - $projects_dir:/home/developer/Projects" docker-compose.yml - else - sed -i "/\$HOME\/Documents:/a\\ - - $projects_dir:/home/developer/Projects" docker-compose.yml - fi - print_success "Projects directory added: $projects_dir -> /home/developer/Projects" - else - print_warning "Directory $projects_dir does not exist, you can add it later" - fi - fi - - # Configure additional directories - echo "" - echo "📂 Additional Directories:" - read -p "Do you want to mount any additional directories? (y/N): " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - local counter=1 - while true; do - echo "" - read -p "Enter directory path (or 'done' to finish): " custom_dir - if [[ "$custom_dir" == "done" ]]; then - break - fi - - if [[ -d "$custom_dir" ]]; then - local mount_name=$(basename "$custom_dir") - read -p "Mount as [/home/developer/$mount_name]: " container_path - container_path=${container_path:-"/home/developer/$mount_name"} - - # Add custom directory to docker-compose.yml - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "/\$HOME\/Documents:/a\\ - - $custom_dir:$container_path" docker-compose.yml - else - sed -i "/\$HOME\/Documents:/a\\ - - $custom_dir:$container_path" docker-compose.yml - fi - print_success "Added: $custom_dir -> $container_path" - else - print_warning "Directory $custom_dir does not exist, skipping" - fi - - counter=$((counter + 1)) - if [[ $counter -gt 5 ]]; then - print_info "Maximum directories reached" - break - fi - done - fi - - print_success "Directory configuration completed" -} - -# Initial setup -initial_setup() { - print_step "Running initial setup..." - - cd "$INSTALL_DIR" - - echo "" - print_info "Let's configure your LazyVim Docker environment..." - echo "" - - # Ask for configuration - configure_timezone - echo "" - configure_directories - echo "" - - # Build the Docker environment - print_info "Building Docker environment (this may take a few minutes)..." - if make build; then - print_success "Docker environment built successfully" - else - print_warning "Docker build failed, but installation completed. You can run 'lazy build' later." - fi -} - -# Cleanup -cleanup() { - print_step "Cleaning up temporary files..." - rm -rf "$TEMP_DIR" - print_success "Cleanup completed" -} - -# Main installation process -main() { - print_header - - print_info "Starting LazyVim Docker remote installation..." - print_info "Installation directory: $INSTALL_DIR" - print_info "Binary directory: $BIN_DIR" - echo "" - - check_requirements - create_directories - download_repository - install_application - create_global_commands - initial_setup - cleanup - - echo "" - print_success "🎉 LazyVim Docker installed successfully!" - echo "" - print_info "Usage:" - echo " ${GREEN}lazy enter${NC} # Enter LazyVim development environment" - echo " ${GREEN}lazy start${NC} # Start the container" - echo " ${GREEN}lazy stop${NC} # Stop the container" - echo " ${GREEN}lazy status${NC} # Check container status" - echo " ${GREEN}lazy configure${NC} # Reconfigure directories and timezone" - echo " ${GREEN}lazy update${NC} # Update to latest version" - echo " ${GREEN}lazy uninstall${NC} # Uninstall everything" - echo " ${GREEN}lazy help${NC} # Show all available commands" - echo "" - print_info "To get started:" - echo " 1. Restart your terminal or run: ${YELLOW}source ~/.zshrc${NC} (or ~/.bashrc)" - echo " 2. Run: ${GREEN}lazy enter${NC}" - echo "" - print_info "To reconfigure directories or timezone later:" - echo " Run: ${GREEN}lazy configure${NC}" - echo "" - print_info "Happy coding! 🚀" -} - -# Run main function -main "$@" diff --git a/scripts/remote-uninstall.sh b/scripts/remote-uninstall.sh index 2e88b47..154cdb1 100755 --- a/scripts/remote-uninstall.sh +++ b/scripts/remote-uninstall.sh @@ -5,14 +5,24 @@ set -e -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color +# Colors for output using tput (more compatible) +if command -v tput >/dev/null 2>&1 && [[ -t 1 ]]; then + RED=$(tput setaf 1 2>/dev/null || echo '') + GREEN=$(tput setaf 2 2>/dev/null || echo '') + YELLOW=$(tput setaf 3 2>/dev/null || echo '') + BLUE=$(tput setaf 4 2>/dev/null || echo '') + PURPLE=$(tput setaf 5 2>/dev/null || echo '') + CYAN=$(tput setaf 6 2>/dev/null || echo '') + NC=$(tput sgr0 2>/dev/null || echo '') +else + RED='' + GREEN='' + YELLOW='' + BLUE='' + PURPLE='' + CYAN='' + NC='' +fi # Configuration INSTALL_DIR="$HOME/.local/share/lazyvim-docker" @@ -20,30 +30,71 @@ BIN_DIR="$HOME/.local/bin" # Print functions print_header() { - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║ LazyVim Docker - Uninstaller ║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" + printf "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}\n" + printf "${CYAN}║ LazyVim Docker - Uninstaller ║${NC}\n" + printf "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}\n" + printf "\n" } print_info() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } print_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } print_step() { - echo -e "${PURPLE}[STEP]${NC} $1" + printf "${PURPLE}[STEP]${NC} %s\n" "$1" +} + +# Smart terminal restart for clean environment +restart_terminal() { + print_step "Setting up terminal cleanup..." + + # Detect current shell + local current_shell="" + if [ -n "$SHELL" ]; then + case "$SHELL" in + */zsh) current_shell="zsh" ;; + */bash) current_shell="bash" ;; + *) current_shell="bash" ;; + esac + else + current_shell="bash" + fi + + print_info "Detected shell: $current_shell" + + # Create a helper script for easy restart + local helper_script="/tmp/lazyvim_cleanup_terminal.sh" + cat > "$helper_script" << 'EOF' +#!/bin/bash +echo "🧹 Restarting terminal to complete LazyVim Docker cleanup..." +echo "" +EOF + echo "exec $current_shell" >> "$helper_script" + chmod +x "$helper_script" + + echo "" + print_warning "🧹 To complete cleanup and remove any traces:" + echo "" + printf " ${GREEN}Option 1 (Easiest):${NC}\n" + printf " ${GREEN}%s${NC}\n" "$helper_script" + echo "" + printf " ${GREEN}Option 2 (Manual):${NC}\n" + printf " ${GREEN}exec %s${NC}\n" "$current_shell" + echo "" + print_info "💡 Copy and paste the first command to clean your terminal" + print_info "This ensures no traces of 'lazy' commands remain" } # Stop and remove Docker containers @@ -96,6 +147,40 @@ remove_installation() { fi } +# Remove global commands from shell configurations +remove_shell_commands() { + print_step "Removing global commands from shell configurations..." + + local configs=("$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.bash_profile") + local marker_start="# LazyVim Docker Global Commands - START" + local marker_end="# LazyVim Docker Global Commands - END" + local removed_any=false + + for config in "${configs[@]}"; do + if [[ -f "$config" ]] && grep -q "$marker_start" "$config" 2>/dev/null; then + print_info "Removing commands from: $config" + + # Create backup + cp "$config" "${config}.backup.$(date +%Y%m%d-%H%M%S)" + + # Remove the section between markers + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/$marker_start/,/$marker_end/d" "$config" + else + sed -i "/$marker_start/,/$marker_end/d" "$config" + fi + + removed_any=true + fi + done + + if [[ "$removed_any" == true ]]; then + print_success "Global commands removed from shell configurations" + else + print_info "No global commands found in shell configurations" + fi +} + # Remove global command remove_global_command() { print_step "Removing global command..." @@ -108,40 +193,38 @@ remove_global_command() { fi } -# Remove PATH modifications (optional) +# Remove PATH modifications automatically remove_path_modifications() { - echo "" - echo -n "Do you want to remove PATH modifications from shell config? [y/N]: " - read -r response + print_step "Removing PATH modifications..." - case "$response" in - [yY][eE][sS]|[yY]) - print_step "Removing PATH modifications..." - - local shell_configs=("$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile") - - for config in "${shell_configs[@]}"; do - if [ -f "$config" ]; then - # Create backup - cp "$config" "${config}.backup.$(date +%Y%m%d-%H%M%S)" - - # Remove LazyVim Docker PATH modifications - sed -i.tmp '/# LazyVim Docker - Add local bin to PATH/d' "$config" 2>/dev/null || true - sed -i.tmp '/export PATH=.*\.local\/bin.*PATH/d' "$config" 2>/dev/null || true - rm -f "${config}.tmp" - - print_info "Cleaned PATH modifications from: $config" - fi - done + local shell_configs=("$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile") + local removed_any=false + + for config in "${shell_configs[@]}"; do + if [ -f "$config" ]; then + # Create backup + cp "$config" "${config}.backup.$(date +%Y%m%d-%H%M%S)" - print_success "PATH modifications removed" - ;; - *) - print_info "PATH modifications preserved" - ;; - esac + # Remove LazyVim Docker PATH modifications + if grep -q "LazyVim Docker" "$config" 2>/dev/null; then + sed -i.tmp '/# LazyVim Docker - Add local bin to PATH/d' "$config" 2>/dev/null || true + sed -i.tmp '/export PATH=.*\.local\/bin.*PATH/d' "$config" 2>/dev/null || true + rm -f "${config}.tmp" + + print_info "Cleaned PATH modifications from: $config" + removed_any=true + fi + fi + done + + if [[ "$removed_any" == true ]]; then + print_success "PATH modifications removed" + else + print_info "No PATH modifications found" + fi } +# Confirm uninstallation # Confirm uninstallation confirm_uninstall() { echo "" @@ -151,8 +234,33 @@ confirm_uninstall() { echo " • Global 'lazy' command" echo " • All data and configurations" echo "" - echo -n "Are you sure you want to continue? [y/N]: " - read -r response + + # Try to read from terminal, fallback to stdin if needed + printf "Are you sure you want to continue? [y/N]: " + local response + + # Try multiple methods to read input + if read -r response < /dev/tty 2>/dev/null; then + # Successfully read from terminal + : + elif [[ -t 0 ]]; then + # stdin is a terminal, try regular read + read -r response + else + # Non-interactive mode or piped input + if [[ "${LAZYVIM_FORCE_UNINSTALL:-}" == "true" ]]; then + print_info "Non-interactive mode: proceeding with forced uninstall (LAZYVIM_FORCE_UNINSTALL=true)" + response="y" + else + print_info "Non-interactive mode: uninstallation cancelled for safety" + print_info "To force uninstall via pipe, set: LAZYVIM_FORCE_UNINSTALL=true" + print_info "" + print_info "Examples:" + printf " ${GREEN}LAZYVIM_FORCE_UNINSTALL=true curl -fsSL [URL] | bash${NC}\n" + printf " ${GREEN}curl -fsSL [URL] | LAZYVIM_FORCE_UNINSTALL=true bash${NC}\n" + exit 0 + fi + fi case "$response" in [yY][eE][sS]|[yY]) @@ -177,6 +285,7 @@ main() { cleanup_docker remove_installation remove_global_command + remove_shell_commands remove_path_modifications echo "" @@ -190,8 +299,11 @@ main() { print_info "Thank you for using LazyVim Docker! 🚀" echo "" print_info "To reinstall later, run:" - echo " ${GREEN}curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash${NC}" + printf " ${GREEN}curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash${NC}\n" echo "" + + # Restart terminal to clean up environment + restart_terminal } # Run main function diff --git a/scripts/remote-update.sh b/scripts/remote-update.sh index b0a259e..db7ab01 100755 --- a/scripts/remote-update.sh +++ b/scripts/remote-update.sh @@ -53,7 +53,7 @@ check_installation() { if [ ! -d "$INSTALL_DIR" ]; then print_error "LazyVim Docker installation not found at: $INSTALL_DIR" print_info "Please install first:" - echo " curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/remote-install.sh | bash" + echo " curl -fsSL https://raw.githubusercontent.com/manghidev/lazyvim-docker/main/scripts/start.sh | bash" exit 1 fi } @@ -217,7 +217,7 @@ main() { print_info "Backup available at: $BACKUP_DIR" echo "" print_info "To start using the updated version:" - echo " ${GREEN}lazyvim enter${NC}" + printf " ${GREEN}lazyvim enter${NC}\n" echo "" } diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100755 index 0000000..994009b --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,419 @@ +#!/bin/bash + +# LazyVim Docker - One-Command Setup +# Automatic installation with smart defaults - no questions asked! +# Usage: curl -fsSL https://raw.githubusercontent.com/USER/lazyvim-docker/main/scripts/start.sh | bash + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Configuration +REPO_URL="https://github.com/manghidev/lazyvim-docker" +REPO_NAME="lazyvim-docker" +INSTALL_DIR="$HOME/.local/share/lazyvim-docker" +BIN_DIR="$HOME/.local/bin" +TEMP_DIR="/tmp/lazyvim-docker-install" +BRANCH="${LAZYVIM_BRANCH:-develop}" + +# Print functions +print_header() { + printf "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}\n" + printf "${CYAN}║ LazyVim Docker - Quick Start ║${NC}\n" + printf "${CYAN}║ One Command, Instant Development ║${NC}\n" + printf "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}\n" + printf "\n" +} + +print_info() { + printf "${BLUE}[INFO]${NC} %s\n" "$1" +} + +print_success() { + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" +} + +print_warning() { + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" +} + +print_error() { + printf "${RED}[ERROR]${NC} %s\n" "$1" +} + +print_step() { + printf "${PURPLE}[STEP]${NC} %s\n" "$1" +} + +# Smart terminal restart with helper script +restart_terminal() { + print_step "Setting up terminal restart..." + + # Detect current shell + local current_shell="" + if [ -n "$SHELL" ]; then + case "$SHELL" in + */zsh) current_shell="zsh" ;; + */bash) current_shell="bash" ;; + *) current_shell="bash" ;; + esac + else + current_shell="bash" + fi + + print_info "Detected shell: $current_shell" + + # Create a helper script for easy restart + local helper_script="/tmp/lazyvim_restart_terminal.sh" + cat > "$helper_script" << 'EOF' +#!/bin/bash +echo "🔄 Restarting terminal to activate LazyVim Docker commands..." +echo "" +EOF + echo "exec $current_shell" >> "$helper_script" + chmod +x "$helper_script" + + echo "" + print_warning "🔄 To activate 'lazy' commands, choose the EASIEST option:" + echo "" + printf " ${GREEN}Option 1 (Easiest):${NC}\n" + printf " ${GREEN}%s${NC}\n" "$helper_script" + echo "" + printf " ${GREEN}Option 2 (Manual):${NC}\n" + printf " ${GREEN}exec %s${NC}\n" "$current_shell" + echo "" + printf " ${GREEN}Option 3 (Alternative):${NC}\n" + printf " ${GREEN}source ~/.%src${NC}\n" "$current_shell" + echo "" + + # Try to detect if we can restart directly + if [[ -t 0 ]] && [[ -t 1 ]] && [[ $- == *i* ]]; then + print_info "✨ Auto-restart available!" + local choice + printf "Press ENTER to restart now, or 'n' to do it manually: " + read -r choice + + if [[ "$choice" != "n" ]] && [[ "$choice" != "N" ]]; then + print_info "Restarting terminal..." + exec "$current_shell" + else + print_info "Manual restart chosen - use the commands above" + fi + else + print_info "💡 Copy and paste the first command to restart your terminal" + printf "Then run: ${GREEN}lazy enter${NC}\n" + fi +} + +# Check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check system requirements +check_requirements() { + print_step "Checking system requirements..." + + local missing_deps=() + + if ! command_exists curl; then + missing_deps+=("curl") + fi + + if ! command_exists git; then + missing_deps+=("git") + fi + + if ! command_exists docker; then + missing_deps+=("docker") + fi + + if ! command_exists docker && ! docker compose version >/dev/null 2>&1; then + print_warning "Docker or Docker Compose not found." + if ! docker compose version >/dev/null 2>&1; then + missing_deps+=("docker") + fi + fi + + if [ ${#missing_deps[@]} -ne 0 ]; then + print_error "Missing required dependencies: ${missing_deps[*]}" + echo "" + print_info "Please install the missing dependencies and try again:" + echo "" + if [[ "$OSTYPE" == "darwin"* ]]; then + echo " brew install ${missing_deps[*]}" + elif [[ "$OSTYPE" == "linux"* ]]; then + echo " # Ubuntu/Debian:" + echo " sudo apt-get update && sudo apt-get install -y ${missing_deps[*]}" + echo "" + echo " # CentOS/RHEL:" + echo " sudo yum install -y ${missing_deps[*]}" + fi + echo "" + exit 1 + fi + + print_success "All requirements satisfied!" +} + +# Create installation directories +create_directories() { + print_step "Creating installation directories..." + + mkdir -p "$INSTALL_DIR" + mkdir -p "$BIN_DIR" + mkdir -p "$TEMP_DIR" + + print_success "Directories created successfully" +} + +# Download repository +download_repository() { + print_step "Downloading LazyVim Docker repository..." + + cd "$TEMP_DIR" + + if command_exists git; then + git clone --branch "$BRANCH" --depth 1 "$REPO_URL" "$REPO_NAME" >/dev/null 2>&1 + else + curl -fsSL "${REPO_URL}/archive/${BRANCH}.tar.gz" | tar -xz --strip-components=1 -C "$REPO_NAME" 2>/dev/null + fi + + print_success "Repository downloaded successfully" +} + +# Install application +install_application() { + print_step "Installing LazyVim Docker..." + + if [ -d "$INSTALL_DIR" ]; then + print_info "Removing existing installation..." + rm -rf "$INSTALL_DIR" + fi + + cp -r "$TEMP_DIR/$REPO_NAME" "$INSTALL_DIR" + + print_success "Application installed to $INSTALL_DIR" +} + +# Setup PATH for local bin directory +setup_local_bin_path() { + local shell_config="$1" + local path_line="export PATH=\"\$HOME/.local/bin:\$PATH\"" + + # Create config file if it doesn't exist + touch "$shell_config" + + # Add to PATH if not already there + if ! grep -q "$HOME/.local/bin" "$shell_config" 2>/dev/null; then + echo "" >> "$shell_config" + echo "# LazyVim Docker - Add local bin to PATH" >> "$shell_config" + echo "$path_line" >> "$shell_config" + print_info "Added $HOME/.local/bin to PATH in $shell_config" + fi +} + +# Create global commands +create_global_commands() { + print_step "Installing global commands..." + + # Create bin directory if it doesn't exist + mkdir -p "$BIN_DIR" + + # Run the installer script from the project + cd "$INSTALL_DIR" + chmod +x ./scripts/install-global-commands.sh + if ./scripts/install-global-commands.sh; then + print_success "Global commands installed successfully" + else + print_error "Failed to install global commands" + exit 1 + fi + + # Ensure .local/bin is in PATH for both shells + setup_local_bin_path "$HOME/.bashrc" + setup_local_bin_path "$HOME/.zshrc" + + print_success "Global 'lazy' command is now available" +} + +# Auto-configure with smart defaults +auto_configure() { + print_step "Auto-configuring with smart defaults..." + + cd "$INSTALL_DIR" + + # Detect and set timezone + local system_tz="" + if command -v timedatectl >/dev/null 2>&1; then + system_tz=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "") + elif [[ -f /etc/timezone ]]; then + system_tz=$(cat /etc/timezone 2>/dev/null || echo "") + elif [[ "$OSTYPE" == "darwin"* ]]; then + system_tz=$(ls -la /etc/localtime 2>/dev/null | sed 's/.*zoneinfo\///' || echo "") + fi + + local default_tz="${system_tz:-America/Mexico_City}" + + # Update timezone in docker-compose.yml + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s|TIMEZONE: .*|TIMEZONE: $default_tz|" docker-compose.yml + sed -i '' "s|TZ=.*|TZ=$default_tz|" docker-compose.yml + else + sed -i "s|TIMEZONE: .*|TIMEZONE: $default_tz|" docker-compose.yml + sed -i "s|TZ=.*|TZ=$default_tz|" docker-compose.yml + fi + + print_success "Timezone configured: $default_tz" + + # Auto-configure directories + local default_docs="$HOME/Documents" + local default_projects="" + + if [[ "$OSTYPE" == "darwin"* ]]; then + default_projects="$HOME/Developer" + else + default_projects="$HOME/Projects" + fi + + # Configure Documents automatically if exists + if [[ -d "$default_docs" ]]; then + print_success "Documents directory will be mounted: $default_docs" + else + # Comment out the Documents line + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' 's|^ - \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml + else + sed -i 's|^ - \$HOME/Documents:| # - \$HOME/Documents:|' docker-compose.yml + fi + print_info "Documents directory not found, mounting disabled" + fi + + # Configure Projects automatically if exists + if [[ -d "$default_projects" ]]; then + # Add projects directory to docker-compose.yml + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "/\$HOME\/Documents:/a\\ + - $default_projects:/home/developer/Projects" docker-compose.yml + else + sed -i "/\$HOME\/Documents:/a\\ + - $default_projects:/home/developer/Projects" docker-compose.yml + fi + print_success "Projects directory added: $default_projects" + else + print_info "Projects directory not found: $default_projects" + fi + + print_success "Auto-configuration completed with smart defaults" +} + +# Build environment +build_environment() { + print_step "Building Docker environment..." + + cd "$INSTALL_DIR" + + print_info "This may take a few minutes..." + + # Clean up existing environment + print_info "Cleaning up existing environment..." + docker compose down --rmi all --volumes 2>/dev/null || true + + # Pull latest base images + print_info "Pulling latest base images..." + docker compose pull 2>/dev/null || print_warning "Could not pull some images, continuing..." + + # Build the container + print_info "Building container..." + if docker compose build --no-cache 2>/dev/null; then + print_success "Container built successfully" + + # Start the container + print_info "Starting the container..." + if docker compose up --force-recreate -d 2>/dev/null; then + print_success "Container started successfully" + + # Wait for container to be ready + print_info "Waiting for container to be ready..." + sleep 3 + + # Check if container is running + if docker compose ps 2>/dev/null | grep -q "Up"; then + print_success "Container is running!" + print_info "Opening shell in the container..." + # Don't try to open shell automatically - let user do it manually + print_info "You can enter the container with: lazy enter" + else + print_warning "Container may not have started properly. Check with 'lazy status'" + fi + else + print_warning "Failed to start container. You can try 'lazy start' later." + fi + else + print_warning "Docker build failed, but installation completed. You can run 'lazy build' later." + fi +} + +# Cleanup +cleanup() { + print_step "Cleaning up temporary files..." + rm -rf "$TEMP_DIR" + print_success "Cleanup completed" +} + +# Main installation process +main() { + print_header + + print_info "Starting LazyVim Docker simple installation..." + print_info "Installation directory: $INSTALL_DIR" + print_info "Binary directory: $BIN_DIR" + print_info "Using smart defaults (no interactive input required)" + echo "" + + check_requirements + create_directories + download_repository + install_application + create_global_commands + auto_configure + build_environment + cleanup + + echo "" + print_success "🎉 LazyVim Docker installed successfully!" + echo "" + print_info "Configuration applied:" + echo " • Timezone: Auto-detected from system" + echo " • Documents: Auto-mounted if exists" + echo " • Projects: Auto-mounted if exists" + echo "" + print_info "Usage:" + printf " ${GREEN}lazy enter${NC} # Enter LazyVim development environment\n" + printf " ${GREEN}lazy start${NC} # Start the container\n" + printf " ${GREEN}lazy stop${NC} # Stop the container\n" + printf " ${GREEN}lazy status${NC} # Check container status\n" + printf " ${GREEN}lazy configure${NC} # Reconfigure directories and timezone\n" + printf " ${GREEN}lazy update${NC} # Update to latest version\n" + printf " ${GREEN}lazy uninstall${NC} # Uninstall everything\n" + printf " ${GREEN}lazy help${NC} # Show all available commands\n" + echo "" + print_info "To customize configuration later:" + printf " Run: ${GREEN}lazy configure${NC}\n" + echo "" + print_info "Happy coding! 🚀" + echo "" + + # Restart terminal to make commands available immediately + restart_terminal +} + +# Run main function +main "$@" diff --git a/scripts/uninstall-global-commands.sh b/scripts/uninstall-global-commands.sh index 2eca576..5f9dd06 100755 --- a/scripts/uninstall-global-commands.sh +++ b/scripts/uninstall-global-commands.sh @@ -19,19 +19,19 @@ END_MARKER="# LazyVim Docker Global Commands - END" # Print colored output print_status() { - echo -e "${BLUE}[INFO]${NC} $1" + printf "${BLUE}[INFO]${NC} %s\n" "$1" } print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" + printf "${GREEN}[SUCCESS]${NC} %s\n" "$1" } print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + printf "${YELLOW}[WARNING]${NC} %s\n" "$1" } print_error() { - echo -e "${RED}[ERROR]${NC} $1" + printf "${RED}[ERROR]${NC} %s\n" "$1" } # Function to remove commands from a specific shell config file @@ -103,12 +103,18 @@ remove_global_commands() { remove_project_directory() { local project_dir project_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + # Get parent directory (remove /scripts) + project_dir="$(dirname "$project_dir")" echo print_status "Current project directory: $project_dir" echo - echo -n "Do you want to remove the entire LazyVim Docker project directory? [y/N]: " - read -r response + printf "Do you want to remove the entire LazyVim Docker project directory? [y/N]: " + if [[ -t 0 ]] && [[ -t 1 ]] && [[ $- == *i* ]]; then + read -r response