#!/bin/bash # apt-layer Installation Script # This script installs the apt-layer tool, its dependencies, creates necessary directories and files, # and sets up the system to use apt-layer. If already installed, it will update the tool. # # Usage: # ./install-apt-layer.sh # Install or update apt-layer # ./install-apt-layer.sh --uninstall # Remove apt-layer and all its files # ./install-apt-layer.sh --reinstall # Remove and reinstall (reset to default state) # ./install-apt-layer.sh --help # Show this help message set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # Function to print colored output print_status() { echo -e "${GREEN}[INFO]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } print_header() { echo -e "${BLUE}================================${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}================================${NC}" } # Function to show help show_help() { cat << 'EOF' apt-layer Installation Script This script installs the apt-layer tool, its dependencies, creates necessary directories and files, and sets up the system to use apt-layer. Usage: ./install-apt-layer.sh # Install or update apt-layer ./install-apt-layer.sh --uninstall # Remove apt-layer and all its files ./install-apt-layer.sh --reinstall # Remove and reinstall (reset to default state) ./install-apt-layer.sh --help # Show this help message What this script does: - Downloads the latest apt-layer.sh from the repository - Installs required dependencies (jq, dos2unix, etc.) - Creates necessary directories (/var/lib/apt-layer, /var/log/apt-layer, etc.) - Sets up configuration files - Makes apt-layer executable and available system-wide - Initializes the apt-layer system Dependencies: - curl or wget (for downloading) - jq (for JSON processing) - dos2unix (for Windows line ending conversion) - sudo (for system installation) EOF } # Function to check if running as root check_root() { if [[ $EUID -eq 0 ]]; then print_error "This script should not be run as root. Use sudo for specific commands." exit 1 fi } # Function to check dependencies check_dependencies() { print_status "Checking dependencies..." local missing_deps=() # Check for curl or wget if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then missing_deps+=("curl or wget") fi # Check for jq if ! command -v jq >/dev/null 2>&1; then missing_deps+=("jq") fi # Check for dos2unix if ! command -v dos2unix >/dev/null 2>&1; then missing_deps+=("dos2unix") fi if [[ ${#missing_deps[@]} -gt 0 ]]; then print_error "Missing required dependencies: ${missing_deps[*]}" print_status "Installing missing dependencies..." # Try to install dependencies if command -v apt-get >/dev/null 2>&1; then sudo apt-get update sudo apt-get install -y "${missing_deps[@]}" elif command -v dnf >/dev/null 2>&1; then sudo dnf install -y "${missing_deps[@]}" elif command -v yum >/dev/null 2>&1; then sudo yum install -y "${missing_deps[@]}" else print_error "Could not automatically install dependencies. Please install manually:" print_error " ${missing_deps[*]}" exit 1 fi fi print_success "All dependencies satisfied" } # Function to download apt-layer download_apt_layer() { print_status "Downloading apt-layer..." local download_url="https://git.raines.xyz/robojerk/particle-os-tools/raw/branch/main/apt-layer.sh" local temp_file="/tmp/apt-layer.sh" # Download using curl or wget if command -v curl >/dev/null 2>&1; then if curl -L -o "$temp_file" "$download_url"; then print_success "Downloaded apt-layer using curl" else print_error "Failed to download apt-layer using curl" return 1 fi elif command -v wget >/dev/null 2>&1; then if wget -O "$temp_file" "$download_url"; then print_success "Downloaded apt-layer using wget" else print_error "Failed to download apt-layer using wget" return 1 fi else print_error "No download tool available (curl or wget)" return 1 fi # Verify the downloaded file if [[ ! -f "$temp_file" ]] || [[ ! -s "$temp_file" ]]; then print_error "Downloaded file is empty or missing" return 1 fi # Convert line endings if needed if command -v dos2unix >/dev/null 2>&1; then dos2unix "$temp_file" 2>/dev/null || true fi # Make executable chmod +x "$temp_file" print_success "apt-layer downloaded and prepared" } # Function to install apt-layer install_apt_layer() { print_status "Installing apt-layer..." local temp_file="/tmp/apt-layer.sh" local install_dir="/usr/local/bin" local config_dir="/usr/local/etc/apt-layer" # Create installation directory if it doesn't exist sudo mkdir -p "$install_dir" # Install apt-layer sudo cp "$temp_file" "$install_dir/apt-layer" sudo chmod +x "$install_dir/apt-layer" # Create configuration directory sudo mkdir -p "$config_dir" # Create paths.json configuration sudo tee "$config_dir/paths.json" >/dev/null << 'EOF' { "apt_layer_paths": { "description": "apt-layer system path configuration", "version": "1.0", "main_directories": { "workspace": { "path": "/var/lib/apt-layer", "description": "Main apt-layer workspace directory", "permissions": "755", "owner": "root:root" }, "logs": { "path": "/var/log/apt-layer", "description": "apt-layer log files directory", "permissions": "755", "owner": "root:root" }, "cache": { "path": "/var/cache/apt-layer", "description": "apt-layer cache directory", "permissions": "755", "owner": "root:root" } }, "workspace_subdirectories": { "build": { "path": "/var/lib/apt-layer/build", "description": "Build artifacts and temporary files", "permissions": "755", "owner": "root:root" }, "live_overlay": { "path": "/var/lib/apt-layer/live-overlay", "description": "Live overlay system for temporary changes", "permissions": "755", "owner": "root:root" }, "composefs": { "path": "/var/lib/apt-layer/composefs", "description": "ComposeFS layers and metadata", "permissions": "755", "owner": "root:root" }, "ostree_commits": { "path": "/var/lib/apt-layer/ostree-commits", "description": "OSTree commit history and metadata", "permissions": "755", "owner": "root:root" }, "deployments": { "path": "/var/lib/apt-layer/deployments", "description": "Deployment directories and state", "permissions": "755", "owner": "root:root" }, "history": { "path": "/var/lib/apt-layer/history", "description": "Deployment history and rollback data", "permissions": "755", "owner": "root:root" }, "bootloader": { "path": "/var/lib/apt-layer/bootloader", "description": "Bootloader state and configuration", "permissions": "755", "owner": "root:root" }, "transaction_state": { "path": "/var/lib/apt-layer/transaction-state", "description": "Transaction state and temporary data", "permissions": "755", "owner": "root:root" } }, "files": { "deployment_db": { "path": "/var/lib/apt-layer/deployments.json", "description": "Deployment database file", "permissions": "644", "owner": "root:root" }, "current_deployment": { "path": "/var/lib/apt-layer/current-deployment", "description": "Current deployment identifier file", "permissions": "644", "owner": "root:root" }, "pending_deployment": { "path": "/var/lib/apt-layer/pending-deployment", "description": "Pending deployment identifier file", "permissions": "644", "owner": "root:root" }, "transaction_log": { "path": "/var/lib/apt-layer/transaction.log", "description": "Transaction log file", "permissions": "644", "owner": "root:root" } }, "fallback_paths": { "description": "Fallback paths for different environments", "wsl": { "workspace": "/mnt/wsl/apt-layer", "logs": "/mnt/wsl/apt-layer/logs", "cache": "/mnt/wsl/apt-layer/cache" }, "container": { "workspace": "/tmp/apt-layer", "logs": "/tmp/apt-layer/logs", "cache": "/tmp/apt-layer/cache" }, "test": { "workspace": "/tmp/apt-layer-test", "logs": "/tmp/apt-layer-test/logs", "cache": "/tmp/apt-layer-test/cache" } }, "environment_variables": { "description": "Environment variable mappings", "APT_LAYER_WORKSPACE": "workspace", "APT_LAYER_LOG_DIR": "logs", "APT_LAYER_CACHE_DIR": "cache", "BUILD_DIR": "workspace_subdirectories.build", "LIVE_OVERLAY_DIR": "workspace_subdirectories.live_overlay", "COMPOSEFS_DIR": "workspace_subdirectories.composefs", "OSTREE_COMMITS_DIR": "workspace_subdirectories.ostree_commits", "DEPLOYMENTS_DIR": "workspace_subdirectories.deployments", "HISTORY_DIR": "workspace_subdirectories.history", "BOOTLOADER_STATE_DIR": "workspace_subdirectories.bootloader", "TRANSACTION_STATE": "workspace_subdirectories.transaction_state", "DEPLOYMENT_DB": "files.deployment_db", "CURRENT_DEPLOYMENT_FILE": "files.current_deployment", "PENDING_DEPLOYMENT_FILE": "files.pending_deployment", "TRANSACTION_LOG": "files.transaction_log" } } } EOF # Set proper permissions sudo chmod 644 "$config_dir/paths.json" # Initialize apt-layer system print_status "Initializing apt-layer system..." if sudo apt-layer --init; then print_success "apt-layer system initialized" else print_warning "apt-layer system initialization failed, but installation completed" fi # Clean up temporary file rm -f "$temp_file" print_success "apt-layer installed successfully" print_status "You can now use 'apt-layer --help' to see available commands" } # Function to uninstall apt-layer uninstall_apt_layer() { print_status "Uninstalling apt-layer..." local install_dir="/usr/local/bin" local config_dir="/usr/local/etc/apt-layer" # Remove apt-layer binary if [[ -f "$install_dir/apt-layer" ]]; then sudo rm -f "$install_dir/apt-layer" print_status "Removed apt-layer binary" fi # Remove configuration directory if [[ -d "$config_dir" ]]; then sudo rm -rf "$config_dir" print_status "Removed configuration directory" fi # Remove apt-layer directories (optional - ask user) if [[ -d "/var/lib/apt-layer" ]] || [[ -d "/var/log/apt-layer" ]] || [[ -d "/var/cache/apt-layer" ]]; then echo -e "${YELLOW}Do you want to remove all apt-layer data directories? (y/N)${NC}" read -r response if [[ "$response" =~ ^[Yy]$ ]]; then sudo rm -rf "/var/lib/apt-layer" "/var/log/apt-layer" "/var/cache/apt-layer" print_status "Removed all apt-layer data directories" else print_status "Keeping apt-layer data directories" fi fi print_success "apt-layer uninstalled successfully" } # Function to reinstall apt-layer reinstall_apt_layer() { print_status "Reinstalling apt-layer..." # Uninstall first uninstall_apt_layer # Install again install_apt_layer print_success "apt-layer reinstalled successfully" } # Function to check if apt-layer is installed is_apt_layer_installed() { command -v apt-layer >/dev/null 2>&1 } # Function to check if apt-layer is up to date check_for_updates() { print_status "Checking for updates..." if ! is_apt_layer_installed; then return 0 # Not installed, so no update needed fi # For now, we'll always download the latest version # In the future, this could check version numbers or timestamps return 1 # Update needed } # Main installation function main_install() { print_header "apt-layer Installation" # Check if running as root check_root # Check dependencies check_dependencies # Check if already installed if is_apt_layer_installed; then print_status "apt-layer is already installed" if check_for_updates; then print_status "apt-layer is up to date" return 0 else print_status "Updating apt-layer..." fi else print_status "Installing apt-layer..." fi # Download and install if download_apt_layer && install_apt_layer; then print_success "apt-layer installation completed successfully" print_status "You can now use 'apt-layer --help' to see available commands" return 0 else print_error "apt-layer installation failed" return 1 fi } # Main function main() { case "${1:-}" in --help|-h) show_help exit 0 ;; --uninstall) print_header "apt-layer Uninstallation" uninstall_apt_layer exit 0 ;; --reinstall) print_header "apt-layer Reinstallation" reinstall_apt_layer exit 0 ;; "") main_install exit $? ;; *) print_error "Unknown option: $1" show_help exit 1 ;; esac } # Run main function with all arguments main "$@"