#!/bin/sh set -eu DATA_ROOT="${ASSETMANAGER_DATA_ROOT:-/assetmanager-data}" CONFIG_PATH="${APP_CONFIG:-$DATA_ROOT/config/config.json}" APPINFO_PATH="${APPINFO_PATH:-$DATA_ROOT/config/APPINFO.json}" DEFAULT_APPINFO="${DEFAULT_APPINFO:-/app/default-config/APPINFO.json}" UPLOAD_DIR="${UPLOAD_DIR:-$DATA_ROOT/uploads}" STANDARD_IMAGE_DIR="${STANDARD_IMAGE_DIR:-$UPLOAD_DIR/library}" APP_LOG_DIR="${APP_LOG_DIR:-$DATA_ROOT/logs}" SYNC_LOG_DIR="${SYNC_LOG_DIR:-$APP_LOG_DIR/sync}" DIAGNOSTIC_DIR="${DIAGNOSTIC_DIR:-$APP_LOG_DIR/diagnostics}" BACKUP_DIR="${BACKUP_DIR:-$DATA_ROOT/backups}" SCRIPT_DIR="${SCRIPT_DIR:-$DATA_ROOT/scripts}" SOFTWARE_PACKAGE_DIR="${SOFTWARE_PACKAGE_DIR:-$DATA_ROOT/software-packages}" ANALYZER_PROFILE_DIR="${ANALYZER_PROFILE_DIR:-$DATA_ROOT/analyzer-profiles}" # Export normalized paths so every application module uses the same runtime root, # even when the container is started without the bundled Compose file. export ASSETMANAGER_DATA_ROOT="$DATA_ROOT" export APP_CONFIG="$CONFIG_PATH" APPINFO_PATH="$APPINFO_PATH" export UPLOAD_DIR="$UPLOAD_DIR" STANDARD_IMAGE_DIR="$STANDARD_IMAGE_DIR" export APP_LOG_DIR="$APP_LOG_DIR" SYNC_LOG_DIR="$SYNC_LOG_DIR" DIAGNOSTIC_DIR="$DIAGNOSTIC_DIR" export BACKUP_DIR="$BACKUP_DIR" SCRIPT_DIR="$SCRIPT_DIR" export SOFTWARE_PACKAGE_DIR="$SOFTWARE_PACKAGE_DIR" ANALYZER_PROFILE_DIR="$ANALYZER_PROFILE_DIR" ensure_dir() { path="$1" label="$2" if ! mkdir -p "$path"; then echo "ERROR: Cannot create $label directory: $path" >&2 exit 1 fi if [ ! -d "$path" ]; then echo "ERROR: $label path is not a directory: $path" >&2 exit 1 fi probe="$path/.assetmanager-write-test-${HOSTNAME:-container}-$$" if ! (umask 077; : > "$probe") 2>/dev/null; then echo "ERROR: $label directory is not writable: $path" >&2 exit 1 fi rm -f "$probe" } # Keep all persistent runtime data below the single Compose bind mount. # This avoids requiring administrators to create new feature directories by hand. ensure_dir "$DATA_ROOT" "data root" ensure_dir "$(dirname "$CONFIG_PATH")" "configuration" ensure_dir "$(dirname "$APPINFO_PATH")" "application information" ensure_dir "$UPLOAD_DIR" "uploads" ensure_dir "$STANDARD_IMAGE_DIR" "standard image library" ensure_dir "$APP_LOG_DIR" "logs" ensure_dir "$SYNC_LOG_DIR" "sync logs" ensure_dir "$DIAGNOSTIC_DIR" "diagnostics" ensure_dir "$BACKUP_DIR" "backups" ensure_dir "$SCRIPT_DIR" "scripts" ensure_dir "$SOFTWARE_PACKAGE_DIR" "software packages" ensure_dir "$ANALYZER_PROFILE_DIR" "analyzer profiles" ensure_dir "$ANALYZER_PROFILE_DIR/community" "community analyzer profiles" ensure_dir "$ANALYZER_PROFILE_DIR/local" "local analyzer profiles" # Preserve the established /scripts path used by existing job definitions while # storing the files inside the common persistent data root. if [ "$SCRIPT_DIR" != "/scripts" ]; then if [ -L /scripts ]; then rm -f /scripts elif [ -e /scripts ]; then if [ -d /scripts ] && [ -z "$(ls -A /scripts 2>/dev/null)" ]; then rmdir /scripts else echo "ERROR: /scripts exists and cannot safely be linked to $SCRIPT_DIR" >&2 exit 1 fi fi ln -s "$SCRIPT_DIR" /scripts fi echo "AssetManager data root: $DATA_ROOT" echo "Standard image library: $STANDARD_IMAGE_DIR" if [ ! -f "$CONFIG_PATH" ]; then echo "Initializing AssetManager configuration: $CONFIG_PATH" python - "$CONFIG_PATH" <<'PYCFG' import json import sys from pathlib import Path from app.config import DEFAULT_CONFIG path = Path(sys.argv[1]) path.parent.mkdir(parents=True, exist_ok=True) try: with path.open("x", encoding="utf-8") as handle: json.dump(DEFAULT_CONFIG, handle, ensure_ascii=False, indent=2) handle.write("\n") except FileExistsError: # app and callback containers may perform first-start initialization in parallel. pass PYCFG else echo "Keeping existing AssetManager configuration: $CONFIG_PATH" fi if [ ! -f "$APPINFO_PATH" ]; then echo "Initializing AssetManager APPINFO: $APPINFO_PATH" # cp is safe when app and callback initialize the same fresh installation. cp "$DEFAULT_APPINFO" "$APPINFO_PATH" else echo "Keeping existing AssetManager APPINFO: $APPINFO_PATH" fi exec "$@"