#!/usr/bin/env bash # 重新生成 release/ 与 release.tar.gz,供 Ubuntu Docker Compose 一键部署。 set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" RELEASE_DIR="$ROOT_DIR/release" STAGING_DIR="$(mktemp -d "${TMPDIR:-/tmp}/wordcloud-release.XXXXXX")" ARCHIVE="$ROOT_DIR/release.tar.gz" PKG_NAME="wordcloud" cleanup() { rm -rf "$STAGING_DIR" } trap cleanup EXIT log() { echo "[release] $*"; } log "staging at $STAGING_DIR" mkdir -p "$STAGING_DIR/$PKG_NAME" # ── root deploy files ─────────────────────────────────────── cp -a "$ROOT_DIR/docker-compose.yml" "$STAGING_DIR/$PKG_NAME/" cp -a "$ROOT_DIR/Makefile" "$STAGING_DIR/$PKG_NAME/" cp -a "$ROOT_DIR/DOCKER.md" "$STAGING_DIR/$PKG_NAME/" cp -a "$ROOT_DIR/install-ubuntu.sh" "$STAGING_DIR/$PKG_NAME/" cp -a "$ROOT_DIR/README.md" "$STAGING_DIR/$PKG_NAME/" 2>/dev/null || true cp -a "$ROOT_DIR/CHANGELOG.md" "$STAGING_DIR/$PKG_NAME/" 2>/dev/null || true cat > "$STAGING_DIR/$PKG_NAME/.gitignore" <<'GI' .DS_Store .idea/ .claude/ __pycache__/ *.py[cod] .venv/ node_modules/ frontend/dist/ backend/service_workspace/ backend/service_assets/ backend/service_projects/ backend/service_fonts/ backend/EfficientWordCloud/build/ backend/EfficientWordCloud/dist/ backend/EfficientWordCloud/**/*.so *.log *.db GI # ── backend (source only) ─────────────────────────────────── mkdir -p "$STAGING_DIR/$PKG_NAME/backend" rsync -a \ --exclude '.venv/' \ --exclude '.runtime/' \ --exclude '.matplotlib/' \ --exclude '.idea/' \ --exclude '.claude/' \ --exclude '.DS_Store' \ --exclude '__pycache__/' \ --exclude '*.py[cod]' \ --exclude '*.so' \ --exclude '*.o' \ --exclude '*.egg-info/' \ --exclude 'service_workspace/' \ --exclude 'service_assets/' \ --exclude 'service_projects/' \ --exclude 'service_fonts/' \ --exclude 'service_design_templates/' \ --exclude 'output/' \ --exclude 'output_cli_test/' \ --exclude 'ref/' \ --exclude 'docs/' \ --exclude 'EfficientWordCloud/build/' \ --exclude 'EfficientWordCloud/dist/' \ --exclude 'EfficientWordCloud/efficient_wordcloud.egg-info/' \ --exclude 'EfficientWordCloud/**/__pycache__/' \ --exclude 'EfficientWordCloud/**/*.so' \ --exclude 'EfficientWordCloud/**/*.o' \ "$ROOT_DIR/backend/" "$STAGING_DIR/$PKG_NAME/backend/" # design template seeds (json only) if [[ -d "$ROOT_DIR/backend/service_design_templates" ]]; then mkdir -p "$STAGING_DIR/$PKG_NAME/backend/service_design_templates" rsync -a \ --include '*/' \ --include 'template.json' \ --exclude '*' \ "$ROOT_DIR/backend/service_design_templates/" \ "$STAGING_DIR/$PKG_NAME/backend/service_design_templates/" || true fi # ensure runtime dirs exist as empty placeholders (volumes will mount over them) mkdir -p \ "$STAGING_DIR/$PKG_NAME/backend/service_workspace" \ "$STAGING_DIR/$PKG_NAME/backend/service_assets" \ "$STAGING_DIR/$PKG_NAME/backend/service_projects" \ "$STAGING_DIR/$PKG_NAME/backend/service_fonts" # keep design templates if seeded; otherwise empty mkdir -p "$STAGING_DIR/$PKG_NAME/backend/service_design_templates" # ── frontend ──────────────────────────────────────────────── mkdir -p "$STAGING_DIR/$PKG_NAME/frontend" rsync -a \ --exclude 'node_modules/' \ --exclude 'dist/' \ --exclude '.DS_Store' \ --exclude '.claude/' \ --exclude '.idea/' \ "$ROOT_DIR/frontend/" "$STAGING_DIR/$PKG_NAME/frontend/" # ── docs ──────────────────────────────────────────────────── if [[ -d "$ROOT_DIR/docs" ]]; then mkdir -p "$STAGING_DIR/$PKG_NAME/docs" rsync -a \ --exclude '.DS_Store' \ "$ROOT_DIR/docs/" "$STAGING_DIR/$PKG_NAME/docs/" || true fi chmod +x "$STAGING_DIR/$PKG_NAME/install-ubuntu.sh" chmod +x "$STAGING_DIR/$PKG_NAME/backend/start-dev.sh" 2>/dev/null || true # sanity: refuse if venv/workspace leaked in if [[ -e "$STAGING_DIR/$PKG_NAME/backend/.venv" ]]; then echo "[release] ERROR: .venv leaked into staging" >&2 exit 1 fi if find "$STAGING_DIR/$PKG_NAME/backend/service_workspace" -mindepth 1 | read -r _; then echo "[release] ERROR: service_workspace not empty in staging" >&2 exit 1 fi # ── overwrite release/ ────────────────────────────────────── log "overwrite $RELEASE_DIR" rm -rf "$RELEASE_DIR" mkdir -p "$RELEASE_DIR" rsync -a "$STAGING_DIR/$PKG_NAME/" "$RELEASE_DIR/" # ── overwrite release.tar.gz ──────────────────────────────── log "write $ARCHIVE" rm -f "$ARCHIVE" # write to temp then atomic move to avoid truncated archive on interrupt TMP_ARCHIVE="$(mktemp "${TMPDIR:-/tmp}/wordcloud-release-tar.XXXXXX").tar.gz" tar -C "$STAGING_DIR" -czf "$TMP_ARCHIVE" "$PKG_NAME" mv -f "$TMP_ARCHIVE" "$ARCHIVE" # verify archive tar -tzf "$ARCHIVE" >/dev/null python3 - <