240 lines
6.7 KiB
Bash
Executable File
240 lines
6.7 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Fix script for Raspberry Pi installation issues
|
||
# Specifically handles the "No space left on device" error during pip install
|
||
|
||
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_header() {
|
||
echo
|
||
echo -e "${BLUE}════════════════════════════════════════════════${NC}"
|
||
echo -e "${BLUE} Turmli Calendar - Installation Fix for RPi${NC}"
|
||
echo -e "${BLUE}════════════════════════════════════════════════${NC}"
|
||
echo
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓${NC} $1"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗${NC} $1"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠${NC} $1"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ${NC} $1"
|
||
}
|
||
|
||
# Configuration
|
||
APP_DIR="/opt/turmli-calendar"
|
||
APP_USER="pi"
|
||
|
||
print_header
|
||
|
||
# Check if running as root
|
||
if [[ $EUID -ne 0 ]]; then
|
||
print_error "This script must be run as root (use sudo)"
|
||
exit 1
|
||
fi
|
||
|
||
# Step 1: Clean up temporary files
|
||
print_info "Cleaning up temporary files..."
|
||
rm -rf /tmp/pip-*
|
||
rm -rf /tmp/tmp*
|
||
apt-get clean
|
||
apt-get autoremove -y
|
||
print_success "Temporary files cleaned"
|
||
|
||
# Step 2: Check available space
|
||
print_info "Checking available space..."
|
||
echo "Disk usage:"
|
||
df -h / /tmp /opt
|
||
echo
|
||
|
||
# Step 3: Create alternative temp directory
|
||
print_info "Creating alternative temp directory..."
|
||
CUSTOM_TEMP="$APP_DIR/tmp"
|
||
mkdir -p "$CUSTOM_TEMP"
|
||
chown ${APP_USER}:${APP_USER} "$CUSTOM_TEMP"
|
||
print_success "Temp directory created at $CUSTOM_TEMP"
|
||
|
||
# Step 4: Create optimized requirements file
|
||
print_info "Creating optimized requirements file..."
|
||
cat > "$APP_DIR/requirements-rpi.txt" << 'EOF'
|
||
# Optimized requirements for Raspberry Pi
|
||
# Avoids packages that require compilation
|
||
|
||
fastapi>=0.104.0
|
||
# Use uvicorn without extras to avoid watchfiles compilation
|
||
uvicorn>=0.24.0
|
||
httpx>=0.25.0
|
||
icalendar>=5.0.0
|
||
jinja2>=3.1.0
|
||
python-multipart>=0.0.6
|
||
apscheduler>=3.10.0
|
||
pytz>=2023.3
|
||
|
||
# These are the problematic packages we're excluding:
|
||
# - watchfiles (requires Rust compilation)
|
||
# - websockets with speedups
|
||
# - httptools (requires C compilation)
|
||
# - python-dotenv (not needed for production)
|
||
# - uvloop (requires C compilation)
|
||
EOF
|
||
print_success "Optimized requirements file created"
|
||
|
||
# Step 5: Install Python packages with custom temp directory
|
||
print_info "Installing Python dependencies..."
|
||
print_warning "This may take 10-20 minutes on Raspberry Pi Zero"
|
||
|
||
# First, upgrade pip and basic tools
|
||
sudo -u ${APP_USER} TMPDIR="$CUSTOM_TEMP" "$APP_DIR/venv/bin/pip" install \
|
||
--no-cache-dir \
|
||
--upgrade pip wheel setuptools
|
||
|
||
# Install packages one by one to handle failures better
|
||
PACKAGES=(
|
||
"fastapi>=0.104.0"
|
||
"uvicorn>=0.24.0"
|
||
"httpx>=0.25.0"
|
||
"icalendar>=5.0.0"
|
||
"jinja2>=3.1.0"
|
||
"python-multipart>=0.0.6"
|
||
"apscheduler>=3.10.0"
|
||
"pytz>=2023.3"
|
||
)
|
||
|
||
for package in "${PACKAGES[@]}"; do
|
||
print_info "Installing $package..."
|
||
sudo -u ${APP_USER} TMPDIR="$CUSTOM_TEMP" "$APP_DIR/venv/bin/pip" install \
|
||
--no-cache-dir \
|
||
--prefer-binary \
|
||
--no-build-isolation \
|
||
"$package" || {
|
||
print_warning "Failed to install $package, trying without isolation..."
|
||
sudo -u ${APP_USER} TMPDIR="$CUSTOM_TEMP" "$APP_DIR/venv/bin/pip" install \
|
||
--no-cache-dir \
|
||
--no-deps \
|
||
"$package" || print_error "Failed to install $package"
|
||
}
|
||
done
|
||
|
||
print_success "Dependencies installed"
|
||
|
||
# Step 6: Clean up
|
||
print_info "Cleaning up..."
|
||
rm -rf "$CUSTOM_TEMP"
|
||
print_success "Cleanup complete"
|
||
|
||
# Step 7: Test the installation
|
||
print_info "Testing Python installation..."
|
||
if sudo -u ${APP_USER} "$APP_DIR/venv/bin/python" -c "import fastapi, uvicorn, httpx, icalendar, jinja2, apscheduler, pytz; print('All modules imported successfully')"; then
|
||
print_success "All required Python modules are installed"
|
||
else
|
||
print_error "Some modules failed to import"
|
||
exit 1
|
||
fi
|
||
|
||
# Step 8: Create a test script
|
||
print_info "Creating test script..."
|
||
cat > "$APP_DIR/test_import.py" << 'EOF'
|
||
#!/usr/bin/env python3
|
||
import sys
|
||
print("Python version:", sys.version)
|
||
print("\nTrying to import modules...")
|
||
|
||
try:
|
||
import fastapi
|
||
print("✓ fastapi:", fastapi.__version__)
|
||
except ImportError as e:
|
||
print("✗ fastapi:", e)
|
||
|
||
try:
|
||
import uvicorn
|
||
print("✓ uvicorn:", uvicorn.__version__)
|
||
except ImportError as e:
|
||
print("✗ uvicorn:", e)
|
||
|
||
try:
|
||
import httpx
|
||
print("✓ httpx:", httpx.__version__)
|
||
except ImportError as e:
|
||
print("✗ httpx:", e)
|
||
|
||
try:
|
||
import icalendar
|
||
print("✓ icalendar:", icalendar.__version__)
|
||
except ImportError as e:
|
||
print("✗ icalendar:", e)
|
||
|
||
try:
|
||
import jinja2
|
||
print("✓ jinja2:", jinja2.__version__)
|
||
except ImportError as e:
|
||
print("✗ jinja2:", e)
|
||
|
||
try:
|
||
import apscheduler
|
||
print("✓ apscheduler:", apscheduler.__version__)
|
||
except ImportError as e:
|
||
print("✗ apscheduler:", e)
|
||
|
||
try:
|
||
import pytz
|
||
print("✓ pytz:", pytz.__version__)
|
||
except ImportError as e:
|
||
print("✗ pytz:", e)
|
||
|
||
print("\nAll critical modules checked!")
|
||
EOF
|
||
|
||
chmod +x "$APP_DIR/test_import.py"
|
||
print_success "Test script created"
|
||
|
||
# Step 9: Run the test
|
||
print_info "Running import test..."
|
||
sudo -u ${APP_USER} "$APP_DIR/venv/bin/python" "$APP_DIR/test_import.py"
|
||
|
||
# Step 10: Try to start the application
|
||
print_info "Attempting to start the application..."
|
||
cd "$APP_DIR"
|
||
|
||
# Test if the application can start
|
||
timeout 10 sudo -u ${APP_USER} "$APP_DIR/venv/bin/python" -m uvicorn main:app --host 0.0.0.0 --port 8000 &
|
||
PID=$!
|
||
sleep 5
|
||
|
||
if kill -0 $PID 2>/dev/null; then
|
||
print_success "Application started successfully!"
|
||
kill $PID
|
||
else
|
||
print_warning "Application may have issues starting"
|
||
fi
|
||
|
||
# Final summary
|
||
echo
|
||
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
|
||
echo -e "${GREEN} Installation Fix Complete!${NC}"
|
||
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
|
||
echo
|
||
print_info "Next steps:"
|
||
print_info "1. Start the service: sudo systemctl start turmli-calendar"
|
||
print_info "2. Check status: sudo systemctl status turmli-calendar"
|
||
print_info "3. View logs: sudo journalctl -u turmli-calendar -f"
|
||
echo
|
||
print_info "If you still have issues, try:"
|
||
print_info "1. Increase swap: sudo nano /etc/dphys-swapfile (set CONF_SWAPSIZE=512)"
|
||
print_info "2. Reboot: sudo reboot"
|
||
print_info "3. Manual test: cd $APP_DIR && sudo -u pi ./venv/bin/python main.py"
|
||
echo |