Commit Graph
2 Commits
Author SHA1 Message Date
chakcy 8489b4052d feat: SQLiteVFS.add_bytes()/commit()/rename_snapshot()
tests / ubuntu-latest / py3.13 (push) Has been cancelled
tests / windows-latest / py3.13 (push) Has been cancelled
tests / ubuntu-latest / py3.13 (pull_request) Has been cancelled
tests / windows-latest / py3.13 (pull_request) Has been cancelled
三处写入侧的缺口,都是被下游"模块银行"(module_bank,把模块打包进 svfs 包
再按需导入)真实逼出来的:

- add_bytes(rel_path, data, ...):从内存写文件,不经过磁盘。受保护的字节码、
  密文这类绝对不能落盘的内容因此可以直接入库——先写临时文件再 add_file 会把
  明文留在磁盘上,而磁盘残留是这类工具最容易被忽视的泄漏点。
- make_parents=True(默认):补齐缺失的父目录行。list_directory 是按
  parent_path 过滤的,而"某个目录存在"的唯一标志就是它自己那一行——少一层
  目录行,export_directory 从根就递归不下去,export_filesystem() 会静默导出
  一个空目录。add_file 一并受益(内部改为读盘后调 add_bytes,行为不变,
  含 created_time 取 st_ctime 这个细节)。
- commit=False + 公开的 commit():一组相关文件可以写成一个事务,中途任何一步
  失败整批回滚,不会在库里留下半套数据。
- rename_snapshot(id, name):create/list/delete 都有,唯独缺改名;而"把发布名
  落在快照上"是版本管理的基本动作。**定格一个版本靠的正是它**:先给当前快照
  改名,再另建一个工作快照接手后续写入——直接 create_snapshot(name) 的话,
  名字落在会继续被写入的那一版上,下一次改动就把这个"版本"改了。
- DEFAULT_DIR_PERMISSIONS:补出来的目录行用 0o755(表的默认值 0o644 是按文件
  定的,套到目录上会让导出的目录不可进入)。
- 版本 0.3.0 → 0.4.0(add_file 开始建父目录行属于可见的行为变化)。

测试:tests/test_core_add_bytes.py(22 条:往返/空内容/bytearray/时间戳与权限/
压缩/去重/覆盖/空路径/只读拒绝/父目录行与 export 目录树/批量提交与回滚/
add_file 委托行为)+ tests/test_snapshots.py 新增 5 条改名用例(只改名字不动
内容与摘要/空名拒绝/不存在的快照报错/允许重名/改名+派生工作快照之后
已定格的版本不被后续写入改动)。完整测试套件逐个文件跑通。
2026-09-20 14:58:17 +08:00
chakcy ecdfacc620 fix+feat: 修复打包/解包主链路,并把存储层重建为内容寻址 + 快照
起始状态:主链路 100% 不可用,而且失败被静默吞掉——打包后库里 0 个文件、
界面仍打印"文件数量: N";解包导出 0 个文件并在磁盘上生成几百层 sub/sub/sub 垃圾目录。

缺陷修复(4 个 P0 + 12 个 P1,逐条见 BUG_REPORT.md):
- 建表列名 compresse_algo 与 INSERT/read_file 用的 compress_algo 不一致
- list_directory 按 path 而非 parent_path 过滤,导致导出无限自递归
- CLI --ignore-timestamps 把 export_filesystem 赋成引用自身的 lambda
- add_file 缺少 commit(直接调用 API 时静默丢数据)
- LIKE 前缀误伤兄弟目录(删 doc 连带删 docs);mv_dir 二次改名
- 失败路径一律返回 exit code 0;--exclude 是子串匹配而非 glob
- FolderPacker.add_file 反向调用 export_file_safe,会用库内内容覆盖源文件

存储层(schema v3,格式变更,提供 vfsmigrate 迁移):
- 内容移入 blobs(hash PRIMARY KEY):相同内容只存一份,跨路径/跨快照共享
- files 的唯一约束改为 UNIQUE(snapshot_id, path):一个库存多个版本
- 完整性:每文件 sha256 + 快照级摘要 + HMAC-SHA256 签名,只读连接即可验证
- 增量打包:按 mtime+size 或 sha256 只写变化项,未变文件不重写不重压
- get_file_info 不再返回 content(元数据查询不该搬 BLOB)

新增能力:
- 可选 FastAPI 静态文件插件(extras,核心仍零第三方依赖)
- 内容寻址发布到对象存储 + 逐对象校验的取回客户端
- 压缩默认改回 zlib:实测比自研哈夫曼体积小 1/3~1/170、快数百倍

其它:
- P2-4:时间戳显式转字符串,清掉 1240 条 DeprecationWarning(盘上格式不变)
- read_file 负数 offset/size 改为报错(原先会走切片语义从末尾取)
- requires-python 从 >=3.7 改为按实际 API 推导的 >=3.9

测试:0 → 343 个用例,纯标准库 unittest,有/无 FastAPI 两种环境都跑通。
证据见 docs/evidence-*.txt。
2026-09-14 00:11:42 +08:00