300 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/bin/bash
 | 
						||
 | 
						||
# Smart container build script for Turmli Bar Calendar
 | 
						||
# Automatically detects architecture and chooses the best build strategy
 | 
						||
 | 
						||
set -e
 | 
						||
 | 
						||
# Colors for output
 | 
						||
RED='\033[0;31m'
 | 
						||
GREEN='\033[0;32m'
 | 
						||
YELLOW='\033[1;33m'
 | 
						||
BLUE='\033[0;34m'
 | 
						||
NC='\033[0m' # No Color
 | 
						||
 | 
						||
# Configuration
 | 
						||
IMAGE_NAME="${IMAGE_NAME:-turmli-calendar}"
 | 
						||
BUILD_TYPE=""
 | 
						||
RUNTIME=""
 | 
						||
 | 
						||
# Print functions
 | 
						||
print_error() {
 | 
						||
    echo -e "${RED}❌ $1${NC}"
 | 
						||
}
 | 
						||
 | 
						||
print_success() {
 | 
						||
    echo -e "${GREEN}✅ $1${NC}"
 | 
						||
}
 | 
						||
 | 
						||
print_info() {
 | 
						||
    echo -e "${BLUE}ℹ️  $1${NC}"
 | 
						||
}
 | 
						||
 | 
						||
print_warning() {
 | 
						||
    echo -e "${YELLOW}⚠️  $1${NC}"
 | 
						||
}
 | 
						||
 | 
						||
# Detect container runtime
 | 
						||
detect_runtime() {
 | 
						||
    if command -v podman &> /dev/null; then
 | 
						||
        RUNTIME="podman"
 | 
						||
        print_info "Using Podman"
 | 
						||
    elif command -v docker &> /dev/null; then
 | 
						||
        RUNTIME="docker"
 | 
						||
        print_info "Using Docker"
 | 
						||
    else
 | 
						||
        print_error "No container runtime found. Please install Podman or Docker."
 | 
						||
        exit 1
 | 
						||
    fi
 | 
						||
}
 | 
						||
 | 
						||
# Detect architecture and choose build strategy
 | 
						||
detect_architecture() {
 | 
						||
    ARCH=$(uname -m)
 | 
						||
    OS=$(uname -s)
 | 
						||
    
 | 
						||
    print_info "System: ${OS} ${ARCH}"
 | 
						||
    
 | 
						||
    case "${ARCH}" in
 | 
						||
        armv6l|armv7l)
 | 
						||
            print_info "ARM 32-bit detected (Raspberry Pi)"
 | 
						||
            BUILD_TYPE="arm"
 | 
						||
            ;;
 | 
						||
        aarch64|arm64)
 | 
						||
            print_info "ARM 64-bit detected"
 | 
						||
            BUILD_TYPE="arm"
 | 
						||
            ;;
 | 
						||
        x86_64|amd64)
 | 
						||
            print_info "x86_64 detected"
 | 
						||
            BUILD_TYPE="standard"
 | 
						||
            ;;
 | 
						||
        *)
 | 
						||
            print_warning "Unknown architecture: ${ARCH}"
 | 
						||
            BUILD_TYPE="standard"
 | 
						||
            ;;
 | 
						||
    esac
 | 
						||
}
 | 
						||
 | 
						||
# Check if we have enough memory for build
 | 
						||
check_memory() {
 | 
						||
    if [ -f /proc/meminfo ]; then
 | 
						||
        TOTAL_MEM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
 | 
						||
        TOTAL_MEM_MB=$((TOTAL_MEM / 1024))
 | 
						||
        
 | 
						||
        if [ $TOTAL_MEM_MB -lt 512 ]; then
 | 
						||
            print_warning "Low memory detected: ${TOTAL_MEM_MB}MB"
 | 
						||
            print_warning "Build may fail. Consider using pre-built images or increasing swap."
 | 
						||
            
 | 
						||
            # Check swap
 | 
						||
            SWAP=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
 | 
						||
            SWAP_MB=$((SWAP / 1024))
 | 
						||
            if [ $SWAP_MB -lt 1024 ]; then
 | 
						||
                print_warning "Swap is low: ${SWAP_MB}MB. Consider adding swap space:"
 | 
						||
                echo "  sudo dd if=/dev/zero of=/swapfile bs=1G count=2"
 | 
						||
                echo "  sudo mkswap /swapfile"
 | 
						||
                echo "  sudo swapon /swapfile"
 | 
						||
            fi
 | 
						||
        else
 | 
						||
            print_info "Memory: ${TOTAL_MEM_MB}MB"
 | 
						||
        fi
 | 
						||
    fi
 | 
						||
}
 | 
						||
 | 
						||
