#!/bin/bash # Configuration IMAGE_NAME="markdown-blog" CONTAINER_NAME="markdown-blog-container" PORT=8080 # Automatically set MARKDOWN_DIR to the directory where this script lives 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' 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${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)." "NPM: 5 minutes left... just kidding!" "JavaScript: Because who needs types anyway?" "NPM: One does not simply 'npm install' without warnings." "TypeScript: The language that makes you write more code to do less." "NPM: 0 vulnerabilities (in your dreams)." ) local colors=(31 33 32 36 34 35 91 92 93 94 95 96) local joke_count=${#jokes[@]} local joke_index=0 tput civis 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) % joke_count )) done printf "\r" tput cnorm } # Function to build the Docker image (show spinner/jokes only during npm ci) build_image() { echo -e "${YELLOW}Building Docker image...${NC}" # Use a named pipe to capture docker build output local pipe=$(mktemp -u) mkfifo "$pipe" # Start docker build, redirect output to pipe (docker build -t $IMAGE_NAME . | tee "$pipe") & build_pid=$! # Watch the pipe for the npm ci step while read -r line; do echo "$line" if [[ "$line" == *"RUN npm ci"* ]]; then # Wait for the npm ci process to start in the background 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${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}" # Check if container already exists if container_exists; then if container_running; then echo -e "${YELLOW}Container is already running${NC}" return else echo -e "${YELLOW}Container exists but is not running. Starting it...${NC}" if ! docker start $CONTAINER_NAME; then echo -e "${RED}Error: Failed to start existing container${NC}" exit 1 fi fi else # Create and start new container if ! docker run -d \ --name $CONTAINER_NAME \ -p $PORT:8080 \ -v "$MARKDOWN_DIR:/markdown" \ --restart unless-stopped \ --health-cmd="wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1" \ --health-interval=30s \ --health-timeout=30s \ --health-retries=3 \ --health-start-period=5s \ $IMAGE_NAME; then echo -e "${RED}Error: Failed to create and start container${NC}" exit 1 fi fi # Wait for container to be ready echo -e "${YELLOW}Waiting for container to be ready...${NC}" local max_attempts=60 local attempt=1 while [ $attempt -le $max_attempts ]; do if check_container_health; then echo -e "${GREEN}Container is healthy and accessible at http://localhost:$PORT${NC}" return fi # Check if container is still running if ! container_running; then echo -e "${RED}Error: Container stopped unexpectedly${NC}" docker logs $CONTAINER_NAME exit 1 fi echo -n "." sleep 1 attempt=$((attempt + 1)) done echo -e "${RED}Error: Container did not become healthy in time${NC}" docker logs $CONTAINER_NAME 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 if ! docker stop $CONTAINER_NAME; then echo -e "${RED}Error: Failed to stop container${NC}" exit 1 fi 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 if ! docker rm $CONTAINER_NAME; then echo -e "${RED}Error: Failed to remove container${NC}" exit 1 fi 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 container...${NC}" start_container return fi if ! docker restart $CONTAINER_NAME; then echo -e "${RED}Error: Failed to restart container${NC}" exit 1 fi 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 "Health status: $health_status" echo "Access the application at: http://localhost:$PORT" 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"