#!/bin/bash # LED Matrix One-Shot Installation Script # This script provides a single-command installation experience # Usage: curl -fsSL https://raw.githubusercontent.com/ChuckBuilds/LEDMatrix/main/scripts/install/one-shot-install.sh | bash set -Eeuo pipefail # Global state for error tracking CURRENT_STEP="initialization" # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Error handler for explicit failures on_error() { local exit_code=$? local line_no=${1:-unknown} echo "" >&2 echo -e "${RED}✗ ERROR: Installation failed at step: $CURRENT_STEP${NC}" >&2 echo -e "${RED} Line: $line_no, Exit code: $exit_code${NC}" >&2 echo "" >&2 echo "Common fixes:" >&2 echo " - Check internet connectivity: ping -c1 8.8.8.8" >&2 echo " - Verify sudo access: sudo -v" >&2 echo " - Check disk space: df -h /" >&2 echo " - If APT lock error: sudo dpkg --configure -a" >&2 echo " - If /tmp permission error: sudo chmod 1777 /tmp" >&2 echo " - Wait a few minutes and try again" >&2 echo "" >&2 echo "This script is safe to run multiple times. You can re-run it to continue." >&2 exit "$exit_code" } trap 'on_error $LINENO' ERR # Helper functions for colored output print_step() { echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}==========================================${NC}" echo "" } print_success() { echo -e "${GREEN}✓${NC} $1" } print_warning() { echo -e "${YELLOW}⚠${NC} $1" } print_error() { echo -e "${RED}✗${NC} $1" } # Retry function for network operations retry() { local attempt=1 local max_attempts=3 local delay_seconds=5 while true; do if "$@"; then return 0 fi local status=$? if [ $attempt -ge $max_attempts ]; then print_error "Command failed after $attempt attempts: $*" return $status fi print_warning "Command failed (attempt $attempt/$max_attempts). Retrying in ${delay_seconds}s: $*" attempt=$((attempt+1)) sleep "$delay_seconds" done } # Check network connectivity check_network() { CURRENT_STEP="Network connectivity check" print_step "Checking network connectivity..." if command -v ping >/dev/null 2>&1; then if ping -c 1 -W 3 8.8.8.8 >/dev/null 2>&1; then print_success "Internet connectivity confirmed (ping test)" return 0 fi fi if command -v curl >/dev/null 2>&1; then if curl -Is --max-time 5 http://deb.debian.org >/dev/null 2>&1; then print_success "Internet connectivity confirmed (curl test)" return 0 fi fi if command -v wget >/dev/null 2>&1; then if wget --spider --timeout=5 http://deb.debian.org >/dev/null 2>&1; then print_success "Internet connectivity confirmed (wget test)" return 0 fi fi print_error "No internet connectivity detected" echo "" echo "Please ensure your Raspberry Pi is connected to the internet and try again." exit 1 } # Check disk space check_disk_space() { CURRENT_STEP="Disk space check" if ! command -v df >/dev/null 2>&1; then print_warning "df command not available, skipping disk space check" return 0 fi # Check available space in MB AVAILABLE_SPACE=$(df -m / | awk 'NR==2{print $4}' || echo "0") # Ensure AVAILABLE_SPACE has a default value if empty (handles unexpected df output) AVAILABLE_SPACE=${AVAILABLE_SPACE:-0} if [ "$AVAILABLE_SPACE" -lt 500 ]; then print_error "Insufficient disk space: ${AVAILABLE_SPACE}MB available (need at least 500MB)" echo "" echo "Please free up disk space before continuing:" echo " - Remove unnecessary packages: sudo apt autoremove" echo " - Clean APT cache: sudo apt clean" echo " - Check large files: sudo du -sh /* | sort -h" exit 1 elif [ "$AVAILABLE_SPACE" -lt 1024 ]; then print_warning "Limited disk space: ${AVAILABLE_SPACE}MB available (recommend at least 1GB)" else print_success "Disk space sufficient: ${AVAILABLE_SPACE}MB available" fi } # Ensure sudo access check_sudo() { CURRENT_STEP="Sudo access check" print_step "Checking sudo access..." # Check if running as root if [ "$EUID" -eq 0 ]; then print_success "Running as root" return 0 fi # Check if sudo is available if ! command -v sudo >/dev/null 2>&1; then print_error "sudo is not available and script is not running as root" echo "" echo "Please either:" echo " 1. Run as root: sudo bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/ChuckBuilds/LEDMatrix/main/scripts/install/one-shot-install.sh)\"" echo " 2. Or install sudo first" exit 1 fi # Test sudo access if ! sudo -n true 2>/dev/null; then print_warning "Need sudo password - you may be prompted" if ! sudo -v; then print_error "Failed to obtain sudo privileges" exit 1 fi fi print_success "Sudo access confirmed" } # Fix /tmp permissions if needed (common issue when running via curl | bash) # Note: /tmp permission fixing is now done inline before running first_time_install.sh # This function is kept for backward compatibility but not actively used fix_tmp_permissions() { CURRENT_STEP="TMP directory check" # Only fix if /tmp is actually not writable (don't preemptively fix) if [ ! -w /tmp ]; then print_warning "/tmp is not writable, attempting to fix..." if [ "$EUID" -eq 0 ]; then chmod 1777 /tmp 2>/dev/null || true else sudo chmod 1777 /tmp 2>/dev/null || true fi fi # Ensure TMPDIR is set correctly if [ -z "${TMPDIR:-}" ] || [ ! -w "${TMPDIR:-/tmp}" ]; then export TMPDIR=/tmp fi } # Main installation function main() { print_step "LED Matrix One-Shot Installation" echo "This script will:" echo " 1. Check prerequisites (network, disk space, sudo)" echo " 2. Install system dependencies (git, python3, build tools)" echo " 3. Clone the LEDMatrix repository" echo " 4. Run the first-time installation script" echo "" # Check prerequisites check_network check_disk_space check_sudo # Note: /tmp permissions are checked and fixed inline before running first_time_install.sh # (only if actually wrong, not preemptively) # Determine repository location REPO_DIR="${HOME}/LEDMatrix" REPO_URL="https://github.com/ChuckBuilds/LEDMatrix.git" CURRENT_STEP="Repository setup" print_step "Setting up repository..." # Check if directory exists and handle accordingly if [ -d "$REPO_DIR" ]; then if [ -d "$REPO_DIR/.git" ]; then print_warning "Repository already exists at $REPO_DIR" print_warning "Pulling latest changes..." cd "$REPO_DIR" if git pull origin main >/dev/null 2>&1; then print_success "Repository updated successfully" else print_warning "Git pull failed, but continuing with existing repository" print_warning "You may have local changes or the repository may be on a different branch" fi else print_warning "Directory exists but is not a git repository" print_warning "Removing and cloning fresh..." cd "$HOME" rm -rf "$REPO_DIR" print_success "Cloning repository..." retry git clone "$REPO_URL" "$REPO_DIR" fi else print_success "Cloning repository to $REPO_DIR..." retry git clone "$REPO_URL" "$REPO_DIR" fi # Verify repository is accessible if [ ! -d "$REPO_DIR" ] || [ ! -f "$REPO_DIR/first_time_install.sh" ]; then print_error "Repository setup failed: $REPO_DIR/first_time_install.sh not found" exit 1 fi print_success "Repository ready at $REPO_DIR" # Execute main installation script CURRENT_STEP="Main installation" print_step "Running main installation script..." cd "$REPO_DIR" # Make sure the script is executable chmod +x first_time_install.sh # Check if script exists if [ ! -f "first_time_install.sh" ]; then print_error "first_time_install.sh not found in $REPO_DIR" exit 1 fi print_success "Starting main installation (this may take 10-30 minutes)..." echo "" # Execute with proper error handling and non-interactive mode # Temporarily disable errexit to capture exit code instead of exiting immediately set +e # Check /tmp permissions - only fix if actually wrong (common in automated scenarios) # When running manually, /tmp usually has correct permissions (1777) TMP_PERMS=$(stat -c '%a' /tmp 2>/dev/null || echo "unknown") if [ "$TMP_PERMS" != "1777" ] && [ "$TMP_PERMS" != "unknown" ]; then CURRENT_STEP="Fixing /tmp permissions" print_warning "/tmp has incorrect permissions ($TMP_PERMS), fixing to 1777..." if [ "$EUID" -eq 0 ]; then chmod 1777 /tmp 2>/dev/null || print_warning "Failed to fix /tmp permissions, continuing anyway..." else sudo chmod 1777 /tmp 2>/dev/null || print_warning "Failed to fix /tmp permissions, continuing anyway..." fi fi # Execute main installation script with non-interactive mode CURRENT_STEP="Main installation" export TMPDIR=/tmp if [ "$EUID" -eq 0 ]; then # Run in non-interactive mode with ASSUME_YES (both -y flag and env var for safety) export LEDMATRIX_ASSUME_YES=1 bash ./first_time_install.sh -y else # Pass both -y flag AND environment variable for non-interactive mode # This ensures it works even if the script re-executes itself with sudo # Also ensure stdin is properly handled for non-interactive mode sudo -E env TMPDIR=/tmp LEDMATRIX_ASSUME_YES=1 bash ./first_time_install.sh -y