# Build for ARM architecture
 | 
						||
build_arm() {
 | 
						||
    print_info "Building for ARM architecture..."
 | 
						||
    
 | 
						||
    # Check which Dockerfile to use
 | 
						||
    if [ -f "Dockerfile.arm" ]; then
 | 
						||
        print_info "Using ARM-optimized Dockerfile"
 | 
						||
        DOCKERFILE="Dockerfile.arm"
 | 
						||
    else
 | 
						||
        print_warning "Dockerfile.arm not found, using standard Dockerfile"
 | 
						||
        print_warning "This may take longer and require more memory"
 | 
						||
        DOCKERFILE="Dockerfile"
 | 
						||
    fi
 | 
						||
    
 | 
						||
    # Check if requirements-arm.txt exists
 | 
						||
    if [ -f "requirements-arm.txt" ] && [ -f "Dockerfile.arm" ]; then
 | 
						||
        print_info "Using simplified requirements for ARM"
 | 
						||
    elif [ -f "requirements-arm.txt" ]; then
 | 
						||
        print_warning "Found requirements-arm.txt but no Dockerfile.arm"
 | 
						||
        print_info "Consider creating Dockerfile.arm for better ARM support"
 | 
						||
    fi
 | 
						||
    
 | 
						||
    # Build with limited parallelism on ARM to save memory
 | 
						||
    print_info "Building with limited parallelism to save memory..."
 | 
						||
    export CARGO_BUILD_JOBS=1
 | 
						||
    export MAKEFLAGS="-j1"
 | 
						||
    
 | 
						||
    ${RUNTIME} build \
 | 
						||
        --file "${DOCKERFILE}" \
 | 
						||
        --tag "${IMAGE_NAME}" \
 | 
						||
        --memory-swap -1 \
 | 
						||
        . || {
 | 
						||
        print_error "Build failed!"
 | 
						||
        print_info "Troubleshooting tips:"
 | 
						||
        echo "  1. Try increasing swap space"
 | 
						||
        echo "  2. Use Dockerfile.arm with requirements-arm.txt"
 | 
						||
        echo "  3. Build on a more powerful machine and transfer the image"
 | 
						||
        exit 1
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
# Build for standard architecture
 | 
						||
build_standard() {
 | 
						||
    print_info "Building for standard architecture..."
 | 
						||
    
 | 
						||
    # Choose Dockerfile
 | 
						||
    if [ "$RUNTIME" = "podman" ] && [ -f "Containerfile" ]; then
 | 
						||
        DOCKERFILE="Containerfile"
 | 
						||
    elif [ -f "Dockerfile" ]; then
 | 
						||
        DOCKERFILE="Dockerfile"
 | 
						||
    else
 | 
						||
        print_error "No Dockerfile found!"
 | 
						||
        exit 1
 | 
						||
    fi
 | 
						||
    
 | 
						||
    print_info "Using ${DOCKERFILE}"
 | 
						||
    
 | 
						||
    ${RUNTIME} build \
 | 
						||
        --file "${DOCKERFILE}" \
 | 
						||
        --tag "${IMAGE_NAME}" \
 | 
						||
        . || {
 | 
						||
        print_error "Build failed!"
 | 
						||
        exit 1
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
# Build with cache mount (if supported)
 | 
						||
build_with_cache() {
 | 
						||
    print_info "Attempting build with cache mount..."
 | 
						||
    
 | 
						||
    # Check if BuildKit is available (Docker) or if Podman supports cache mounts
 | 
						||
    if [ "$RUNTIME" = "docker" ]; then
 | 
						||
        export DOCKER_BUILDKIT=1
 | 
						||
        CACHE_OPT="--mount=type=cache,target=/root/.cache/pip"
 | 
						||
    elif [ "$RUNTIME" = "podman" ]; then
 | 
						||
        # Podman 4.1+ supports cache mounts
 | 
						||
        CACHE_OPT="--mount=type=cache,target=/root/.cache/pip"
 | 
						||
    else
 | 
						||
        CACHE_OPT=""
 | 
						||
    fi
 | 
						||
    
 | 
						||
    # Attempt build with cache
 | 
						||
    if [ -n "$CACHE_OPT" ]; then
 | 
						||
        print_info "Using build cache for faster rebuilds"
 | 
						||
    fi
 | 
						||
    
 | 
						||
    if [ "$BUILD_TYPE" = "arm" ]; then
 | 
						||
        build_arm
 | 
						||
    else
 | 
						||
        build_standard
 | 
						||
    fi
 | 
						||
}
 | 
						||
 | 
						||
# Clean build (no cache)
 | 
						||
clean_build() {
 | 
						||
    print_info "Performing clean build (no cache)..."
 | 
						||
    
 | 
						||
    ${RUNTIME} build \
 | 
						||
        --no-cache \
 | 
						||
        --file "${DOCKERFILE:-Dockerfile}" \
 | 
						||
        --tag "${IMAGE_NAME}" \
 | 
						||
        . || {
 | 
						||
        print_error "Build failed!"
 | 
						||
        exit 1
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
# Show build information
 | 
						||
show_info() {
 | 
						||
    echo -e "${BLUE}Build Configuration:${NC}"
 | 
						||
    echo "  Runtime: ${RUNTIME}"
 | 
						||
    echo "  Architecture: $(uname -m)"
 | 
						||
    echo "  Build Type: ${BUILD_TYPE}"
 | 
						||
    echo "  Image Name: ${IMAGE_NAME}"
 | 
						||
    
 | 
						||
    if [ "$BUILD_TYPE" = "arm" ]; then
 | 
						||
        echo ""
 | 
						||
        echo -e "${YELLOW}ARM Build Notes:${NC}"
 | 
						||
        echo "  - Uses simplified dependencies where possible"
 | 
						||
        echo "  - Avoids packages requiring Rust compilation"
 | 
						||
        echo "  - May have slightly reduced performance"
 | 
						||
        echo "  - Optimized for low memory usage"
 | 
						||
    fi
 | 
						||
    
 | 
						||
    echo ""
 | 
						||
    print_info "Checking available Dockerfiles..."
 | 
						||
    for file in Dockerfile Containerfile Dockerfile.arm; do
 | 
						||
        if [ -f "$file" ]; then
 | 
						||
            print_success "$file found"
 | 
						||
        fi
 | 
						||
    done
 | 
						||
    
 | 
						||
    echo ""
 | 
						||
    print_info "Checking requirements files..."
 | 
						||
    for file in requirements.txt requirements-arm.txt; do
 | 
						||
        if [ -f "$file" ]; then
 | 
						||
            print_success "$file found"
 | 
						||
        fi
 | 
						||
    done
 | 
						||
}
 | 
						||
 | 
						||
# Main function
 | 
						||
main() {
 | 
						||
    case "${1:-}" in
 | 
						||
        --clean)
 | 
						||
            detect_runtime
 | 
						||
            detect_architecture
 | 
						||
            clean_build
 | 
						||
            ;;
 | 
						||
        --info)
 | 
						||
            detect_runtime
 | 
						||
            detect_architecture
 | 
						||
            check_memory
 | 
						||
            show_info
 | 
						||
            ;;
 | 
						||
        --help)
 | 
						||
            echo "Smart Container Build Script for Turmli Bar Calendar"
 | 
						||
            echo ""
 | 
						||
            echo "Usage: $0 [OPTIONS]"
 | 
						||
            echo ""
 | 
						||
            echo "Options:"
 | 
						||
            echo "  --clean   Perform a clean build (no cache)"
 | 
						||
            echo "  --info    Show build configuration and system info"
 | 
						||
            echo "  --help    Show this help message"
 | 
						||
            echo ""
 | 
						||
            echo "Environment Variables:"
 | 
						||
            echo "  IMAGE_NAME    Name for the built image (default: turmli-calendar)"
 | 
						||
            echo ""
 | 
						||
            echo "The script automatically detects:"
 | 
						||
            echo "  - Container runtime (Podman/Docker)"
 | 
						||
            echo "  - System architecture (ARM/x86_64)"
 | 
						||
            echo "  - Available memory"
 | 
						||
            echo "  - Best Dockerfile to use"
 | 
						||
            ;;
 | 
						||
        *)
 | 
						||
            detect_runtime
 | 
						||
            detect_architecture
 | 
						||
            check_memory
 | 
						||
            
 | 
						||
            print_info "Starting build process..."
 | 
						||
            
 | 
						||
            if [ "$BUILD_TYPE" = "arm" ]; then
 | 
						||
                build_arm
 | 
						||
            else
 | 
						||
                build_standard
 | 
						||
            fi
 | 
						||
            
 | 
						||
            if [ $? -eq 0 ]; then
 | 
						||
                print_success "Build completed successfully!"
 | 
						||
                print_info "Image: ${IMAGE_NAME}"
 | 
						||
                print_info "Run with: ${RUNTIME} run -d -p 8000:8000 ${IMAGE_NAME}"
 | 
						||
            fi
 | 
						||
            ;;
 | 
						||
    esac
 | 
						||
}
 | 
						||
 | 
						||
# Run main function
 | 
						||
main "$@" |