#!/bin/bash # --- Configuration --- # IMPORTANT: Set this to the ABSOLUTE path of your Quartz project directory on the host QUARTZ_PROJECT_DIR="/home/hoid/projects/portfolio/quartz" # IMPORTANT: Set this to the ABSOLUTE path of the ACTUAL FOLDER in your Obsidian vault # that contains the Markdown files and assets for your Quartz site. # This is the SOURCE of your content. OBSIDIAN_CONTENT_SOURCE="/home/hoid/docker/obsidian/vaults/weeslahw_coppermind/Digital_Garden" # Directory name within your QUARTZ_PROJECT_DIR that Quartz uses for content # This is where the script will temporarily place the real content for the Docker build. # The Dockerfile's `COPY . .` will then pick this up. LOCAL_CONTENT_TARGET_DIR_NAME="content" # Timestamp file to track the last successful build's content state # This file will be created in the QUARTZ_PROJECT_DIR LAST_BUILD_TIMESTAMP_FILE=".last_build_content_timestamp" # Log file for this script's output (recommended when run by cron) LOG_FILE="${QUARTZ_PROJECT_DIR}/update_quartz_docker.log" # --- Script Logic --- # Function for logging log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] - $1" | tee -a "$LOG_FILE" } cd "$QUARTZ_PROJECT_DIR" || { log_message "FATAL: Failed to cd to project directory: ${QUARTZ_PROJECT_DIR}" exit 1 } log_message "--- Quartz Docker Update Script Started ---" # --- Change Detection --- NEEDS_REBUILD=false if [ ! -d "$OBSIDIAN_CONTENT_SOURCE" ]; then log_message "ERROR: Obsidian content source directory does not exist: ${OBSIDIAN_CONTENT_SOURCE}" NEEDS_REBUILD=false # Or set to true if you want to try building with an empty content dir elif [ ! -f "$LAST_BUILD_TIMESTAMP_FILE" ]; then log_message "No last build timestamp found at ${LAST_BUILD_TIMESTAMP_FILE}. Triggering initial rebuild." NEEDS_REBUILD=true else # Efficiently check if any file within OBSIDIAN_CONTENT_SOURCE is newer than the timestamp file if find "$OBSIDIAN_CONTENT_SOURCE" -type f -newer "$LAST_BUILD_TIMESTAMP_FILE" -print -quit | grep -q .; then log_message "Changes detected in Obsidian content directory (${OBSIDIAN_CONTENT_SOURCE}) since last build. Triggering rebuild." NEEDS_REBUILD=true else log_message "No changes detected in Obsidian content directory since last build." fi fi if [ "$NEEDS_REBUILD" = false ]; then log_message "Skipping Docker rebuild and deploy." log_message "--- Script Finished (No Changes) ---" exit 0 fi # --- Prepare Content for Docker Build --- LOCAL_CONTENT_FULL_PATH="${QUARTZ_PROJECT_DIR}/${LOCAL_CONTENT_TARGET_DIR_NAME}" log_message "Preparing content directory: ${LOCAL_CONTENT_FULL_PATH}" # Remove existing local content directory/symlink in project dir (if any) if [ -L "${LOCAL_CONTENT_FULL_PATH}" ] || [ -d "${LOCAL_CONTENT_FULL_PATH}" ]; then log_message "Removing existing ./${LOCAL_CONTENT_TARGET_DIR_NAME}" rm -rf "${LOCAL_CONTENT_FULL_PATH}" fi log_message "Creating new ./${LOCAL_CONTENT_TARGET_DIR_NAME} directory" mkdir "${LOCAL_CONTENT_FULL_PATH}" if [ $? -ne 0 ]; then log_message "ERROR: Failed to create local content directory: ${LOCAL_CONTENT_FULL_PATH}" log_message "--- Script Finished (Error) ---" exit 1 fi log_message "Copying content from ${OBSIDIAN_CONTENT_SOURCE} to ${LOCAL_CONTENT_FULL_PATH}" # Using rsync for efficient copying; ensure it's installed (sudo apt install rsync) # The trailing slash on OBSIDIAN_CONTENT_SOURCE/ is important for rsync rsync -a --delete "${OBSIDIAN_CONTENT_SOURCE}/" "${LOCAL_CONTENT_FULL_PATH}/" if [ $? -ne 0 ]; then log_message "ERROR: Failed to copy content from Obsidian source to local content directory." log_message "--- Script Finished (Error) ---" exit 1 fi log_message "Content prepared successfully for Docker build." # --- Docker Build & Deploy using Docker Compose --- # Use absolute path for docker-compose for robustness in cron DOCKER_COMPOSE_CMD="/usr/local/bin/docker-compose" log_message "Tearing down existing Docker Compose services (if any) for a clean deployment..." # Create a temporary file to capture output from 'docker-compose down' COMPOSE_DOWN_OUTPUT_FILE="${QUARTZ_PROJECT_DIR}/compose_down_output.tmp" # Execute 'docker-compose down' and capture all its output $DOCKER_COMPOSE_CMD down --remove-orphans --volumes > "$COMPOSE_DOWN_OUTPUT_FILE" 2>&1 DOWN_EXIT_CODE=$? if [ $DOWN_EXIT_CODE -ne 0 ]; then log_message "WARNING: '$DOCKER_COMPOSE_CMD down' failed with exit code $DOWN_EXIT_CODE. Output from command:" # Append the captured output from docker-compose down to the main log # Ensure there's a newline before catting, in case log_message doesn't add one after its prefix echo "" >> "$LOG_FILE" cat "$COMPOSE_DOWN_OUTPUT_FILE" >> "$LOG_FILE" echo "" >> "$LOG_FILE" # Add a newline after the output log_message "(End of '$DOCKER_COMPOSE_CMD down' output for this attempt)" log_message "Attempting to proceed with 'up' command despite 'down' issues..." # This was your script's original logic else log_message "'$DOCKER_COMPOSE_CMD down' executed successfully." fi rm -f "$COMPOSE_DOWN_OUTPUT_FILE" # Clean up the temporary file log_message "Building and deploying with Docker Compose..." # Create a temporary file to capture output from 'docker-compose up' COMPOSE_UP_OUTPUT_FILE="${QUARTZ_PROJECT_DIR}/compose_up_output.tmp" $DOCKER_COMPOSE_CMD up -d --build --remove-orphans > "$COMPOSE_UP_OUTPUT_FILE" 2>&1 UP_EXIT_CODE=$? if [ $UP_EXIT_CODE -ne 0 ]; then log_message "ERROR: '$DOCKER_COMPOSE_CMD up -d --build --remove-orphans' failed with exit code $UP_EXIT_CODE! Output from command:" echo "" >> "$LOG_FILE" cat "$COMPOSE_UP_OUTPUT_FILE" >> "$LOG_FILE" echo "" >> "$LOG_FILE" log_message "(End of '$DOCKER_COMPOSE_CMD up' output for this attempt)" log_message "--- Script Finished (Error) ---" rm -f "$COMPOSE_UP_OUTPUT_FILE" # Clean up exit 1 else log_message "'$DOCKER_COMPOSE_CMD up -d --build --remove-orphans' executed successfully." fi rm -f "$COMPOSE_UP_OUTPUT_FILE" # Clean up # Update the timestamp file on successful deployment touch "$LAST_BUILD_TIMESTAMP_FILE" log_message "Updated last build timestamp: ${LAST_BUILD_TIMESTAMP_FILE}" # Optional: Clean up by removing the copied content and restoring symlink if needed for local dev # This is useful if your local Quartz dev workflow relies on the symlink. # If the cron job is the ONLY way this is built, cleanup might not be strictly necessary, # but it keeps the project dir clean of copied data between runs. log_message "Cleaning up temporary local content directory..." rm -rf "${LOCAL_CONTENT_FULL_PATH}" # If you use a symlink for local dev, uncomment and adjust to restore it: #ln -s "${OBSIDIAN_CONTENT_SOURCE}" "${LOCAL_CONTENT_FULL_PATH}" log_message "Local content directory cleaned up." log_message "--- Script Finished Successfully ---"