237 lines
6.2 KiB
Bash
Executable File
237 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
if [[ -z "${BASH_VERSION:-}" ]]; then
|
|
echo "Error: run this script with bash (example: bash deploy_synology.sh)." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ManeshTrader quick deploy helper for Synology Docker host.
|
|
# Defaults are set for the target provided by the user.
|
|
|
|
REMOTE_USER="${REMOTE_USER:-mbrucedogs}"
|
|
REMOTE_HOST="${REMOTE_HOST:-192.168.1.128}"
|
|
REMOTE_PORT="${REMOTE_PORT:-25}"
|
|
REMOTE_BASE="${REMOTE_BASE:-/volume1/docker/maneshtrader}"
|
|
SYNO_PASSWORD="${SYNO_PASSWORD:-}"
|
|
|
|
MODE="bind" # bind: upload + restart; image: upload + rebuild
|
|
NO_RESTART="0"
|
|
DRY_RUN="0"
|
|
|
|
DEFAULT_FILES=(
|
|
"web/src/web_core/ui/help_content.py"
|
|
"web/src/PRD.md"
|
|
"web/src/ONBOARDING.md"
|
|
)
|
|
|
|
FILES=("${DEFAULT_FILES[@]}")
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
./deploy_synology.sh [options]
|
|
|
|
Options:
|
|
--mode bind|image Deploy mode (default: bind)
|
|
--files "a b c" Space-separated file list to upload
|
|
--recent-minutes N Upload files under web/src modified in last N minutes
|
|
--no-restart Upload only; skip remote docker restart/rebuild
|
|
--dry-run Print actions but do not execute
|
|
-h, --help Show help
|
|
|
|
Environment overrides:
|
|
REMOTE_USER, REMOTE_HOST, REMOTE_PORT, REMOTE_BASE, SYNO_PASSWORD, CONTAINER_NAME
|
|
|
|
Examples:
|
|
./deploy_synology.sh
|
|
./deploy_synology.sh --mode image
|
|
./deploy_synology.sh --recent-minutes 120
|
|
./deploy_synology.sh --files "web/src/web_core/ui/help_content.py"
|
|
EOF
|
|
}
|
|
|
|
run_cmd() {
|
|
if [[ "$DRY_RUN" == "1" ]]; then
|
|
printf '[dry-run] %s\n' "$*"
|
|
else
|
|
eval "$@"
|
|
fi
|
|
}
|
|
|
|
build_ssh_cmd() {
|
|
if [[ -n "${SYNO_PASSWORD:-}" ]]; then
|
|
if ! command -v sshpass >/dev/null 2>&1; then
|
|
echo "Error: SYNO_PASSWORD is set but sshpass is not installed." >&2
|
|
exit 1
|
|
fi
|
|
printf "SSHPASS='%s' sshpass -e ssh -o StrictHostKeyChecking=accept-new -p '%s' '%s@%s'" \
|
|
"${SYNO_PASSWORD}" "${REMOTE_PORT}" "${REMOTE_USER}" "${REMOTE_HOST}"
|
|
else
|
|
printf "ssh -p '%s' '%s@%s'" "${REMOTE_PORT}" "${REMOTE_USER}" "${REMOTE_HOST}"
|
|
fi
|
|
}
|
|
|
|
build_scp_cmd() {
|
|
if [[ -n "${SYNO_PASSWORD:-}" ]]; then
|
|
if ! command -v sshpass >/dev/null 2>&1; then
|
|
echo "Error: SYNO_PASSWORD is set but sshpass is not installed." >&2
|
|
exit 1
|
|
fi
|
|
printf "SSHPASS='%s' sshpass -e scp -O -o StrictHostKeyChecking=accept-new -P '%s'" \
|
|
"${SYNO_PASSWORD}" "${REMOTE_PORT}"
|
|
else
|
|
printf "scp -O -P '%s'" "${REMOTE_PORT}"
|
|
fi
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--mode)
|
|
MODE="${2:-}"
|
|
shift 2
|
|
;;
|
|
--files)
|
|
read -r -a FILES <<< "${2:-}"
|
|
shift 2
|
|
;;
|
|
--recent-minutes)
|
|
minutes="${2:-}"
|
|
if ! [[ "$minutes" =~ ^[0-9]+$ ]]; then
|
|
echo "Error: --recent-minutes requires an integer." >&2
|
|
exit 1
|
|
fi
|
|
FILES=()
|
|
while IFS= read -r candidate; do
|
|
[[ -z "$candidate" ]] && continue
|
|
FILES+=("$candidate")
|
|
done <<EOF
|
|
$(find web/src -type f -mmin "-$minutes" ! -name ".DS_Store" | sort)
|
|
EOF
|
|
shift 2
|
|
;;
|
|
--no-restart)
|
|
NO_RESTART="1"
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
DRY_RUN="1"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ "$MODE" != "bind" && "$MODE" != "image" ]]; then
|
|
echo "Error: --mode must be 'bind' or 'image'." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ${#FILES[@]} -eq 0 ]]; then
|
|
echo "Error: No files selected for upload." >&2
|
|
exit 1
|
|
fi
|
|
|
|
for file in "${FILES[@]}"; do
|
|
if [[ ! -f "$file" ]]; then
|
|
echo "Error: Local file not found: $file" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
echo "Deploy target: ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}"
|
|
echo "Remote base: ${REMOTE_BASE}"
|
|
echo "Mode: ${MODE}"
|
|
echo "Files:"
|
|
for file in "${FILES[@]}"; do
|
|
echo " - $file"
|
|
done
|
|
|
|
for file in "${FILES[@]}"; do
|
|
remote_path="${REMOTE_BASE}/${file}"
|
|
remote_dir="$(dirname "$remote_path")"
|
|
SSH_CMD="$(build_ssh_cmd)"
|
|
SCP_CMD="$(build_scp_cmd)"
|
|
run_cmd "${SSH_CMD} \"mkdir -p '${remote_dir}'\""
|
|
run_cmd "${SCP_CMD} '${file}' '${REMOTE_USER}@${REMOTE_HOST}:${remote_path}'"
|
|
done
|
|
|
|
if [[ "$NO_RESTART" == "1" ]]; then
|
|
echo "Upload complete (restart/rebuild skipped)."
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$MODE" == "bind" ]]; then
|
|
SSH_CMD="$(build_ssh_cmd)"
|
|
run_cmd "${SSH_CMD} '
|
|
set -e
|
|
cd \"${REMOTE_BASE}\"
|
|
DOCKER_BIN=\"\"
|
|
if command -v docker >/dev/null 2>&1; then
|
|
DOCKER_BIN=\"\$(command -v docker)\"
|
|
elif [[ -x /usr/local/bin/docker ]]; then
|
|
DOCKER_BIN=\"/usr/local/bin/docker\"
|
|
elif [[ -x /usr/bin/docker ]]; then
|
|
DOCKER_BIN=\"/usr/bin/docker\"
|
|
elif [[ -x /var/packages/ContainerManager/target/usr/bin/docker ]]; then
|
|
DOCKER_BIN=\"/var/packages/ContainerManager/target/usr/bin/docker\"
|
|
fi
|
|
|
|
if [[ -n \"\$DOCKER_BIN\" ]] && \"\$DOCKER_BIN\" compose version >/dev/null 2>&1; then
|
|
\"\$DOCKER_BIN\" compose restart
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
|
docker-compose restart
|
|
elif [[ -n \"\$DOCKER_BIN\" ]]; then
|
|
if [[ -n \"${CONTAINER_NAME:-}\" ]]; then
|
|
\"\$DOCKER_BIN\" restart \"${CONTAINER_NAME}\"
|
|
else
|
|
ids=\$(\"\$DOCKER_BIN\" ps --filter \"name=maneshtrader\" -q)
|
|
if [[ -z \"\$ids\" ]]; then
|
|
echo \"No docker compose command found, and no running containers matched name=maneshtrader.\" >&2
|
|
echo \"Set CONTAINER_NAME=<your-container-name> and rerun.\" >&2
|
|
exit 1
|
|
fi
|
|
\"\$DOCKER_BIN\" restart \$ids
|
|
fi
|
|
else
|
|
echo \"No docker or docker compose command found on remote host.\" >&2
|
|
exit 1
|
|
fi
|
|
'"
|
|
echo "Upload + container restart complete."
|
|
else
|
|
SSH_CMD="$(build_ssh_cmd)"
|
|
run_cmd "${SSH_CMD} '
|
|
set -e
|
|
cd \"${REMOTE_BASE}\"
|
|
DOCKER_BIN=\"\"
|
|
if command -v docker >/dev/null 2>&1; then
|
|
DOCKER_BIN=\"\$(command -v docker)\"
|
|
elif [[ -x /usr/local/bin/docker ]]; then
|
|
DOCKER_BIN=\"/usr/local/bin/docker\"
|
|
elif [[ -x /usr/bin/docker ]]; then
|
|
DOCKER_BIN=\"/usr/bin/docker\"
|
|
elif [[ -x /var/packages/ContainerManager/target/usr/bin/docker ]]; then
|
|
DOCKER_BIN=\"/var/packages/ContainerManager/target/usr/bin/docker\"
|
|
fi
|
|
|
|
if [[ -n \"\$DOCKER_BIN\" ]] && \"\$DOCKER_BIN\" compose version >/dev/null 2>&1; then
|
|
\"\$DOCKER_BIN\" compose up -d --build
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
|
docker-compose up -d --build
|
|
else
|
|
echo \"No docker compose command found on remote host.\" >&2
|
|
exit 1
|
|
fi
|
|
'"
|
|
echo "Upload + image rebuild complete."
|
|
fi
|