forked from Goko/JingTian-Rclone
feat: add Windows sync script
- Phase 1: One-way sync (Windows -> Server) for main folders - Phase 2: Bidirectional sync using rclone bisync for _LLM_Sync - Auto-detects rclone and BenjaminTeam folder paths - Comprehensive logging to %LOCALAPPDATA%\JingTian\logs - Supports verbose output with -VerboseOutput flag
This commit is contained in:
235
windows/sync.ps1
Normal file
235
windows/sync.ps1
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
JingTian rclone Sync Script
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Syncs the local BenjaminTeam folder with the remote Ubuntu server.
|
||||||
|
- Main folders: One-way sync (Windows -> Server)
|
||||||
|
- _LLM_Sync folder: Bidirectional sync
|
||||||
|
|
||||||
|
.PARAMETER LocalPath
|
||||||
|
Path to the local BenjaminTeam folder.
|
||||||
|
|
||||||
|
.PARAMETER RclonePath
|
||||||
|
Path to rclone.exe. Default: auto-detect
|
||||||
|
|
||||||
|
.PARAMETER LogDir
|
||||||
|
Directory for log files. Default: %LOCALAPPDATA%\JingTian\logs
|
||||||
|
|
||||||
|
.PARAMETER Verbose
|
||||||
|
Show detailed output during sync.
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[string]$LocalPath = "",
|
||||||
|
[string]$RclonePath = "",
|
||||||
|
[string]$LogDir = "$env:LOCALAPPDATA\JingTian\logs",
|
||||||
|
[switch]$VerboseOutput
|
||||||
|
)
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
$RemoteName = "jingtian-server"
|
||||||
|
$RemotePath = "/data/jingtian/BenjaminTeam"
|
||||||
|
$LLMSyncFolder = "_LLM_Sync"
|
||||||
|
|
||||||
|
# Find rclone if not specified
|
||||||
|
if (-not $RclonePath -or -not (Test-Path $RclonePath)) {
|
||||||
|
$possiblePaths = @(
|
||||||
|
"$env:LOCALAPPDATA\rclone\rclone.exe",
|
||||||
|
"C:\rclone\rclone.exe",
|
||||||
|
"rclone.exe"
|
||||||
|
)
|
||||||
|
foreach ($path in $possiblePaths) {
|
||||||
|
if (Test-Path $path) {
|
||||||
|
$RclonePath = $path
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $RclonePath)) {
|
||||||
|
Write-Error "rclone not found. Please run setup.ps1 first."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find LocalPath if not specified (check common locations)
|
||||||
|
if (-not $LocalPath -or -not (Test-Path $LocalPath)) {
|
||||||
|
$searchPaths = @(
|
||||||
|
"$env:USERPROFILE\Documents\BenjaminTeam",
|
||||||
|
"$env:USERPROFILE\Documents\Benjamin Team",
|
||||||
|
"D:\BenjaminTeam",
|
||||||
|
"C:\BenjaminTeam"
|
||||||
|
)
|
||||||
|
foreach ($path in $searchPaths) {
|
||||||
|
if (Test-Path $path) {
|
||||||
|
$LocalPath = $path
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $LocalPath)) {
|
||||||
|
Write-Error "BenjaminTeam folder not found. Please specify -LocalPath"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup logging
|
||||||
|
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
|
||||||
|
$logFile = Join-Path $LogDir "sync.log"
|
||||||
|
$detailLogFile = Join-Path $LogDir "sync_$timestamp.log"
|
||||||
|
|
||||||
|
if (-not (Test-Path $LogDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Log {
|
||||||
|
param([string]$Message, [string]$Level = "INFO")
|
||||||
|
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||||
|
$logLine = "[$ts] [$Level] $Message"
|
||||||
|
Add-Content -Path $logFile -Value $logLine
|
||||||
|
|
||||||
|
if ($VerboseOutput) {
|
||||||
|
switch ($Level) {
|
||||||
|
"ERROR" { Write-Host $logLine -ForegroundColor Red }
|
||||||
|
"WARN" { Write-Host $logLine -ForegroundColor Yellow }
|
||||||
|
"OK" { Write-Host $logLine -ForegroundColor Green }
|
||||||
|
default { Write-Host $logLine }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# MAIN SYNC LOGIC
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
Write-Log "========== Sync Started =========="
|
||||||
|
Write-Log "Local: $LocalPath"
|
||||||
|
Write-Log "Remote: ${RemoteName}:${RemotePath}"
|
||||||
|
|
||||||
|
$syncErrors = @()
|
||||||
|
$startTime = Get-Date
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Phase 1: One-way sync (Windows -> Server) for main folders
|
||||||
|
# Excludes _LLM_Sync which is handled separately
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
Write-Log "Phase 1: Syncing main folders (Windows -> Server)..."
|
||||||
|
|
||||||
|
$rcloneArgs = @(
|
||||||
|
"sync",
|
||||||
|
$LocalPath,
|
||||||
|
"${RemoteName}:${RemotePath}",
|
||||||
|
"--exclude", "$LLMSyncFolder/**",
|
||||||
|
"--transfers", "4",
|
||||||
|
"--checkers", "8",
|
||||||
|
"--contimeout", "60s",
|
||||||
|
"--timeout", "300s",
|
||||||
|
"--retries", "3",
|
||||||
|
"--low-level-retries", "10",
|
||||||
|
"--stats", "1m",
|
||||||
|
"--stats-one-line",
|
||||||
|
"--log-file", $detailLogFile,
|
||||||
|
"--log-level", "INFO"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($VerboseOutput) {
|
||||||
|
$rcloneArgs += "--progress"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = & $RclonePath @rcloneArgs 2>&1
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Log "Phase 1 complete: Main folders synced successfully" "OK"
|
||||||
|
} else {
|
||||||
|
Write-Log "Phase 1 warning: rclone exited with code $LASTEXITCODE" "WARN"
|
||||||
|
$syncErrors += "Main folder sync had warnings (exit code: $LASTEXITCODE)"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Log "Phase 1 error: $_" "ERROR"
|
||||||
|
$syncErrors += "Main folder sync failed: $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Phase 2: Bidirectional sync for _LLM_Sync folder
|
||||||
|
# Uses rclone bisync for true bidirectional sync
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
Write-Log "Phase 2: Syncing _LLM_Sync folder (bidirectional)..."
|
||||||
|
|
||||||
|
$llmLocalPath = Join-Path $LocalPath $LLMSyncFolder
|
||||||
|
$llmRemotePath = "${RemoteName}:${RemotePath}/${LLMSyncFolder}"
|
||||||
|
|
||||||
|
# Ensure local _LLM_Sync exists
|
||||||
|
if (-not (Test-Path $llmLocalPath)) {
|
||||||
|
New-Item -ItemType Directory -Path $llmLocalPath -Force | Out-Null
|
||||||
|
Write-Log "Created local _LLM_Sync folder"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if bisync has been initialized (look for .rclone-bisync directory)
|
||||||
|
$bisyncStateDir = "$env:USERPROFILE\.cache\rclone\bisync"
|
||||||
|
$bisyncStateFile = Join-Path $bisyncStateDir "*.lst"
|
||||||
|
|
||||||
|
# For first run, we need to use --resync to initialize
|
||||||
|
$needsResync = $false
|
||||||
|
if (-not (Test-Path $bisyncStateDir) -or -not (Get-ChildItem $bisyncStateFile -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Log "First bisync run detected, will initialize with --resync"
|
||||||
|
$needsResync = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$bisyncArgs = @(
|
||||||
|
"bisync",
|
||||||
|
$llmLocalPath,
|
||||||
|
$llmRemotePath,
|
||||||
|
"--transfers", "4",
|
||||||
|
"--checkers", "8",
|
||||||
|
"--contimeout", "60s",
|
||||||
|
"--timeout", "300s",
|
||||||
|
"--retries", "3",
|
||||||
|
"--log-file", $detailLogFile,
|
||||||
|
"--log-level", "INFO"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($needsResync) {
|
||||||
|
$bisyncArgs += "--resync"
|
||||||
|
$bisyncArgs += "--resync-mode", "newer"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($VerboseOutput) {
|
||||||
|
$bisyncArgs += "--progress"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = & $RclonePath @bisyncArgs 2>&1
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Log "Phase 2 complete: _LLM_Sync folder synced successfully" "OK"
|
||||||
|
} else {
|
||||||
|
# bisync can return non-zero for various reasons, check output
|
||||||
|
Write-Log "Phase 2 warning: bisync exited with code $LASTEXITCODE" "WARN"
|
||||||
|
$syncErrors += "_LLM_Sync bisync had warnings (exit code: $LASTEXITCODE)"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Log "Phase 2 error: $_" "ERROR"
|
||||||
|
$syncErrors += "_LLM_Sync sync failed: $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Summary
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
$endTime = Get-Date
|
||||||
|
$duration = $endTime - $startTime
|
||||||
|
|
||||||
|
Write-Log "========== Sync Completed =========="
|
||||||
|
Write-Log "Duration: $($duration.TotalSeconds.ToString('F1')) seconds"
|
||||||
|
|
||||||
|
if ($syncErrors.Count -gt 0) {
|
||||||
|
Write-Log "Completed with $($syncErrors.Count) warning(s):" "WARN"
|
||||||
|
foreach ($err in $syncErrors) {
|
||||||
|
Write-Log " - $err" "WARN"
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
} else {
|
||||||
|
Write-Log "All syncs completed successfully" "OK"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user