#!/bin/bash # Package Delivery — 依 M4 spec 三層打包 # Usage: # bash package_delivery.sh dev # bash package_delivery.sh prod # bash package_delivery.sh file set -euo pipefail CMD="${1:?Usage: $0 [version]}" PROJECT="/Users/accusys/momentry_core_0.1" PG_BIN="/Users/accusys/pgsql/18.3/bin" T0=$(date +%s) case "$CMD" in dev) VERSION="${2:?Usage: $0 dev }" OUTPUT="$PROJECT/release/dev_upgrade_${VERSION}" mkdir -p "$OUTPUT/schema" "$OUTPUT/bin" "$OUTPUT/src" echo "=== Dev Upgrade Package ${VERSION} ===" # Migration SQL (auto-generated from current schema) echo "[1/4] Migration SQL..." { echo "-- Migration: dev schema ${VERSION}" echo "-- Date: $(date +%Y-%m-%d)" echo "-- Auto-generated from current DB schema" echo "" echo "SET search_path TO dev;" echo "" # face_detections: timestamp_secs was added later $PG_BIN/psql -U accusys -d momentry -t -A -c " SELECT 'ALTER TABLE dev.face_detections ADD COLUMN IF NOT EXISTS ' || column_name || ' ' || udt_name || ';' FROM information_schema.columns WHERE table_schema='dev' AND table_name='face_detections' AND column_name = 'timestamp_secs'; " 2>/dev/null # chunk: chunk_id was changed to short format echo "" echo "-- Chunk index removals (already applied)" echo "-- chunk_vectors: standard columns" } > "$OUTPUT/schema/migration_${VERSION}.sql" echo " migration_${VERSION}.sql" # Binary echo "[2/4] Binary..." BIN_SRC="$PROJECT/target/debug/momentry_playground" if [ -f "$BIN_SRC" ]; then cp "$BIN_SRC" "$OUTPUT/bin/" echo " momentry_playground ($(ls -lh "$OUTPUT/bin/momentry_playground" | awk '{print $5}'))" else echo " WARN: binary not found at $BIN_SRC (build first: cargo build --bin momentry_playground)" fi # Source (optional) echo "[3/4] Source code..." cd "$PROJECT" git archive --format=tar.gz -o "$OUTPUT/src/momentry_core_${VERSION}_source.tar.gz" HEAD 2>/dev/null echo " source.tar.gz ($(ls -lh "$OUTPUT/src/momentry_core_${VERSION}_source.tar.gz" | awk '{print $5}'))" # UPGRADE.md echo "[4/4] UPGRADE.md..." cat > "$OUTPUT/UPGRADE.md" << UPEOF # Dev Upgrade ${VERSION} ## Steps \`\`\`bash # 1. Apply migration psql -U accusys -d momentry < schema/migration_${VERSION}.sql # 2. Replace binary cp bin/momentry_playground ${PROJECT}/target/debug/ # 3. Restart pkill momentry_playground DATABASE_SCHEMA=dev ${PROJECT}/target/debug/momentry_playground server --port 3003 \`\`\` UPEOF # Package cd "$PROJECT/release" tar czf "dev_upgrade_${VERSION}.tar.gz" -C "$(dirname "$OUTPUT")" "$(basename "$OUTPUT")" echo "" echo "=== Package: release/dev_upgrade_${VERSION}.tar.gz ($(ls -lh "dev_upgrade_${VERSION}.tar.gz" | awk '{print $5}')) ===" ;; prod) VERSION="${2:?Usage: $0 prod }" OUTPUT="$PROJECT/release/prod_upgrade_${VERSION}" mkdir -p "$OUTPUT/schema" "$OUTPUT/bin" echo "=== Prod Upgrade Package ${VERSION} ===" echo "[1/3] Migration SQL..." cat > "$OUTPUT/schema/migration_${VERSION}.sql" << SQLEOF -- Migration: public schema ${VERSION} -- Date: $(date +%Y-%m-%d) SET search_path TO public; -- ALTER TABLE public.videos ADD COLUMN IF NOT EXISTS ...; SQLEOF echo " migration_${VERSION}.sql" echo "[2/3] Binary..." BIN_SRC="$PROJECT/target/release/momentry" if [ -f "$BIN_SRC" ]; then cp "$BIN_SRC" "$OUTPUT/bin/" echo " momentry ($(ls -lh "$OUTPUT/bin/momentry" | awk '{print $5}'))" else echo " WARN: release binary not found (build: cargo build --release --bin momentry)" fi echo "[3/3] UPGRADE.md..." cat > "$OUTPUT/UPGRADE.md" << UPEOF # Prod Upgrade ${VERSION} ## Pre-flight \`\`\`bash pg_dump -U accusys -d momentry --schema=public > backup_${VERSION}_pre.sql \`\`\` ## Steps \`\`\`bash # 1. Migration psql -U accusys -d momentry < schema/migration_${VERSION}.sql # 2. Replace binary cp bin/momentry ${PROJECT}/target/release/ # 3. Restart sudo launchctl stop com.momentry.api sudo launchctl start com.momentry.api \`\`\` ## Rollback \`\`\`bash psql -U accusys -d momentry < backup_${VERSION}_pre.sql \`\`\` UPEOF cd "$PROJECT/release" tar czf "prod_upgrade_${VERSION}.tar.gz" -C "$(dirname "$OUTPUT")" "$(basename "$OUTPUT")" echo "" echo "=== Package: release/prod_upgrade_${VERSION}.tar.gz ($(ls -lh "prod_upgrade_${VERSION}.tar.gz" | awk '{print $5}')) ===" ;; file) UUID="${2:?Usage: $0 file [version]}" VERSION="${3:-v1.0}" OUTPUT="$PROJECT/release/file_${UUID}_${VERSION}" mkdir -p "$OUTPUT" echo "=== File Package ${UUID} ${VERSION} ===" # file_info.json echo "[1/5] file_info.json..." $PG_BIN/psql -U accusys -d momentry -t -A -c " SELECT json_build_object( 'file_uuid', file_uuid, 'file_name', file_name, 'duration', duration, 'fps', fps, 'width', width, 'height', height, 'total_frames', total_frames, 'status', status ) FROM dev.videos WHERE file_uuid='$UUID'; " 2>/dev/null | python3 -c "import json,sys;json.dump(json.load(sys.stdin),open('$OUTPUT/file_info.json','w'),indent=2)" # data.sql (using Python export script) echo "[2/5] data.sql..." python3 "$PROJECT/scripts/export_file_package.py" "$UUID" "$OUTPUT" 2>&1 # checksums.md5 echo "[3/5] checksums.md5..." cd "$OUTPUT" md5sum data.sql file_info.json 2>/dev/null > checksums.md5 || md5 data.sql file_info.json > checksums.md5 2>/dev/null echo " checksums.md5" # README.md echo "[4/5] README.md..." cat > "$OUTPUT/README.md" << READMEEOF # File Package: ${UUID} ## Import \`\`\`bash export UUID=${UUID} # 1. Clean existing data for this file psql -U accusys -d momentry << SQL DELETE FROM dev.chunk_vectors WHERE uuid = '\${UUID}'::text; DELETE FROM dev.chunk WHERE file_uuid = '\${UUID}'; DELETE FROM dev.face_detections WHERE file_uuid = '\${UUID}'; DELETE FROM dev.videos WHERE file_uuid = '\${UUID}'; SQL # 2. Restore psql -U accusys -d momentry < data.sql # 3. Verify psql -U accusys -d momentry -c "SELECT file_uuid, status FROM dev.videos WHERE file_uuid = '\${UUID}'" \`\`\` ## Verification - \`GET /api/v1/file/{uuid}\` → 200, status=ready - \`GET /api/v1/file/{uuid}/chunk/0-01\` → 200 - \`POST /api/v1/search/universal\` → results READMEEOF # Package echo "[5/5] Packaging tar.gz..." cd "$PROJECT/release" tar czf "file_${UUID}_${VERSION}.tar.gz" -C "$(dirname "$OUTPUT")" "$(basename "$OUTPUT")" 2>/dev/null echo " release/file_${UUID}_${VERSION}.tar.gz ($(ls -lh "file_${UUID}_${VERSION}.tar.gz" | awk '{print $5}'))" rm -rf "$OUTPUT" ;; *) echo "Usage: $0 [version]" exit 1 ;; esac ELAPSED=$(($(date +%s) - T0)) echo " Elapsed: ${ELAPSED}s"