引入软件名录:清单写软件名,归档名也用软件名
新功能 - 新增 SoftwareCatalog.psd1 —— "软件名 -> 目录"映射表,BackupList.txt 里 直接写软件名即可,归档名也就是软件名(FooClolor.7z), 不再是 FooClolor_from_C_+Programs.7z 这种由路径拼出来的名字。 - 三种写法可混用:软件名、字面路径(现有清单无需改写)、软件名 @pathname。 - 名录支持前缀补全(legendary -> legendary_2.0.4,只认 <名>_* / <名>-*)、 Variants(同名目录在多处)、Includes(分文件维护)。 - tools/Rename-Archives.ps1:存量归档重命名,默认试运行,逐份大小校验并重建 manifest。 - 归档名重复直接报错,不再静默互相覆盖。 两套测试全绿:单元 42 项、端到端 23 项(新增名录命名/解析/迁移用例)。 过程中修掉的缺陷 - Resolve-BackupEntry 里 @pathname 与 Unresolved 分支顺序错误, @pathname 会被静默吃掉(改名后仍用软件名)。 - 源目录被删除时解析器丢掉 Sources,导致恢复端把软件名当路径、 报 "Cannot bind argument to parameter 'Path' because it is an empty string"。 恢复的语义恰恰是"源不存在就要还原回去",现在 Sources 照旧给出。 - 源存在性检查曾被漏掉,Get-Item 对不存在路径抛异常会中断整轮备份; 且不能用 Join-Path 探测——目标盘符不存在时它会直接抛异常。 - 计划任务脚本外的 Caller 需要 -DryRun 才能验,已实跑确认。
This commit is contained in:
1 parent
dbc0c00554
commit
045d51ac9c
9 files changed
+1330
-143
No files matched your search
+88
-1
@@ -253,7 +253,94 @@ Test-Case 'Backup -DryRun:退出码 0、不写归档也不写 manifest' {
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 6. 失败路径:源不存在时必须留下可核对的记录
|
||||
# 6. 软件名录:清单里写软件名,归档名就是软件名
|
||||
# ============================================================================
|
||||
|
||||
$catRoot = Join-Path $WorkRoot 'catalog'
|
||||
$catSource = Join-Path $catRoot 'src'
|
||||
$catTarget = Join-Path $catSource 'My App' # 真实目录名与软件名刻意不同
|
||||
$catBackupDir = Join-Path $catRoot 'Backups'
|
||||
$catFile = Join-Path $catRoot 'SoftwareCatalog.psd1'
|
||||
$catList = Join-Path $catRoot 'list.txt'
|
||||
$catConfig = Join-Path $catRoot 'config.psd1'
|
||||
|
||||
New-Item -ItemType Directory -Path $catTarget -Force | Out-Null
|
||||
Set-Content -LiteralPath (Join-Path $catTarget 'data.txt') -Value 'catalog-test' -Encoding UTF8
|
||||
Set-Content -LiteralPath (Join-Path $catTarget 'skip.bin') -Value 'nope' -Encoding UTF8
|
||||
|
||||
[System.IO.File]::WriteAllText($catFile, "@{`n 'my-app' = '$catTarget'`n}`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($catList, "my-app :: skip.bin`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($catConfig, "@{ SoftwareCatalog = '$catFile' }`n", [System.Text.UTF8Encoding]::new($false))
|
||||
|
||||
& $backupScript -BackupListPath $catList -BackupDir $catBackupDir -ConfigPath $catConfig -Force -QuietTool
|
||||
$catExitCode = $LASTEXITCODE
|
||||
$catArchive = Join-Path $catBackupDir 'my-app.7z'
|
||||
|
||||
Test-Case '清单里写软件名 -> 归档名就是软件名' {
|
||||
Assert-Equal 0 $catExitCode
|
||||
Assert-FileExists $catArchive
|
||||
}
|
||||
|
||||
Test-Case '软件名条目的归档内容与历史布局一致(根目录仍是源目录名)' {
|
||||
$extract = Join-Path $catRoot 'verify'
|
||||
New-Item -ItemType Directory -Path $extract -Force | Out-Null
|
||||
$sevenZip = Get-Command 7z -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Source
|
||||
if ($sevenZip) {
|
||||
$null = Invoke-ExternalCommand -FilePath $sevenZip -ArgumentList @('x', '-bso0', '-bsp0', '-y', "-o$extract", $catArchive)
|
||||
# 归档文件名是软件名 my-app,但包内根目录是源目录名 My App
|
||||
Assert-FileExists (Join-Path $extract 'My App\data.txt')
|
||||
Assert-FileMissing (Join-Path $extract 'my-app') '包内不应多出一层软件名'
|
||||
Assert-FileMissing (Join-Path $extract 'My App\skip.bin') '排除模式以源目录名为前缀,仍然生效'
|
||||
}
|
||||
}
|
||||
|
||||
Test-Case '@pathname 覆盖:强制用路径命名算法(用独立备份目录,避免污染共享 manifest)' {
|
||||
$pathList = Join-Path $catRoot 'list-pathname.txt'
|
||||
$pathNameDir = Join-Path $catRoot 'Backups-pathname'
|
||||
[System.IO.File]::WriteAllText($pathList, "my-app @pathname`n", [System.Text.UTF8Encoding]::new($false))
|
||||
& $backupScript -BackupListPath $pathList -BackupDir $pathNameDir -ConfigPath $catConfig -Force -QuietTool
|
||||
Assert-Equal 0 $LASTEXITCODE
|
||||
|
||||
# 名录里存的是绝对路径,所以路径命名结果也基于它
|
||||
$expectedBase = Get-BackupBaseName -RawPath $catTarget
|
||||
Assert-FileExists (Join-Path $pathNameDir ($expectedBase + '.7z'))
|
||||
}
|
||||
|
||||
Test-Case '软件名录条目:删源后能按原路径恢复' {
|
||||
Remove-Item -LiteralPath $catTarget -Recurse -Force
|
||||
& $restoreScript -BackupListPath $catList -BackupDir $catBackupDir -ConfigPath $catConfig -Force
|
||||
Assert-Equal 0 $LASTEXITCODE
|
||||
Assert-FileExists (Join-Path $catTarget 'data.txt')
|
||||
Assert-Equal 'catalog-test' (Get-Content -LiteralPath (Join-Path $catTarget 'data.txt') -Raw).Trim()
|
||||
}
|
||||
|
||||
|
||||
Test-Case '归档名重复时直接报失败,不静默互相覆盖' {
|
||||
$dupList = Join-Path $catRoot 'dup.txt'
|
||||
[System.IO.File]::WriteAllText($dupList, "my-app`nmy-app`n", [System.Text.UTF8Encoding]::new($false))
|
||||
& $backupScript -BackupListPath $dupList -BackupDir $catBackupDir -ConfigPath $catConfig -Force -QuietTool
|
||||
Assert-Equal 1 $LASTEXITCODE '重复条目应让退出码为 1'
|
||||
}
|
||||
|
||||
Test-Case '字面路径不受名录影响,仍走路径命名' {
|
||||
$literalList = Join-Path $catRoot 'list-literal.txt'
|
||||
[System.IO.File]::WriteAllText($literalList, "$catTarget`n", [System.Text.UTF8Encoding]::new($false))
|
||||
& $backupScript -BackupListPath $literalList -BackupDir $catBackupDir -ConfigPath $catConfig -Force -QuietTool
|
||||
Assert-Equal 0 $LASTEXITCODE
|
||||
}
|
||||
|
||||
Test-Case '名录里没有该软件名时记为 missing-source,而不是崩掉' {
|
||||
$badList = Join-Path $catRoot 'bad.txt'
|
||||
[System.IO.File]::WriteAllText($badList, "no-such-app`n", [System.Text.UTF8Encoding]::new($false))
|
||||
& $backupScript -BackupListPath $badList -BackupDir $catBackupDir -ConfigPath $catConfig -Force -QuietTool
|
||||
Assert-Equal 0 $LASTEXITCODE '跳过不算失败'
|
||||
$rec = (Read-BaknretManifest -Path (Join-Path $catBackupDir 'manifest.json')).items['no-such-app']
|
||||
Assert-True ($null -ne $rec) '应留下记录'
|
||||
Assert-Equal 'missing-source' $rec.action
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 7. 失败路径:源不存在时必须留下可核对的记录
|
||||
# ============================================================================
|
||||
|
||||
$missingList = Join-Path $WorkRoot 'missing.txt'
|
||||
|
||||
Reference in new issue
Block a user