#!/usr/bin/env bash # Configure Chinese mirrors if USE_CHINA_MIRRORS is set configure_china_mirrors() { if [[ "$USE_CHINA_MIRRORS" == "1" || "${USE_CHINA_MIRRORS,,}" == "true" ]]; then echo "Configuring Chinese mirrors for apt and pip..." # Replace Ubuntu sources if [[ -f /etc/apt/sources.list.d/ubuntu.sources ]]; then sudo sed -i 's|http://archive.ubuntu.com/ubuntu/|https://mirrors.tuna.tsinghua.edu.cn/ubuntu/|g' /etc/apt/sources.list.d/ubuntu.sources sudo sed -i 's|http://security.ubuntu.com/ubuntu/|https://mirrors.tuna.tsinghua.edu.cn/ubuntu/|g' /etc/apt/sources.list.d/ubuntu.sources echo "Updated Ubuntu apt sources to use Chinese mirrors" fi # Configure npm registry to use Chinese mirror (npmmirror.com is the recommended mirror) if command -v npm &> /dev/null; then npm config set registry https://registry.npmmirror.com/ echo "Configured npm registry to use Chinese mirror (registry.npmmirror.com)" fi # Also set system-wide npm config for all users sudo mkdir -p /etc/npm echo "registry=https://registry.npmmirror.com/" | sudo tee /etc/npm/npmrc > /dev/null # Set for root user as well (for when npm is installed later) sudo mkdir -p /root/.npm echo "registry=https://registry.npmmirror.com/" | sudo tee /root/.npmrc > /dev/null echo "Configured npm registry to use Chinese mirror (registry.npmmirror.com)" # Configure pip to use Chinese mirrors sudo mkdir -p /etc/pip echo "[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = pypi.tuna.tsinghua.edu.cn" | sudo tee /etc/pip/pip.conf > /dev/null echo "Configured pip to use Chinese mirrors" echo "Chinese mirrors configuration completed" fi } # Run mirror configuration early, before any apt/pip operations configure_china_mirrors if [[ "$UPDATE_APT" == "1" || "${UPDATE_APT,,}" == "true" ]]; then # Gracefully update package lists if network is available echo "Checking network connectivity..." if ping -c 1 -W 5 8.8.8.8 >/dev/null 2>&1 || ping -c 1 -W 5 1.1.1.1 >/dev/null 2>&1; then echo "Network detected, refreshing package lists..." if sudo apt update; then echo "Package lists updated successfully" else echo "Warning: apt update failed despite network connectivity" echo "Falling back to cached package lists" fi else echo "No network connectivity detected, using cached package lists" fi fi # Global variables to track background processes TAIL_PID="" INIT_PID="" term_handler() { echo "Received termination signal (PID: $$), cleaning up..." # First run user-defined exit commands (may gracefully shut down processes) if [[ -n "$COMMAND_EXIT" ]]; then echo "Running legacy COMMAND_EXIT..." eval "$COMMAND_EXIT" fi # Then run numbered COMMAND_EXIT variables in order for i in {01..99}; do var_name="COMMAND_EXIT$i" var_value="${!var_name}" if [[ -n "$var_value" ]]; then echo "Running $var_name..." eval "$var_value" fi done # Kill any still-running background processes if they didn't shut down gracefully if [[ -n "$INIT_PID" ]]; then if kill -0 "$INIT_PID" 2>/dev/null; then echo "Init process still running, force killing: $INIT_PID" kill "$INIT_PID" 2>/dev/null else echo "Init process already terminated gracefully" fi fi # Kill the tail process if it's running if [[ -n "$TAIL_PID" ]]; then echo "Killing tail process: $TAIL_PID" kill "$TAIL_PID" 2>/dev/null fi # Stop SSH service echo "Stopping SSH service..." sudo service ssh stop 2>/dev/null || true echo "Cleanup completed, exiting..." exit 0 } # Debug: Show our PID and signal handling setup echo "Entrypoint script starting with PID: $$" echo "Setting up signal handlers..." # Setup signal handlers for graceful shutdown trap 'term_handler' SIGTERM SIGINT SIGQUIT # Test signal handling is working echo "Signal handlers registered. Testing with kill -0..." # setup home directory for the current user. It is useful for attaching vscode with container. user_name=$(whoami) user_home="/home/$user_name" sudo mkdir -p "$user_home" sudo chown -R "$(id -u):$(id -g)" "$user_home" cp -r /etc/skel/. "$user_home" 2>/dev/null || true if [[ $LOG_FILE != "/dev/null" ]]; then sudo touch "$LOG_FILE" sudo chown -R "$(id -u):$(id -g)" "$LOG_FILE" fi echo "Starting SSH service..." sudo service ssh start # Run initialization commands (last one in background to allow signal handling) # First collect all defined COMMAND_INIT variables init_commands=() if [[ -n "$COMMAND_INIT" ]]; then init_commands+=("COMMAND_INIT") fi for i in {01..99}; do var_name="COMMAND_INIT$i" if [[ -n "${!var_name}" ]]; then init_commands+=("$var_name") fi done # Execute them: all synchronously except the last one for ((i=0; i<${#init_commands[@]}; i++)); do var_name="${init_commands[i]}" var_value="${!var_name}" if [[ $i -eq $((${#init_commands[@]} - 1)) ]]; then # Last command - run in background to avoid blocking signals echo "Running $var_name (final command) in background..." eval "$var_value" & INIT_PID=$! echo "Background process started with PID: $INIT_PID" else # Not last - run synchronously to preserve expected behavior echo "Running $var_name..." eval "$var_value" fi done # Start the main process loop if [[ $LOG_FILE == "/dev/null" ]]; then # If no log file, just wait for signals echo "Container ready, waiting for signals..." while true; do sleep 1 & wait $! || break done else # If log file specified, tail it echo "Container ready, tailing log file: $LOG_FILE" tail -f "$LOG_FILE" & TAIL_PID=$! # Wait for the tail process or signals, but make it interruptible while kill -0 $TAIL_PID 2>/dev/null; do sleep 1 & wait $! || break done fi # This should never be reached, but if it is, exit gracefully echo "Main loop exited unexpectedly" exit 0