Files
ulthon_admin/source/stack/docker-dev-sync/source/docker/sync.sh
augushong ddaa0ca5a9 feat(stack): 新增 docker-dev-sync 模式,优化 Windows 下 Docker 开发 I/O 性能
- 新增 source/stack/docker-dev-sync/ 模式目录
- 宿主代码映射到 /var/www/source(bind mount 中转)
- 容器内 rsync 定时同步到 /var/www/html(原生文件系统)
- vendor 由 Docker build 管理,不参与同步
- rsync 使用 --no-perms 避免保留 Windows 源文件权限
- 排除 docker-dev/、runtime/、.git/ 等无关目录
- SYNC_INTERVAL 环境变量可配置轮询间隔(默认 3 秒)
- 更新 stack.json 注册模式并声明 sync.sh 为托管文件
- 调整 CI 构建流程:先安装依赖再切换 stack 模式
2026-06-01 22:32:29 +08:00

130 lines
3.5 KiB
Bash

#!/bin/bash
# ============================================
# sync.sh - Host-to-Container code sync script
# ============================================
# Syncs code from /var/www/source (bind mount from host)
# to /var/www/html (container-native filesystem, fast I/O).
#
# Usage:
# sync.sh init - Perform initial full sync, then exit
# sync.sh watch - Run periodic incremental sync (blocking)
# sync.sh - Same as: init + watch
#
# Environment variables:
# SYNC_INTERVAL - Polling interval in seconds (default: 3)
# SYNC_EXTRAS - Additional rsync exclude patterns (space-separated)
# ============================================
SOURCE_DIR="/var/www/source/"
TARGET_DIR="/var/www/html/"
SYNC_INTERVAL=${SYNC_INTERVAL:-3}
# Build rsync exclude patterns
build_exclude_args() {
EXCLUDE_ARGS=(
--exclude='.git'
--exclude='.gitignore'
--exclude='.sisyphus'
--exclude='.opencode'
--exclude='.agents'
--exclude='.docker-dev-sync'
--exclude='.docker-dev.env'
--exclude='.docker-dev'
--exclude='docker-dev'
--exclude='docker-dev-sync'
--exclude='node_modules'
--exclude='runtime'
--exclude='.idea'
--exclude='.vscode'
--exclude='*.sock'
--exclude='.env'
# vendor is managed by Docker build (composer install), do not overwrite
--exclude='vendor'
)
# Add extra excludes if provided
if [ -n "$SYNC_EXTRAS" ]; then
for pattern in $SYNC_EXTRAS; do
EXCLUDE_ARGS+=(--exclude="$pattern")
done
fi
}
# Sync .env separately (excluded from rsync to avoid overwriting on rebuild)
sync_env() {
if [ -f "/var/www/source/.env" ]; then
cp /var/www/source/.env /var/www/html/.env 2>/dev/null
fi
}
# rsync common flags
# --no-perms --no-owner --no-group: don't preserve source permissions (Windows mounts have bad perms)
RSYNC_FLAGS="-a --no-perms --no-owner --no-group"
# ---- Initial full sync ----
do_init() {
build_exclude_args
echo "============================================"
echo "[sync] Starting initial full sync..."
echo "[sync] Source: ${SOURCE_DIR}"
echo "[sync] Target: ${TARGET_DIR}"
echo "============================================"
rsync ${RSYNC_FLAGS} --delete "${EXCLUDE_ARGS[@]}" "$SOURCE_DIR" "$TARGET_DIR"
if [ $? -eq 0 ]; then
echo "[sync] Initial sync complete."
else
echo "[sync] WARNING: Initial sync had errors (source may not be mounted yet)."
fi
sync_env
}
# ---- Periodic incremental sync (blocking) ----
do_watch() {
build_exclude_args
echo "[sync] Starting periodic sync (interval: ${SYNC_INTERVAL}s)..."
while true; do
sleep "$SYNC_INTERVAL"
# Check if source directory is mounted and accessible
if [ ! -d "/var/www/source" ]; then
continue
fi
# Incremental sync (only changed files)
rsync ${RSYNC_FLAGS} --delete "${EXCLUDE_ARGS[@]}" "$SOURCE_DIR" "$TARGET_DIR" 2>/dev/null
# Sync .env separately
sync_env
done
}
# ---- Main ----
MODE="${1:-all}"
case "$MODE" in
init)
do_init
;;
watch)
do_watch
;;
all|"")
do_init
do_watch
;;
*)
echo "Usage: $0 [init|watch]"
echo " init - Initial full sync, then exit"
echo " watch - Periodic incremental sync (blocking)"
echo " (no args) - init + watch"
exit 1
;;
esac