sync-engine 应用图标

把目录稳妥地同步到另一处

macOS 原生 · SwiftUI + Swift · 零第三方依赖

用 SHA-256 内容指纹而不是修改时间判断变更 —— 外接盘常是 FAT/exFAT(时间戳精度只有 2 秒), 时钟也会漂移,靠时间戳判变更必然出错。目标端支持本地目录、SMB 与 WebDAV。

macOS 14+ Swift 6 构建 第三方依赖 76 项单元测试 MIT 许可
功能

已实现的能力

下面每一条都是可验证的已实现功能。尚未实现的部分在「进度」一节里逐条列明。

内容指纹判变更

逐文件 SHA-256,用内容而非时间戳判断是否改动。时间戳只用来缩小候选范围,不参与最终裁决。

并发哈希

多核并行、滑动窗口控制内存。实测 6.3 GB 目录树上 10 路并发比串行快 4.2 倍(283 → 1179 MB/s)。

本地目录目标端

路径逃逸双重校验:词法归一化 + 软链接解析,且校验目标自身而非只校验父目录。

SMB 目标端

走系统 NetFS 框架挂载后复用本地驱动,读写语义与本地目录天然一致。自动复用已挂载的卷,不重复挂载。

WebDAV 目标端

URLSession 直发 PROPFIND/PUT/MKCOL/DELETE,自写 multistatus 解析。Basic/Digest 认证,可选中放行自签名证书。

凭据进系统钥匙串

任务结构里只保存用户名,密码不落配置文件、不进日志、不出现在崩溃报告里。

截图

实际界面

以下截图取自真实运行的 v1.0.0 构建,非设计稿。主题支持浅色 / 深色 / 跟随系统。

sync-engine 浅色主题界面
浅色主题 · 同步任务页。强调色为深一档的绿,以保证白底上的对比度。
sync-engine 深色主题界面
深色主题 · 使用品牌色 #32CD32,在深色底上对比度约 7.9:1。
sync-engine 跟随系统外观
跟随系统 · 解析为系统当前的具体外观,而不是交给系统留空 —— 后者在运行中切换会导致详情区渲染不出来。
进度

已完成 / 尚未实现

v1.0.0 的功能并不完整。把这一点写清楚,比让用户下载后才发现更有价值 —— 未实现的部分在应用界面上也有同样的标注。

已完成

  • 目录扫描 —— 显式栈递归、不跟随软链接、三阶段分开计时
  • 并发 SHA-256 —— 滑动窗口,10 路比串行快 4.2 倍
  • 本地目录驱动 —— 含路径逃逸双重校验
  • SMB 驱动 —— 系统 NetFS 挂载 + 复用已挂载卷
  • WebDAV 驱动 —— 完整读写原语,直发 WebDAV 方法
  • 钥匙串凭据 —— 密码不落配置文件
  • 界面外壳 —— 三功能区、菜单栏常驻、外观三态、任务可编辑

尚未实现

  • 传输能力 —— 目前只能扫描并列文件,不会真正写入目标端
  • 增量同步 —— 每次全量重算哈希,无哈希缓存
  • 三方比对与冲突裁决 —— 目标端被改动过的文件不会被识别
  • 同步删除 —— 因缺少冲突裁决,该开关当前不存在
  • 断点续传 —— 传输未实现,无从谈起
  • FSEvents 监听 —— 只能手动触发扫描,扫描期间不可取消
  • 任务与日志持久化 —— 退出即丢
下载

v1.0.0

未公证的临时签名版本,需要 macOS 14 或更高。

Apple Silicon(M 系列) sync-engine-v1.0.0-arm64.dmg
下载
Intel(x86_64) sync-engine-v1.0.0-x86_64.dmg
下载
首次打开会被 Gatekeeper 拦下,这是预期行为 —— 安装包为临时签名、未经 Apple 公证。 把 sync-engine.app 拖进「应用程序」后,右键 → 打开, 或到「系统设置 → 隐私与安全性」点「仍要打开」。放行一次即可,之后正常双击启动。

全部版本见 Releases

构建

从源码构建

只需 Command Line Tools,不需要打开 Xcode。

# 克隆并构建
git clone https://github.com/zdx8/SyncEngine-macOS.git
cd SyncEngine-macOS/SyncApp

swift build                 # 构建
swift test                  # 单元测试(76 项)
bash Scripts/build_app.sh   # 打包成 dist/sync-engine.app
open dist/sync-engine.app   # 运行

# 打发行版安装包(版本号取自 build_app.sh,不在两处维护)
bash Scripts/make_dmg.sh 1.0.0 arm64
bash Scripts/make_dmg.sh 1.0.0 x86_64

无界面验证

# 跑的是打包产物本身 —— 即用户拿到的那个二进制
dist/sync-engine.app/Contents/MacOS/sync-engine --selfcheck

# 性能基准:指定并发度
dist/sync-engine.app/Contents/MacOS/sync-engine --bench ~/目录 10
验证

不依赖肉眼的验证

这个项目的验证原则是:任何结论都要由可机器判定的证据支撑,而不是「看起来对」。

手段覆盖
引擎逻辑 swift test(76 项) 哈希向量、扫描统计、软链策略、路径逃逸、计时不变量、错误路径
存储驱动 swift test(真实 IO) 进程内真实 WebDAV 服务端做完整往返;对真实 SMB 挂载做只读验证
交付产物 --selfcheck(16 项) 真实 .app 内那份二进制能否跑通引擎与驱动接线
界面渲染 单窗口截图 + 位图像素分析 主题一致性、强调色是否统一、内容是否真的画出来了

两条值得一提的做法:断言只验结构性不变量(如「分项耗时之和 ≤ 总耗时」), 不验机器相关的具体数值 —— 后者必然变成 flaky 测试; 以及只在某条操作路径上出现的缺陷,必须把那条路径本身做成可复现的 (例如「运行中切换主题」无法靠静态启动验证,因此应用内置了走同一入口的诊断钩子)。