备份前空间预估;manifest 的 archive 字段只在文件真的存在时才写
需求
- 写满盘这件事只做一件事:**备份前预测本次所需大小,并提示用户存储够不够**,
不再往"更复杂的占用控制"方向做。
实现
- Backup.ps1 新增只读的"备份前空间预估",在动手之前按清单顺序模拟一遍:
* 逐个条目枚举源目录得到真实源大小/文件数,并读取现有归档大小;
* 沿用主循环那套"源未更新就跳过"的判断,所以列出来的就是**本次真的会重打**的条目;
* 估算模型:临时归档写完时旧归档还在,那一刻占用 = 当前累计净增量 + 本次预估;
原子替换后净增量 = 预估 − 旧归档大小;峰值取整个过程的最大值;
* 预估归档大小:有历史归档取 min(源大小, 旧归档 × 1.3),没有则按"不压缩"的悲观值;
* 打印:可用空间、要重打的条目数(及跳过/缺源的数量)、逐条目明细(前 15 条)、
预计峰值新增与净增量,最后给一句结论——"空间足够"或"空间可能不够!…差 Z GB"。
* 不够时**只告警、不中断**:真正放不下的条目仍由逐条目守卫跳过。
- 新增 Sync-BaknretManifestArchive(Common.psm1,Backup/Restore 都在写 manifest 前调用):
维持不变式"manifest 里写了 archive 的记录,磁盘上就一定有那个文件",
把指向不存在归档的 archive 字段清空,但保留 source / action / 历史计数。
这样"源不存在的条目"不会再让 Restore 反复报"manifest 记录的归档不存在",
人工删掉归档(例如把它并进别的条目)之后记录也会自我纠正。
整理(本机备份集)
- 按用户确认,删除了已被 scoop.7z 覆盖的 scoop-config.7z 与 scoop-persist.7z
(删除前先 7z t 复验 scoop.7z:233 MB / 29478 项 / 顶层 [persist, scoop]),
并清掉 manifest 里这两条历史记录;24 条记录的 archive 现在全部存在于磁盘上。
测试
- Pester 88 项、零依赖单元 49 项、端到端 23 项,全部通过。
新增覆盖:对象数组名录、两种写法 × :+/-、同名目录拒绝执行、行尾 # 说明、
孤儿审计(含"manifest 里还有历史记录"的说明)、archive 字段一致性、空间预估输出。
This commit is contained in:
1 parent
43fa4e52dd
commit
7173e8ae10
5 files changed
+244
-4
No files matched your search
@@ -280,6 +280,12 @@ Describe '集成:手写路径 + :+ 追加 的打包与恢复' -Skip:(-not ($sc
|
||||
}
|
||||
}
|
||||
|
||||
It '备份前会打印空间预估与"够不够"的结论' {
|
||||
$script:AppendBackupRun.Output | Should -Match '备份前空间预估'
|
||||
$script:AppendBackupRun.Output | Should -Match '要重打'
|
||||
$script:AppendBackupRun.Output | Should -Match '结论:'
|
||||
}
|
||||
|
||||
It '备份成功,manifest.roots 记录两棵子树' {
|
||||
$script:AppendBackupRun.ExitCode | Should -Be 0
|
||||
$archive = @(Get-ChildItem -LiteralPath $script:AppendBackupDir -File -Filter *.7z)[0]
|
||||
@@ -414,3 +420,48 @@ Describe '条目从清单里消失后,旧归档必须被点名为孤儿' -Skip
|
||||
$script:OrphanRun.Output | Should -Match 'manifest 里还留着它的历史记录'
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
Describe 'manifest 一致性:archive 字段只在文件真的存在时才写' {
|
||||
# ============================================================================
|
||||
|
||||
BeforeAll {
|
||||
$script:SyncRoot = Join-Path $script:Sandbox 'sync'
|
||||
New-Item -ItemType Directory -Path $script:SyncRoot -Force | Out-Null
|
||||
Set-Content -LiteralPath (Join-Path $script:SyncRoot 'real.7z') 'x'
|
||||
|
||||
$script:SyncManifestPath = Join-Path $script:SyncRoot 'manifest.json'
|
||||
$manifest = Read-BaknretManifest -Path $script:SyncManifestPath
|
||||
$manifest.items['real'] = [pscustomobject]@{ archive = 'real.7z'; action = 'backed-up'; source = 'real' }
|
||||
$manifest.items['gone'] = [pscustomobject]@{ archive = 'gone.7z'; action = 'missing-source'; source = 'gone' }
|
||||
$manifest.items['none'] = [pscustomobject]@{ archive = $null; action = 'missing-source'; source = 'none' }
|
||||
Write-BaknretManifest -Path $script:SyncManifestPath -Manifest $manifest | Out-Null
|
||||
}
|
||||
|
||||
It '存在的归档保留 archive,不存在的被清空' {
|
||||
$manifest = Read-BaknretManifest -Path $script:SyncManifestPath
|
||||
$cleared = Sync-BaknretManifestArchive -Manifest $manifest -BackupDir $script:SyncRoot
|
||||
|
||||
$cleared.Count | Should -Be 1
|
||||
$cleared[0] | Should -Be 'gone'
|
||||
$manifest.items['real'].archive | Should -Be 'real.7z'
|
||||
$manifest.items['gone'].archive | Should -BeNullOrEmpty
|
||||
$manifest.items['none'].archive | Should -BeNullOrEmpty
|
||||
}
|
||||
|
||||
It '清空 archive 时保留条目本身的历史(source / action 不动)' {
|
||||
$manifest = Read-BaknretManifest -Path $script:SyncManifestPath
|
||||
$null = Sync-BaknretManifestArchive -Manifest $manifest -BackupDir $script:SyncRoot
|
||||
$manifest.items['gone'].source | Should -Be 'gone'
|
||||
$manifest.items['gone'].action | Should -Be 'missing-source'
|
||||
}
|
||||
|
||||
It '人工删掉归档之后再同步一次,记录会被纠正过来' {
|
||||
Remove-Item -LiteralPath (Join-Path $script:SyncRoot 'real.7z') -Force
|
||||
$manifest = Read-BaknretManifest -Path $script:SyncManifestPath
|
||||
$cleared = Sync-BaknretManifestArchive -Manifest $manifest -BackupDir $script:SyncRoot
|
||||
|
||||
$cleared | Should -Contain 'real'
|
||||
$manifest.items['real'].archive | Should -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user