feat: schema version tracking, SHA256 integrity, setup scripts, bug fixes
This commit is contained in:
438
scripts/setup/upgrade_momentry.sh
Executable file
438
scripts/setup/upgrade_momentry.sh
Executable file
@@ -0,0 +1,438 @@
|
||||
#!/bin/bash
|
||||
#==============================================================================
|
||||
# Momentry Core — Upgrade Script
|
||||
# Usage: bash upgrade_momentry.sh <delivery_dir>
|
||||
# <delivery_dir> : path to delivery package (e.g. release/delivery/v1.0.0_xxx/)
|
||||
#
|
||||
# Upgrades an existing momentry_core installation from a delivery package.
|
||||
# 1. Pre-flight: version check, backup, health
|
||||
# 2. Migration: apply DB schema changes
|
||||
# 3. Binary: replace momentry binary
|
||||
# 4. Scripts: replace Python processor scripts
|
||||
# 5. Verification: health check + API smoke test
|
||||
#==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
COLOR=true
|
||||
|
||||
# ─── Color helpers ───
|
||||
if [ "$COLOR" = true ]; then
|
||||
R='\033[0;31m'; G='\033[0;32m'; Y='\033[1;33m'; B='\033[0;34m'; C='\033[0;36m'; N='\033[0m'
|
||||
else
|
||||
R=''; G=''; Y=''; B=''; C=''; N=''
|
||||
fi
|
||||
ok() { echo -e " ${G}✓${N} $1"; }
|
||||
fail() { echo -e " ${R}✗${N} $1"; FAILURES+=("$1"); }
|
||||
info() { echo -e " ${B}→${N} $1"; }
|
||||
warn() { echo -e " ${Y}⚠${N} $1"; }
|
||||
header() { echo -e "\n${C}─── $1 ───${N}"; }
|
||||
|
||||
FAILURES=()
|
||||
DELIVERY_DIR=""
|
||||
|
||||
# ─── Parse args ───
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--project-dir) PROJECT_DIR="$2"; shift 2 ;;
|
||||
--no-color) COLOR=false; shift ;;
|
||||
--help) head -20 "$0"; exit 0 ;;
|
||||
*)
|
||||
[ -z "$DELIVERY_DIR" ] && DELIVERY_DIR="$1" || {
|
||||
echo "Unknown: $1"; exit 1; }
|
||||
shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$DELIVERY_DIR" ]; then
|
||||
echo "Usage: bash upgrade_momentry.sh <delivery_dir>"
|
||||
echo ""
|
||||
echo " <delivery_dir> Path to delivery package directory"
|
||||
echo " e.g. $PROJECT_DIR/release/delivery/v1.0.0_0e73d2a_20260515_084750"
|
||||
echo ""
|
||||
echo " Delivery package must contain:"
|
||||
echo " - momentry_v* (production binary)"
|
||||
echo " - scripts/ (processor scripts)"
|
||||
echo " - migrate_*.sql (DB migrations)"
|
||||
echo " - INSTALL.md or similar (package info)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DELIVERY_DIR="$(cd "$DELIVERY_DIR" 2>/dev/null && pwd)" || {
|
||||
echo "ERROR: Delivery directory not found: $DELIVERY_DIR"
|
||||
exit 1
|
||||
}
|
||||
|
||||
PG_BIN="${PG_BIN:-$HOME/pgsql/18.3/bin}"
|
||||
DB_NAME="${DB_NAME:-momentry}"
|
||||
BACKUP_DIR="$PROJECT_DIR/backup/upgrade_$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
echo -e "${C}========================================${N}"
|
||||
echo -e "${C} Momentry Core — Upgrade${N}"
|
||||
echo -e "${C} Delivery: $DELIVERY_DIR${N}"
|
||||
echo -e "${C} Project: $PROJECT_DIR${N}"
|
||||
echo -e "${C} Date: $(date '+%Y-%m-%d %H:%M:%S')${N}"
|
||||
echo -e "${C}========================================${N}"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Phase 0: Pre-flight
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
header "Phase 0/5 — Pre-flight"
|
||||
|
||||
# 0a. Check delivery package integrity
|
||||
info "Checking delivery package..."
|
||||
REQUIRED=()
|
||||
BINARY=$(ls "$DELIVERY_DIR"/momentry_v* 2>/dev/null | head -1 || true)
|
||||
if [ -n "$BINARY" ]; then
|
||||
ok "Binary: $(basename "$BINARY") ($(ls -lh "$BINARY" | awk '{print $5}'))"
|
||||
else
|
||||
fail "No momentry_v* binary in delivery package"
|
||||
fi
|
||||
|
||||
if [ -d "$DELIVERY_DIR/scripts" ]; then
|
||||
SCRIPT_COUNT=$(find "$DELIVERY_DIR/scripts" -name '*.py' -type f | wc -l | tr -d ' ')
|
||||
ok "Scripts dir: $SCRIPT_COUNT .py files"
|
||||
else
|
||||
fail "No scripts/ directory in delivery package"
|
||||
fi
|
||||
|
||||
MIGRATIONS=()
|
||||
for f in "$DELIVERY_DIR"/migrate_*.sql; do
|
||||
[ -f "$f" ] && MIGRATIONS+=("$f")
|
||||
done
|
||||
if [ ${#MIGRATIONS[@]} -gt 0 ]; then
|
||||
for f in "${MIGRATIONS[@]}"; do ok "Migration: $(basename "$f")"; done
|
||||
else
|
||||
warn "No migration SQL files in delivery package"
|
||||
fi
|
||||
|
||||
# 0b. Check current server
|
||||
HEALTH_ENDPOINT="http://127.0.0.1:3003"
|
||||
CURL_OPTS="-sf --connect-timeout 5"
|
||||
|
||||
if curl $CURL_OPTS "$HEALTH_ENDPOINT/health" &>/dev/null; then
|
||||
CURRENT_VER=$(curl -sf "$HEALTH_ENDPOINT/health" | python3 -c "import json,sys;print(json.load(sys.stdin).get('version','?'))" 2>/dev/null)
|
||||
CURRENT_HASH=$(curl -sf "$HEALTH_ENDPOINT/health" | python3 -c "import json,sys;print(json.load(sys.stdin).get('build_git_hash','?'))" 2>/dev/null)
|
||||
ok "Server running: v$CURRENT_VER ($CURRENT_HASH)"
|
||||
else
|
||||
CURRENT_VER="down"
|
||||
warn "Server not reachable at $HEALTH_ENDPOINT"
|
||||
HEALTH_ENDPOINT="http://127.0.0.1:3002"
|
||||
if curl $CURL_OPTS "$HEALTH_ENDPOINT/health" &>/dev/null; then
|
||||
CURRENT_VER=$(curl -sf "$HEALTH_ENDPOINT/health" | python3 -c "import json,sys;print(json.load(sys.stdin).get('version','?'))" 2>/dev/null)
|
||||
ok "Production server running: v$CURRENT_VER"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Extract package version from INSTALL.md or binary name
|
||||
PKG_VER=$(echo "$(basename "$DELIVERY_DIR")" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
|
||||
PKG_BUILD=$(echo "$(basename "$DELIVERY_DIR")" | grep -oE '[a-f0-9]{7}' || echo "unknown")
|
||||
info "Package: $PKG_VER (build $PKG_BUILD)"
|
||||
|
||||
# 0c. Check PostgreSQL
|
||||
if "$PG_BIN/pg_isready" -q 2>/dev/null; then
|
||||
ok "PostgreSQL"
|
||||
else
|
||||
fail "PostgreSQL not running"
|
||||
fi
|
||||
|
||||
# 0d. Prompt to continue
|
||||
if [ ${#FAILURES[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
echo -e "${R}Pre-flight failures detected. Continue anyway? [y/N]${N} "
|
||||
read -r CONFIRM
|
||||
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
|
||||
echo "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Phase 1: Backup
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
header "Phase 1/5 — Backup"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# 1a. Backup current binary (if exists)
|
||||
for bin_path in target/release/momentry target/debug/momentry_playground; do
|
||||
if [ -f "$PROJECT_DIR/$bin_path" ]; then
|
||||
mkdir -p "$BACKUP_DIR/$(dirname "$bin_path")"
|
||||
cp "$PROJECT_DIR/$bin_path" "$BACKUP_DIR/$bin_path"
|
||||
ok "Backed up: $bin_path"
|
||||
fi
|
||||
done
|
||||
|
||||
# 1b. Backup scripts
|
||||
SCRIPTS_SNAPSHOT="$BACKUP_DIR/scripts"
|
||||
mkdir -p "$SCRIPTS_SNAPSHOT"
|
||||
rsync -a "$PROJECT_DIR/scripts/" "$SCRIPTS_SNAPSHOT/" 2>/dev/null
|
||||
ok "Backed up: scripts/ (to $SCRIPTS_SNAPSHOT)"
|
||||
|
||||
# 1c. Backup current .env
|
||||
if [ -f "$PROJECT_DIR/.env" ]; then
|
||||
cp "$PROJECT_DIR/.env" "$BACKUP_DIR/.env"
|
||||
ok "Backed up: .env"
|
||||
fi
|
||||
|
||||
# 1d. Schema backup
|
||||
"$PG_BIN/pg_dump" -U accusys -d "$DB_NAME" --schema-only > "$BACKUP_DIR/schema_pre.sql" 2>/dev/null
|
||||
ok "Backed up: schema (pre-upgrade)"
|
||||
|
||||
echo ""
|
||||
info "Backup saved to: $BACKUP_DIR"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Phase 2: Database Migration
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
header "Phase 2/6 — Database Migration"
|
||||
|
||||
# Ensure schema_migrations table exists first
|
||||
"$PG_BIN/psql" -U accusys -d "$DB_NAME" -c "
|
||||
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
filename TEXT NOT NULL UNIQUE,
|
||||
checksum TEXT NOT NULL,
|
||||
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
duration_ms INTEGER DEFAULT 0
|
||||
)" &>/dev/null
|
||||
ok "schema_migrations table ensured"
|
||||
|
||||
for mig in "${MIGRATIONS[@]}"; do
|
||||
MIG_NAME=$(basename "$mig")
|
||||
MIG_HASH=$(shasum -a 256 "$mig" | awk '{print $1}')
|
||||
|
||||
# Check if already applied with matching checksum
|
||||
ALREADY=$("$PG_BIN/psql" -U accusys -d "$DB_NAME" -t -A -c \
|
||||
"SELECT COUNT(*) FROM schema_migrations WHERE filename='$MIG_NAME' AND checksum='$MIG_HASH'" 2>/dev/null || echo "0")
|
||||
if [ "$ALREADY" -gt 0 ]; then
|
||||
ok "Migration $MIG_NAME (already applied, checksum match)"
|
||||
continue
|
||||
fi
|
||||
|
||||
info "Applying $MIG_NAME..."
|
||||
T0=$(date +%s%N)
|
||||
if "$PG_BIN/psql" -U accusys -d "$DB_NAME" -f "$mig" 2>&1; then
|
||||
T1=$(date +%s%N)
|
||||
DURATION_MS=$(( (T1 - T0) / 1000000 ))
|
||||
"$PG_BIN/psql" -U accusys -d "$DB_NAME" -c \
|
||||
"INSERT INTO schema_migrations (filename, checksum, duration_ms) VALUES ('$MIG_NAME', '$MIG_HASH', $DURATION_MS) ON CONFLICT (filename) DO UPDATE SET checksum=EXCLUDED.checksum, applied_at=NOW()" &>/dev/null || true
|
||||
ok "Applied: $MIG_NAME (${DURATION_MS}ms)"
|
||||
else
|
||||
fail "Migration failed: $MIG_NAME"
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify schema completeness via binary startup check
|
||||
info "Verifying schema... (will be checked at server restart)"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Phase 3: Binary Replacement
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
header "Phase 3/5 — Binary Replacement"
|
||||
|
||||
# Determine which binary to install
|
||||
if echo "$HEALTH_ENDPOINT" | grep -q "3002"; then
|
||||
TARGET_BIN="momentry"
|
||||
TARGET_PATH="$PROJECT_DIR/target/release/$TARGET_BIN"
|
||||
TARGET_PORT=3002
|
||||
else
|
||||
TARGET_BIN="momentry_playground"
|
||||
TARGET_PATH="$PROJECT_DIR/target/debug/$TARGET_BIN"
|
||||
TARGET_PORT=3003
|
||||
fi
|
||||
|
||||
# Copy binary from delivery
|
||||
BINARY_SRC=$(ls "$DELIVERY_DIR"/momentry_v* 2>/dev/null | head -1 || true)
|
||||
if [ -n "$BINARY_SRC" ]; then
|
||||
# If the delivery has a pre-built binary (for production)
|
||||
mkdir -p "$(dirname "$TARGET_PATH")"
|
||||
cp "$BINARY_SRC" "$TARGET_PATH"
|
||||
chmod +x "$TARGET_PATH"
|
||||
|
||||
# Remove code signature (required for Apple Silicon when binary is from another Mac)
|
||||
if command -v codesign &>/dev/null; then
|
||||
codesign --remove-signature "$TARGET_PATH" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
ok "Binary replaced: $TARGET_PATH ($(ls -lh "$TARGET_PATH" | awk '{print $5}'))"
|
||||
else
|
||||
# No pre-built binary — need to build from source
|
||||
info "No pre-built binary in delivery — building from source..."
|
||||
cargo build --bin "$TARGET_BIN" 2>&1 | tail -3
|
||||
if [ -f "$PROJECT_DIR/target/debug/momentry_playground" ]; then
|
||||
ok "Built: $TARGET_BIN"
|
||||
else
|
||||
fail "Build failed: $TARGET_BIN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Phase 4: Scripts Update
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
header "Phase 4/5 — Scripts Update"
|
||||
|
||||
if [ -d "$DELIVERY_DIR/scripts" ]; then
|
||||
# Copy each processor script, preserving existing utility scripts
|
||||
# that may not be in the delivery package
|
||||
for f in "$DELIVERY_DIR/scripts"/*.py; do
|
||||
if [ -f "$f" ]; then
|
||||
cp "$f" "$PROJECT_DIR/scripts/"
|
||||
fi
|
||||
done
|
||||
# Copy subdirectories (swift_processors, utils, etc.)
|
||||
for d in "$DELIVERY_DIR/scripts"/*/; do
|
||||
if [ -d "$d" ]; then
|
||||
rsync -a "$d" "$PROJECT_DIR/scripts/$(basename "$d")/"
|
||||
fi
|
||||
done
|
||||
chmod +x "$PROJECT_DIR/scripts"/*.py 2>/dev/null || true
|
||||
ok "Processor scripts updated ($(find "$PROJECT_DIR/scripts" -name '*.py' -type f | wc -l | tr -d ' ') .py files)"
|
||||
|
||||
# Verify SHA256 checksums after update
|
||||
CHECKSUMS_FILE="$PROJECT_DIR/scripts/checksums.sha256"
|
||||
CS_TOTAL=0; CS_PASS=0; CS_FAIL=0
|
||||
if [ -f "$CHECKSUMS_FILE" ]; then
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
EXPECTED_HASH=$(echo "$line" | awk '{print $1}')
|
||||
FILE_PATH=$(echo "$line" | awk '{print $2}')
|
||||
FULL_PATH="$PROJECT_DIR/scripts/$FILE_PATH"
|
||||
CS_TOTAL=$((CS_TOTAL + 1))
|
||||
if [ -f "$FULL_PATH" ]; then
|
||||
ACTUAL_HASH=$(shasum -a 256 "$FULL_PATH" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$ACTUAL_HASH" = "$EXPECTED_HASH" ]; then
|
||||
CS_PASS=$((CS_PASS + 1))
|
||||
else
|
||||
CS_FAIL=$((CS_FAIL + 1))
|
||||
[ $CS_FAIL -le 5 ] && warn "$FILE_PATH — hash mismatch after update"
|
||||
fi
|
||||
else
|
||||
CS_FAIL=$((CS_FAIL + 1))
|
||||
[ $CS_FAIL -le 5 ] && warn "$FILE_PATH — not found after update"
|
||||
fi
|
||||
done < "$CHECKSUMS_FILE"
|
||||
ok "Script integrity: $CS_PASS/$CS_TOTAL checksums match"
|
||||
[ $CS_FAIL -gt 0 ] && warn "Script integrity: $CS_FAIL mismatches" || true
|
||||
else
|
||||
warn "No checksums.sha256 found — generating from updated scripts..."
|
||||
cd "$PROJECT_DIR/scripts"
|
||||
find . -name '*.py' -type f | sort | while IFS= read -r f; do shasum -a 256 "$f"; done > checksums.sha256
|
||||
ok "checksums.sha256 generated ($(wc -l < checksums.sha256) entries)"
|
||||
fi
|
||||
else
|
||||
warn "No scripts/ in delivery — skipping"
|
||||
fi
|
||||
|
||||
# Python dependencies check
|
||||
header " Python dependencies"
|
||||
PYTHON_BIN="${MOMENTRY_PYTHON_PATH:-/opt/homebrew/bin/python3.11}"
|
||||
for pkg in PyPDF2 python-docx openpyxl python-pptx; do
|
||||
if "$PYTHON_BIN" -c "import ${pkg%%=*}" &>/dev/null 2>&1; then
|
||||
ok "$pkg"
|
||||
else
|
||||
"$PYTHON_BIN" -m pip install "$pkg" --quiet && ok "$pkg" || warn "$pkg"
|
||||
fi
|
||||
done
|
||||
|
||||
# Ensure watch directory exists
|
||||
WATCH_DIR="${MOMENTRY_SFTP_ROOT:-$PROJECT_DIR/storage/watch}"
|
||||
mkdir -p "$WATCH_DIR"
|
||||
ok "Watcher directory: $WATCH_DIR"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Phase 6: Restart & Verify
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
header "Phase 6/6 — Restart & Verify"
|
||||
|
||||
# 5a. Stop old server
|
||||
if [ -n "$TARGET_PORT" ] && [ "$TARGET_PORT" = "3002" ]; then
|
||||
pkill -f "momentry server" 2>/dev/null || true
|
||||
pkill -f "momentry_playground server" 2>/dev/null || true
|
||||
else
|
||||
pkill -f "momentry_playground server" 2>/dev/null || true
|
||||
fi
|
||||
sleep 2
|
||||
info "Stopped old server"
|
||||
|
||||
# 5b. Start new server
|
||||
cd "$PROJECT_DIR"
|
||||
if [ "$TARGET_PORT" = "3002" ]; then
|
||||
DATABASE_SCHEMA=public nohup "$TARGET_PATH" server --port 3002 > "$PROJECT_DIR/production_boot.log" 2>&1 &
|
||||
else
|
||||
DATABASE_SCHEMA=dev nohup "$TARGET_PATH" server --port 3003 > "$PROJECT_DIR/playground_boot.log" 2>&1 &
|
||||
fi
|
||||
|
||||
for i in $(seq 1 10); do
|
||||
sleep 2
|
||||
if curl $CURL_OPTS "$HEALTH_ENDPOINT/health" &>/dev/null; then
|
||||
ok "Server restarted on port $TARGET_PORT"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ! curl $CURL_OPTS "$HEALTH_ENDPOINT/health" &>/dev/null; then
|
||||
fail "Server failed to start on port $TARGET_PORT"
|
||||
fi
|
||||
|
||||
# 5c. Health check
|
||||
HEALTH=$(curl -sf "$HEALTH_ENDPOINT/health" 2>/dev/null || echo '{"status":"error"}')
|
||||
echo "$HEALTH" | python3 -c "
|
||||
import json,sys
|
||||
d=json.load(sys.stdin)
|
||||
print(f' Version: {d.get(\"version\",\"?\")}')
|
||||
print(f' Build: {d.get(\"build_git_hash\",\"?\")}')
|
||||
print(f' Timestamp: {d.get(\"build_timestamp\",\"?\")}')
|
||||
print(f' Status: {d.get(\"status\",\"?\")}')
|
||||
" 2>/dev/null
|
||||
|
||||
# 5d. Processor inventory
|
||||
DETAILED=$(curl -sf "$HEALTH_ENDPOINT/health/detailed" 2>/dev/null || echo '{}')
|
||||
echo "$DETAILED" | python3 -c "
|
||||
import json,sys
|
||||
d=json.load(sys.stdin)
|
||||
p=d.get('pipeline',{})
|
||||
proc=p.get('processors',{})
|
||||
missing=[k for k in ['asr','yolo','face','pose','ocr','cut','caption','scene','story','asrx','probe','visual_chunk'] if not proc.get(k)]
|
||||
if missing:
|
||||
print(f' Missing processors: {missing}')
|
||||
else:
|
||||
print(' All 12 processors: ✓')
|
||||
print(f' Scripts: {p.get(\"scripts_count\",\"?\")} .py files')
|
||||
" 2>/dev/null
|
||||
|
||||
# 5e. API smoke test
|
||||
API_KEY="${MOMENTRY_API_KEY:-muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69}"
|
||||
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" \
|
||||
-H "X-API-Key: $API_KEY" \
|
||||
"$HEALTH_ENDPOINT/api/v1/videos?page=1&page_size=1" 2>/dev/null || echo "000")
|
||||
ok "API /v1/videos → HTTP $STATUS"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Summary
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo ""
|
||||
echo -e "${C}========================================${N}"
|
||||
if [ ${#FAILURES[@]} -eq 0 ]; then
|
||||
echo -e "${G} Upgrade Complete — All Checks Passed${N}"
|
||||
else
|
||||
echo -e "${Y} Upgrade Complete — ${#FAILURES[@]} Warnings${N}"
|
||||
for f in "${FAILURES[@]}"; do echo -e " ${R}✗${N} $f"; done
|
||||
fi
|
||||
echo -e "${C}========================================${N}"
|
||||
echo ""
|
||||
echo " Backup: $BACKUP_DIR"
|
||||
echo " Server: $HEALTH_ENDPOINT"
|
||||
echo " Binary: $TARGET_PATH"
|
||||
echo " Watch dir: $WATCH_DIR"
|
||||
echo " Version: $(echo "$HEALTH" | python3 -c "import json,sys;print(json.load(sys.stdin).get('version','?'))" 2>/dev/null)"
|
||||
echo ""
|
||||
echo " To rollback:"
|
||||
echo " 1. cp $BACKUP_DIR/target/release/momentry $PROJECT_DIR/target/release/"
|
||||
echo " 2. rsync -a $BACKUP_DIR/scripts/ $PROJECT_DIR/scripts/"
|
||||
echo " 3. $PG_BIN/psql -U accusys -d $DB_NAME < $BACKUP_DIR/schema_pre.sql"
|
||||
echo " 4. Restart server"
|
||||
echo ""
|
||||
|
||||
exit $([ ${#FAILURES[@]} -eq 0 ] && echo 0 || echo 1)
|
||||
Reference in New Issue
Block a user