#!/bin/bash # Configuration IMAGE_NAME="markdown-blog" CONTAINER_NAME="markdown-blog-container" PORT=8080 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MARKDOWN_DIR="$SCRIPT_DIR" # Use the script's directory as the default markdown directory # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Function to check if Docker is running check_docker() { if ! docker info > /dev/null 2>&1; then echo -e "${RED}Error: Docker is not running. Please start Docker and try again.${NC}" exit 1 fi } # Function to check if container exists container_exists() { docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" } # Function to check if container is running container_running() { docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" } # Function to check container health check_container_health() { local health_status health_status=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null) if [ "$health_status" = "healthy" ]; then return 0 else return 1 fi } # Fun spinner and jokes for npm build (right-aligned, rainbow) npm_spinner_right() { local pid=$1 local delay=0.15 local spinstr='|/-\\' local jokes=( "NPM is downloading the entire internet..." "TypeScript: It's like JavaScript, but with more errors!" "JavaScript: Where '1' + 1 = '11'!" "NPM: Installing 1000 dependencies for 'hello world'..." "TypeScript: Making JavaScript developers feel safe (sometimes)." ) local colors=(31 33 32 36 34 35) # Red, Yellow, Green, Cyan, Blue, Magenta local joke_index=0 tput civis # Hide cursor while kill -0 "$pid" 2>/dev/null; do local temp="${spinstr#?}" local cols=$(tput cols) local msg="[%c] %s" local joke="${jokes[$joke_index]}" local out printf -v out "$msg" "$spinstr" "$joke" local pad=$((cols - ${#out} - 1)) [ $pad -lt 0 ] && pad=0 # Rainbow coloring local rainbow="" local i=0 local len=${#out} while [ $i -lt $len ]; do local c="${out:$i:1}" local color=${colors[$((i % ${#colors[@]}))]} rainbow+="\033[${color}m$c\033[0m" i=$((i+1)) done printf "\r%*s%s" $pad "" "$rainbow" spinstr=$temp${spinstr%$temp} sleep $delay joke_index=$(( (joke_index + 1) % ${#jokes[@]} )) done printf "\r" tput cnorm # Restore cursor } # Function to build the Docker image (show spinner/jokes only during npm ci) build_image() { echo -e "${YELLOW}Building Docker image...${NC}" local pipe=$(mktemp -u) mkfifo "$pipe" (docker build -t "$IMAGE_NAME" . | tee "$pipe") & build_pid=$! while read -r line; do echo "$line" if [[ "$line" == *"RUN npm ci"* ]]; then sleep 1 npm_spinner_right "$build_pid" & spinner_pid=$! wait "$build_pid" kill "$spinner_pid" 2>/dev/null break fi done < "$pipe" wait "$build_pid" rm -f "$pipe" if [ $? -ne 0 ]; then echo -e "${RED}Error: Failed to build Docker image. Check logs above.${NC}" exit 1 fi echo -e "${GREEN}Docker image built successfully!${NC}" } # Function to start the container start_container() { echo -e "${YELLOW}Starting container...${NC}" if container_exists; then if container_running; then echo -e "${YELLOW}Container is already running.${NC}" return else echo -e "${YELLOW}Restarting existing container...${NC}" docker start "$CONTAINER_NAME" || { echo -e "${RED}Error: Failed to start container.${NC}" exit 1 } fi else echo -e "${BLUE}Creating and starting new container...${NC}" docker run -d \ --name "$CONTAINER_NAME" \ -p "$PORT:8080" \ -v "$MARKDOWN_DIR:/markdown" \ --restart unless-stopped \ --health-cmd="curl -f http://localhost:8080/ || exit 1" \ --health-interval=30s \ --health-timeout=10s \ --health-retries=3 \ "$IMAGE_NAME" || { echo -e "${RED}Error: Failed to create container.${NC}" exit 1 } fi # Wait for container to be healthy echo -e "${YELLOW}Waiting for container to be ready...${NC}" local max_attempts=30 local attempt=1 while [ $attempt -le $max_attempts ]; do if check_container_health; then echo -e "${GREEN}Container is healthy! Access it at: http://localhost:$PORT${NC}" return fi printf "." sleep 1 attempt=$((attempt + 1)) done echo -e "${RED}Error: Container did not become healthy. Check logs with './manage_container.sh logs'.${NC}" exit 1 } # Function to stop the container stop_container() { echo -e "${YELLOW}Stopping container...${NC}" if ! container_exists; then echo -e "${YELLOW}Container does not exist.${NC}" return fi docker stop "$CONTAINER_NAME" || { echo -e "${RED}Error: Failed to stop container.${NC}" exit 1 } echo -e "${GREEN}Container stopped successfully.${NC}" } # Function to remove the container remove_container() { echo -e "${YELLOW}Removing container...${NC}" if ! container_exists; then echo -e "${YELLOW}Container does not exist.${NC}" return fi if container_running; then stop_container fi docker rm "$CONTAINER_NAME" || { echo -e "${RED}Error: Failed to remove container.${NC}" exit 1 } echo -e "${GREEN}Container removed successfully.${NC}" } # Function to restart the container restart_container() { echo -e "${YELLOW}Restarting container...${NC}" if ! container_exists; then echo -e "${YELLOW}Container does not exist. Starting new one...${NC}" start_container return fi docker restart "$CONTAINER_NAME" || { echo -e "${RED}Error: Failed to restart container.${NC}" exit 1 } echo -e "${GREEN}Container restarted successfully.${NC}" } # Function to view logs view_logs() { echo -e "${YELLOW}Viewing logs...${NC}" if ! container_exists; then echo -e "${RED}Error: Container does not exist.${NC}" exit 1 fi docker logs -f "$CONTAINER_NAME" } # Function to show container status show_status() { echo -e "${YELLOW}Container Status:${NC}" if ! container_exists; then echo -e "${RED}Container does not exist.${NC}" return fi if container_running; then local health_status health_status=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null) echo -e "${GREEN}Container is running.${NC}" echo -e "Health: ${health_status}" echo -e else echo -e "${YELLOW}Container exists but is not running${NC}" fi } # Function to auto-deploy: remove old container, build fresh image, start new container autodeploy() { echo -e "${YELLOW}Auto-deploying: remove old container, build fresh image, start new container...${NC}" remove_container echo -e "${YELLOW}Building Docker image (no cache)...${NC}" build_image start_container } # Check Docker is running before proceeding check_docker # Main script logic case "$1" in build) build_image ;; start) start_container ;; stop) stop_container ;; restart) restart_container ;; logs) view_logs ;; status) show_status ;; remove) remove_container ;; autodeploy) autodeploy ;; *) echo "Usage: $0 {build|start|stop|restart|logs|status|remove|autodeploy}" exit 1 ;; esac # Record script start time SCRIPT_START_TIME=$(date +%s) exit 0 # At the very end, print a marathon joke with elapsed time SCRIPT_END_TIME=$(date +%s) ELAPSED=$((SCRIPT_END_TIME - SCRIPT_START_TIME)) MIN=$((ELAPSED / 60)) SEC=$((ELAPSED % 60)) HOUR=$((ELAPSED / 3600)) DAY=$((ELAPSED / 86400)) if [ $ELAPSED -lt 60 ]; then TIME_STR="$ELAPSED seconds" elif [ $ELAPSED -lt 3600 ]; then TIME_STR="$MIN minutes, $SEC seconds" elif [ $ELAPSED -lt 86400 ]; then TIME_STR="$HOUR hours, $(( (ELAPSED % 3600) / 60 )) minutes" else TIME_STR="$DAY days, $(( (ELAPSED % 86400) / 3600 )) hours" fi JOKES=( "Marathon complete! NPM wasted: $TIME_STR." "Build finished! JavaScript has evolved $TIME_STR into a new framework." "Done! TypeScript found $TIME_STR worth of new types." "Success! NPM installed $TIME_STR of dependencies you'll never use." "Victory! You survived $TIME_STR of NPM's existential dread." ) JOKE_INDEX=$((RANDOM % ${#JOKES[@]})) echo -e "\n\033[1;32m${JOKES[$JOKE_INDEX]}\033[0m"