243 lines
8.4 KiB
Bash
Executable File
243 lines
8.4 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Fix script for Python/Pydantic compatibility issues on Raspberry Pi
|
||
# This script helps resolve the Python 3.13 / Pydantic v1 incompatibility
|
||
|
||
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
|
||
|
||
# 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
|
||
}
|
||
|
||
# Main fix process
|
||
main() {
|
||
print_info "Python/Pydantic Compatibility Fix Script"
|
||
print_info "========================================="
|
||
|
||
# Detect runtime
|
||
detect_runtime
|
||
|
||
# Check current situation
|
||
print_info "Checking current container status..."
|
||
if ${RUNTIME} ps -a --format '{{.Names}}' | grep -q "^turmli-calendar$"; then
|
||
print_warning "Found existing turmli-calendar container"
|
||
|
||
# Show current Python version if container is running
|
||
if ${RUNTIME} ps --format '{{.Names}}' | grep -q "^turmli-calendar$"; then
|
||
print_info "Checking Python version in running container..."
|
||
PYTHON_VERSION=$(${RUNTIME} exec turmli-calendar python --version 2>&1 || echo "Unable to determine")
|
||
print_info "Current Python version: ${PYTHON_VERSION}"
|
||
fi
|
||
fi
|
||
|
||
print_info ""
|
||
print_info "This script will fix the Python compatibility issue by:"
|
||
print_info "1. Stopping and removing the existing container"
|
||
print_info "2. Removing the old container image"
|
||
print_info "3. Building a new image with Python 3.11 and compatible packages"
|
||
print_info ""
|
||
|
||
read -p "Do you want to proceed? (y/N) " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
print_info "Operation cancelled"
|
||
exit 0
|
||
fi
|
||
|
||
# Step 1: Stop and remove existing container
|
||
print_info "Step 1: Cleaning up existing container..."
|
||
if ${RUNTIME} ps -a --format '{{.Names}}' | grep -q "^turmli-calendar$"; then
|
||
${RUNTIME} stop turmli-calendar 2>/dev/null || true
|
||
${RUNTIME} rm turmli-calendar 2>/dev/null || true
|
||
print_success "Container removed"
|
||
else
|
||
print_info "No existing container found"
|
||
fi
|
||
|
||
# Step 2: Remove old image
|
||
print_info "Step 2: Removing old container image..."
|
||
if ${RUNTIME} images --format '{{.Repository}}' | grep -q "^turmli-calendar$"; then
|
||
${RUNTIME} rmi turmli-calendar 2>/dev/null || true
|
||
print_success "Old image removed"
|
||
else
|
||
print_info "No existing image found"
|
||
fi
|
||
|
||
# Step 3: Detect architecture and select appropriate Dockerfile
|
||
ARCH=$(uname -m)
|
||
print_info "Step 3: Selecting appropriate Dockerfile for architecture: ${ARCH}"
|
||
|
||
if [[ "$ARCH" == "armv6l" ]]; then
|
||
# Raspberry Pi Zero
|
||
if [ -f "Dockerfile.pizero" ]; then
|
||
DOCKERFILE="Dockerfile.pizero"
|
||
print_info "Using Dockerfile.pizero (Python 3.11 with Pydantic v1)"
|
||
else
|
||
print_error "Dockerfile.pizero not found!"
|
||
exit 1
|
||
fi
|
||
elif [[ "$ARCH" == "armv7l" ]] || [[ "$ARCH" == "aarch64" ]]; then
|
||
# Newer Raspberry Pi models
|
||
if [ -f "Dockerfile.pizero-py312" ]; then
|
||
DOCKERFILE="Dockerfile.pizero-py312"
|
||
print_info "Using Dockerfile.pizero-py312 (Python 3.12 with Pydantic v2)"
|
||
elif [ -f "Dockerfile.pizero" ]; then
|
||
DOCKERFILE="Dockerfile.pizero"
|
||
print_info "Using Dockerfile.pizero (Python 3.11 with Pydantic v1)"
|
||
else
|
||
print_error "No suitable Dockerfile found!"
|
||
exit 1
|
||
fi
|
||
else
|
||
# Other architectures
|
||
if [ -f "Dockerfile.minimal" ]; then
|
||
DOCKERFILE="Dockerfile.minimal"
|
||
print_info "Using Dockerfile.minimal"
|
||
elif [ -f "Dockerfile" ]; then
|
||
DOCKERFILE="Dockerfile"
|
||
print_info "Using standard Dockerfile"
|
||
else
|
||
print_error "No Dockerfile found!"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# Step 4: Build new image
|
||
print_info "Step 4: Building new container image..."
|
||
print_info "This may take a few minutes, especially on Pi Zero..."
|
||
|
||
# Check available memory
|
||
TOTAL_MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||
TOTAL_MEM_MB=$((TOTAL_MEM_KB / 1024))
|
||
if [ $TOTAL_MEM_MB -lt 512 ]; then
|
||
print_warning "Low memory detected: ${TOTAL_MEM_MB}MB"
|
||
print_info "Build may be slow. Consider adding swap if it fails."
|
||
fi
|
||
|
||
# Build with no cache to ensure fresh build
|
||
if ${RUNTIME} build --no-cache --file "${DOCKERFILE}" --tag turmli-calendar . ; then
|
||
print_success "Image built successfully!"
|
||
else
|
||
print_error "Build failed!"
|
||
print_info ""
|
||
print_info "Troubleshooting tips:"
|
||
print_info "1. If you're on a Pi Zero with low memory, try adding swap:"
|
||
print_info " sudo dd if=/dev/zero of=/swapfile bs=1M count=1024"
|
||
print_info " sudo chmod 600 /swapfile"
|
||
print_info " sudo mkswap /swapfile"
|
||
print_info " sudo swapon /swapfile"
|
||
print_info ""
|
||
print_info "2. Try building with the minimal Dockerfile:"
|
||
print_info " ${RUNTIME} build --no-cache --file Dockerfile.minimal --tag turmli-calendar ."
|
||
print_info ""
|
||
print_info "3. Use a pre-built image (if available):"
|
||
print_info " ${RUNTIME} pull ghcr.io/yourusername/turmli-calendar:armv6"
|
||
exit 1
|
||
fi
|
||
|
||
# Step 5: Create cache file if needed
|
||
if [ ! -f "calendar_cache.json" ]; then
|
||
echo "{}" > calendar_cache.json
|
||
print_info "Created cache file"
|
||
fi
|
||
|
||
# Step 6: Run the new container
|
||
print_info "Step 5: Starting new container..."
|
||
|
||
# Try to run with SELinux labels first (Fedora/RHEL)
|
||
if ${RUNTIME} run -d \
|
||
--name turmli-calendar \
|
||
-p 8000:8000 \
|
||
-v $(pwd)/calendar_cache.json:/app/calendar_cache.json:Z \
|
||
-e TZ=Europe/Berlin \
|
||
--restart unless-stopped \
|
||
turmli-calendar 2>/dev/null; then
|
||
print_success "Container started with SELinux labels!"
|
||
else
|
||
# Retry without SELinux labels (Debian/Ubuntu/Raspbian)
|
||
if ${RUNTIME} run -d \
|
||
--name turmli-calendar \
|
||
-p 8000:8000 \
|
||
-v $(pwd)/calendar_cache.json:/app/calendar_cache.json \
|
||
-e TZ=Europe/Berlin \
|
||
--restart unless-stopped \
|
||
turmli-calendar; then
|
||
print_success "Container started!"
|
||
else
|
||
print_error "Failed to start container!"
|
||
print_info "Check logs with: ${RUNTIME} logs turmli-calendar"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# Step 7: Verify the fix
|
||
print_info "Step 6: Verifying the fix..."
|
||
sleep 3
|
||
|
||
# Check if container is running
|
||
if ${RUNTIME} ps --format '{{.Names}}' | grep -q "^turmli-calendar$"; then
|
||
print_success "Container is running!"
|
||
|
||
# Check Python version
|
||
PYTHON_VERSION=$(${RUNTIME} exec turmli-calendar python --version 2>&1)
|
||
print_info "Python version in container: ${PYTHON_VERSION}"
|
||
|
||
# Check if app is responding
|
||
if curl -s -f http://localhost:8000/api/events > /dev/null 2>&1; then
|
||
print_success "Application is responding!"
|
||
print_info ""
|
||
print_success "✨ Fix completed successfully! ✨"
|
||
print_info "Access your calendar at:"
|
||
print_info " http://$(hostname -I | awk '{print $1}'):8000"
|
||
print_info " http://localhost:8000"
|
||
else
|
||
print_warning "Application not responding yet, checking logs..."
|
||
${RUNTIME} logs --tail 10 turmli-calendar
|
||
print_info ""
|
||
print_info "The application may still be starting up."
|
||
print_info "Check full logs with: ${RUNTIME} logs -f turmli-calendar"
|
||
fi
|
||
else
|
||
print_error "Container failed to start!"
|
||
print_info "Checking logs..."
|
||
${RUNTIME} logs turmli-calendar
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# Run main function
|
||
main |