Files
markdownblog/manage_container.sh
2025-06-17 17:36:13 +02:00

312 lines
8.9 KiB
Bash
Executable File

#!/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"