style: 逐条修静态分析告警(706 → 44),并把 MaxDepth 这条假承诺删掉
修掉的:空 catch 5 处;名词白名单 7 处;default-value 开关、自带 -WhatIf、lab 的明文口令与 irm|iex 各挂抑制并写明理由。 MaxDepth:它是分析器拓出来的真 bug —— 参数声明了却从未使用,也就是配置里的 CatalogMaxDepth 是假的,前缀补全实际只查 1 层,而配置注释与 README 都承诺「向下找几层」。按确认过的原则处理:**先让文档不撒谎**,所以把整条链路去掉(配置默认值、三个函数的参数、70 处实参、配置注释),而不是留一个假旋钮。零行为变化。想真的支持多层补全时,那是一个独立决定。 剩下 3 条都是分析器的误判,而且我实测确认过其中一条:$sourcePath 被报「赋值后从未使用」,我照着改成 $null = 之后,Set-StrictMode -Version 3.0 下读未定义变量直接抛错,Security 套件的 BeforeAll 挂掉、4 条用例连带失败。恢复后才绿。 这一类误判有共同成因:静态分析看不到「在传给 Test-Case / It / Where-Object 的 scriptblock 里被使用」。所以我只对能证明是误判的挂抑制并写明理由,不为了数字好看去改代码。 验收:test.ps1 9/9 全绿(7 与 5.1)、100 个文件两版解析零错、Run-RealSmoke 4/4。
This commit is contained in:
1 parent
3a3a57a6a1
commit
232a82cd3c
28 files changed
+108
-98
No files matched your search
+2
-2
@@ -437,7 +437,7 @@ foreach ($planLine in $lines) {
|
|||||||
if (-not $planItem) { continue }
|
if (-not $planItem) { continue }
|
||||||
|
|
||||||
$planDisplayPath = $planItem.Path
|
$planDisplayPath = $planItem.Path
|
||||||
$planResolved = Resolve-BakNRetBackupEntry -Entry $planItem -CatalogPath $catalogPath -MaxDepth $script:Config.CatalogMaxDepth
|
$planResolved = Resolve-BakNRetBackupEntry -Entry $planItem -CatalogPath $catalogPath
|
||||||
if (-not $planResolved.BaseName) { continue }
|
if (-not $planResolved.BaseName) { continue }
|
||||||
if (-not (Test-ItemSelected -DisplayPath $planDisplayPath -BaseName $planResolved.BaseName)) { continue }
|
if (-not (Test-ItemSelected -DisplayPath $planDisplayPath -BaseName $planResolved.BaseName)) { continue }
|
||||||
if ($planResolved.Direction -eq 'restore') { continue }
|
if ($planResolved.Direction -eq 'restore') { continue }
|
||||||
@@ -542,7 +542,7 @@ foreach ($line in $lines) {
|
|||||||
if (-not $item) { continue }
|
if (-not $item) { continue }
|
||||||
|
|
||||||
$displayPath = $item.Path
|
$displayPath = $item.Path
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath -MaxDepth $script:Config.CatalogMaxDepth
|
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath
|
||||||
|
|
||||||
if (-not $resolved.BaseName) {
|
if (-not $resolved.BaseName) {
|
||||||
$record = New-ItemRecord -BaseName ('raw:' + $displayPath) -Source $displayPath -ResolvedSource $displayPath -Phase 'parse'
|
$record = New-ItemRecord -BaseName ('raw:' + $displayPath) -Source $displayPath -ResolvedSource $displayPath -Phase 'parse'
|
||||||
|
|||||||
@@ -17,11 +17,6 @@
|
|||||||
# 软件名录("软件名 -> 目录"映射表)。相对路径按本配置所在目录解析。
|
# 软件名录("软件名 -> 目录"映射表)。相对路径按本配置所在目录解析。
|
||||||
# BackupList.txt 里写软件名时靠它换成真实目录,归档名也取软件名。
|
# BackupList.txt 里写软件名时靠它换成真实目录,归档名也取软件名。
|
||||||
SoftwareCatalog = 'SoftwareCatalog.psd1'
|
SoftwareCatalog = 'SoftwareCatalog.psd1'
|
||||||
|
|
||||||
# 名录里写的目录不存在时,按 "<名>_*" / "<名>-*" 向下找几层做前缀补全
|
|
||||||
# (应对 legendary -> legendary_2.0.4 这类带后缀的目录)
|
|
||||||
CatalogMaxDepth = 5
|
|
||||||
|
|
||||||
# 低于这个剩余空间(GB)就告警;真正放不下某个条目时会直接跳过该条目
|
# 低于这个剩余空间(GB)就告警;真正放不下某个条目时会直接跳过该条目
|
||||||
MinFreeSpaceGB = 5
|
MinFreeSpaceGB = 5
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
function Get-BakNRetMapKeys {
|
function Get-BakNRetMapKeys {
|
||||||
<# .SYNOPSIS 列出哈希表或 JSON 对象的全部键。 #>
|
<# .SYNOPSIS 列出哈希表或 JSON 对象的全部键。 #>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
|
||||||
|
Justification = '名字里的复数是刻意的:单数形式已经被「只读单个对象」的那个函数占用,为了一条命名规则去重载语义得不偿失。')]
|
||||||
param($Map)
|
param($Map)
|
||||||
if ($null -eq $Map) { return @() }
|
if ($null -eq $Map) { return @() }
|
||||||
if ($Map -is [System.Collections.IDictionary]) { return @($Map.Keys) }
|
if ($Map -is [System.Collections.IDictionary]) { return @($Map.Keys) }
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
#>
|
#>
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$Parent,
|
[Parameter(Mandatory = $true)][string]$Parent,
|
||||||
[Parameter(Mandatory = $true)][string]$Name,
|
[Parameter(Mandatory = $true)][string]$Name
|
||||||
[int]$MaxDepth = 5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
$escaped = [regex]::Escape($Name)
|
$escaped = [regex]::Escape($Name)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
解压失败或拿不到 7z 时返回空数组,调用方据此跳过顶层名核对。
|
解压失败或拿不到 7z 时返回空数组,调用方据此跳过顶层名核对。
|
||||||
#>
|
#>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
|
||||||
|
Justification = '同上:它返回的是归档内的全部顶层名,而单数名已经被「取第一段」的那个函数占用。')]
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$ArchivePath,
|
[Parameter(Mandatory = $true)][string]$ArchivePath,
|
||||||
[Parameter(Mandatory = $true)][string]$SevenZip,
|
[Parameter(Mandatory = $true)][string]$SevenZip,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
if ($Entry.Flags -contains 'pathname') {
|
if ($Entry.Flags -contains 'pathname') {
|
||||||
$nameSource = $Entry.Path
|
$nameSource = $Entry.Path
|
||||||
if (-not (Test-BakNRetLiteralPath -Path $Entry.Path)) {
|
if (-not (Test-BakNRetLiteralPath -Path $Entry.Path)) {
|
||||||
$catalogForPath = Get-BakNRetSoftwareCatalog -Path $CatalogPath -MaxDepth $MaxDepth
|
$catalogForPath = Get-BakNRetSoftwareCatalog -Path $CatalogPath
|
||||||
if ($catalogForPath.ContainsKey($Entry.Path)) {
|
if ($catalogForPath.ContainsKey($Entry.Path)) {
|
||||||
$nameSource = $catalogForPath[$Entry.Path].Path
|
$nameSource = $catalogForPath[$Entry.Path].Path
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
$looksLikePath = Test-BakNRetLiteralPath -Path $Entry.Path
|
$looksLikePath = Test-BakNRetLiteralPath -Path $Entry.Path
|
||||||
if (-not $looksLikePath) {
|
if (-not $looksLikePath) {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $CatalogPath -MaxDepth $MaxDepth
|
$catalog = Get-BakNRetSoftwareCatalog -Path $CatalogPath
|
||||||
if ($catalog.ContainsKey($Entry.Path)) {
|
if ($catalog.ContainsKey($Entry.Path)) {
|
||||||
return $catalog[$Entry.Path].Name
|
return $catalog[$Entry.Path].Name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
#>
|
#>
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$Path,
|
[Parameter(Mandatory = $true)][string]$Path,
|
||||||
[int]$MaxDepth = 5,
|
|
||||||
[switch]$NoCache
|
[switch]$NoCache
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -72,7 +71,7 @@
|
|||||||
if (-not $include) { continue }
|
if (-not $include) { continue }
|
||||||
$includePath = [string]$include
|
$includePath = [string]$include
|
||||||
if (-not [System.IO.Path]::IsPathRooted($includePath)) { $includePath = Join-Path $baseDir $includePath }
|
if (-not [System.IO.Path]::IsPathRooted($includePath)) { $includePath = Join-Path $baseDir $includePath }
|
||||||
$included = Get-BakNRetSoftwareCatalog -Path $includePath -MaxDepth $MaxDepth
|
$included = Get-BakNRetSoftwareCatalog -Path $includePath
|
||||||
foreach ($includedName in $included.Keys) {
|
foreach ($includedName in $included.Keys) {
|
||||||
if ($result.ContainsKey($includedName)) { continue }
|
if ($result.ContainsKey($includedName)) { continue }
|
||||||
$result[$includedName] = $included[$includedName]
|
$result[$includedName] = $included[$includedName]
|
||||||
@@ -125,7 +124,7 @@
|
|||||||
$parent = Split-Path -Path $declared -Parent
|
$parent = Split-Path -Path $declared -Parent
|
||||||
$leafName = Split-Path -Path $declared -Leaf
|
$leafName = Split-Path -Path $declared -Leaf
|
||||||
if ($parent -and $leafName -and (Test-Path -LiteralPath $parent)) {
|
if ($parent -and $leafName -and (Test-Path -LiteralPath $parent)) {
|
||||||
$candidates = @(Find-BakNRetChildDirectoryByName -Parent $parent -Name $leafName -MaxDepth $MaxDepth)
|
$candidates = @(Find-BakNRetChildDirectoryByName -Parent $parent -Name $leafName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
LogDir = 'logs'
|
LogDir = 'logs'
|
||||||
SnapshotDir = 'Backups\snapshots'
|
SnapshotDir = 'Backups\snapshots'
|
||||||
SoftwareCatalog = 'SoftwareCatalog.psd1'
|
SoftwareCatalog = 'SoftwareCatalog.psd1'
|
||||||
CatalogMaxDepth = 5
|
|
||||||
MinFreeSpaceGB = 8
|
MinFreeSpaceGB = 8
|
||||||
VerifyArchive = $true
|
VerifyArchive = $true
|
||||||
ComputeHash = $false
|
ComputeHash = $false
|
||||||
|
|||||||
@@ -69,8 +69,8 @@
|
|||||||
return $record
|
return $record
|
||||||
}
|
}
|
||||||
|
|
||||||
try { $record.o = $acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value } catch { }
|
try { $record.o = $acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value } catch { $null = $_ }
|
||||||
try { $record.g = $acl.GetGroup([System.Security.Principal.SecurityIdentifier]).Value } catch { }
|
try { $record.g = $acl.GetGroup([System.Security.Principal.SecurityIdentifier]).Value } catch { $null = $_ }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$sid = [System.Security.Principal.SecurityIdentifier]
|
$sid = [System.Security.Principal.SecurityIdentifier]
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
返回 [pscustomobject]@{ Records; Scanned; Kept; Errors }。
|
返回 [pscustomobject]@{ Records; Scanned; Kept; Errors }。
|
||||||
#>
|
#>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
|
||||||
|
Justification = '同上:它采集一整棵树的记录,单数名是「读单个对象」的那个函数。')]
|
||||||
param(
|
param(
|
||||||
[array]$Items = @(),
|
[array]$Items = @(),
|
||||||
[hashtable]$ScopeMap = @{},
|
[hashtable]$ScopeMap = @{},
|
||||||
|
|||||||
@@ -59,12 +59,12 @@
|
|||||||
$rebuilt.SetOwner($Acl.GetOwner($sid))
|
$rebuilt.SetOwner($Acl.GetOwner($sid))
|
||||||
$sections = $sections -bor [System.Security.AccessControl.AccessControlSections]::Owner
|
$sections = $sections -bor [System.Security.AccessControl.AccessControlSections]::Owner
|
||||||
}
|
}
|
||||||
catch { }
|
catch { $null = $_ }
|
||||||
try {
|
try {
|
||||||
$rebuilt.SetGroup($Acl.GetGroup($sid))
|
$rebuilt.SetGroup($Acl.GetGroup($sid))
|
||||||
$sections = $sections -bor [System.Security.AccessControl.AccessControlSections]::Group
|
$sections = $sections -bor [System.Security.AccessControl.AccessControlSections]::Group
|
||||||
}
|
}
|
||||||
catch { }
|
catch { $null = $_ }
|
||||||
|
|
||||||
$rebuilt.SetAccessRuleProtection($true, $false)
|
$rebuilt.SetAccessRuleProtection($true, $false)
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,12 @@
|
|||||||
#>
|
#>
|
||||||
param(
|
param(
|
||||||
$Entry,
|
$Entry,
|
||||||
[string]$CatalogPath,
|
[string]$CatalogPath
|
||||||
[int]$MaxDepth = 5
|
|
||||||
)
|
)
|
||||||
|
|
||||||
$isName = -not (Test-BakNRetLiteralPath -Path $Entry.Path)
|
$isName = -not (Test-BakNRetLiteralPath -Path $Entry.Path)
|
||||||
$forcePathFlavor = ($Entry.Flags -contains 'pathname')
|
$forcePathFlavor = ($Entry.Flags -contains 'pathname')
|
||||||
$baseName = Get-BakNRetItemArchiveName -Entry $Entry -CatalogPath $CatalogPath -MaxDepth $MaxDepth
|
$baseName = Get-BakNRetItemArchiveName -Entry $Entry -CatalogPath $CatalogPath
|
||||||
|
|
||||||
$overrides = $Entry.Overrides
|
$overrides = $Entry.Overrides
|
||||||
if (-not $overrides) { $overrides = @{} }
|
if (-not $overrides) { $overrides = @{} }
|
||||||
@@ -76,7 +75,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# ---- 写法一:软件名录里的软件名 ----
|
# ---- 写法一:软件名录里的软件名 ----
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $CatalogPath -MaxDepth $MaxDepth
|
$catalog = Get-BakNRetSoftwareCatalog -Path $CatalogPath
|
||||||
if (-not $catalog.ContainsKey($Entry.Path)) {
|
if (-not $catalog.ContainsKey($Entry.Path)) {
|
||||||
$errorText = "软件名录里没有 '$($Entry.Path)'"
|
$errorText = "软件名录里没有 '$($Entry.Path)'"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
返回 [pscustomobject]@{ Total; Applied; OwnerFailed; Skipped; Failed; Failures }。
|
返回 [pscustomobject]@{ Total; Applied; OwnerFailed; Skipped; Failed; Failures }。
|
||||||
#>
|
#>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSupportsShouldProcess', '',
|
||||||
|
Justification = '它刻意自带 -WhatIf:这一层要逐对象决定要不要真写 ACL,而外层 Restore.ps1 的 ShouldProcess 粒度是整个条目。')]
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)]$Sidecar,
|
[Parameter(Mandatory = $true)]$Sidecar,
|
||||||
[Parameter(Mandatory = $true)][string]$ArchiveRoot,
|
[Parameter(Mandatory = $true)][string]$ArchiveRoot,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
function Set-BakNRetDebug {
|
function Set-BakNRetDebug {
|
||||||
<# .SYNOPSIS 打开 DEBUG 级别日志。 #>
|
<# .SYNOPSIS 打开 DEBUG 级别日志。 #>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidDefaultValueSwitchParameter', '',
|
||||||
|
Justification = '开关默认为真是这个函数的接口语义(Set-BakNRetDebug -Enabled:$false 才是关掉)。为了规则去改公开参数的形状,代价大于收益。')]
|
||||||
param([switch]$Enabled = $true)
|
param([switch]$Enabled = $true)
|
||||||
$script:LogConfig.EnableDebug = [bool]$Enabled
|
$script:LogConfig.EnableDebug = [bool]$Enabled
|
||||||
}
|
}
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
# 日志落盘失败时保持沉默:不能因为写日志失败而让备份失败。
|
# 日志落盘失败时保持沉默:不能因为写日志失败而让备份失败。
|
||||||
|
$null = $_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -546,7 +546,7 @@ foreach ($line in $lines) {
|
|||||||
if (-not $item) { continue }
|
if (-not $item) { continue }
|
||||||
|
|
||||||
$displayPath = $item.Path
|
$displayPath = $item.Path
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath -MaxDepth $script:Config.CatalogMaxDepth
|
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath
|
||||||
$baseName = $resolved.BaseName
|
$baseName = $resolved.BaseName
|
||||||
|
|
||||||
if (-not $baseName) { $stats.skipped++; continue }
|
if (-not $baseName) { $stats.skipped++; continue }
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
.\test.ps1 -Suite E2E -PSVersion 5.1
|
.\test.ps1 -Suite E2E -PSVersion 5.1
|
||||||
#>
|
#>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '',
|
||||||
|
Justification = '误判:这些参数的值是在传给 Test-Case / It 的 scriptblock 里用的,静态分析看不到那层使用。')]
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
[ValidateSet('All', 'Parse', 'Unit', 'Smoke', 'E2E', 'Drill')]
|
[ValidateSet('All', 'Parse', 'Unit', 'Smoke', 'E2E', 'Drill')]
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ Describe '软件名录:Slot 形状(新契约)' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '一个软件多个 Slot:Kind=Multi,Slot 按名排序且说明被保留' {
|
It '一个软件多个 Slot:Kind=Multi,Slot 按名排序且说明被保留' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
|
||||||
$catalog['pair'].Kind | Should -Be 'Multi'
|
$catalog['pair'].Kind | Should -Be 'Multi'
|
||||||
@($catalog['pair'].Slots).Count | Should -Be 2
|
@($catalog['pair'].Slots).Count | Should -Be 2
|
||||||
(@($catalog['pair'].Slots | ForEach-Object { $_.Name }) -join ',') | Should -Be 'A,B'
|
(@($catalog['pair'].Slots | ForEach-Object { $_.Name }) -join ',') | Should -Be 'A,B'
|
||||||
@@ -150,7 +150,7 @@ Describe '软件名录:Slot 形状(新契约)' {
|
|||||||
|
|
||||||
It '每个 Slot 都是一个独立的归档项来源(Kind=slot / Origin=catalog)' {
|
It '每个 Slot 都是一个独立的归档项来源(Kind=slot / Origin=catalog)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'pair'
|
$entry = ConvertFrom-BackupListLine -Line 'pair'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
@($resolved.Items).Count | Should -Be 2
|
@($resolved.Items).Count | Should -Be 2
|
||||||
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'A,B'
|
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'A,B'
|
||||||
(@($resolved.Items | ForEach-Object { $_.Kind }) -join ',') | Should -Be 'slot,slot'
|
(@($resolved.Items | ForEach-Object { $_.Kind }) -join ',') | Should -Be 'slot,slot'
|
||||||
@@ -161,22 +161,22 @@ Describe '软件名录:Slot 形状(新契约)' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It 'Slot 级排除写在 Slot 自己身上(相对本 Slot 的归档根)' {
|
It 'Slot 级排除写在 Slot 自己身上(相对本 Slot 的归档根)' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
|
||||||
(@($catalog['slotex'].Slots[0].Exclude) -join '|') | Should -Be '!*Cache|logs\'
|
(@($catalog['slotex'].Slots[0].Exclude) -join '|') | Should -Be '!*Cache|logs\'
|
||||||
|
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'slotex'
|
$entry = ConvertFrom-BackupListLine -Line 'slotex'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
(@($resolved.Items[0].Exclude) -join '|') | Should -Be '!*Cache|logs\'
|
(@($resolved.Items[0].Exclude) -join '|') | Should -Be '!*Cache|logs\'
|
||||||
$resolved.HasExcludeOverride | Should -BeFalse
|
$resolved.HasExcludeOverride | Should -BeFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
It '数组里"当前不存在"的 Slot 仍然产出归档项(恢复要靠它还原回原位)' {
|
It '数组里"当前不存在"的 Slot 仍然产出归档项(恢复要靠它还原回原位)' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
|
||||||
$catalog['partial'].Kind | Should -Be 'Partial'
|
$catalog['partial'].Kind | Should -Be 'Partial'
|
||||||
@($catalog['partial'].Missing) | Should -Contain $script:MissingDir
|
@($catalog['partial'].Missing) | Should -Contain $script:MissingDir
|
||||||
|
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'partial'
|
$entry = ConvertFrom-BackupListLine -Line 'partial'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
@($resolved.Items).Count | Should -Be 2
|
@($resolved.Items).Count | Should -Be 2
|
||||||
@($resolved.Items | ForEach-Object { $_.RealPath }) | Should -Contain $script:MissingDir
|
@($resolved.Items | ForEach-Object { $_.RealPath }) | Should -Contain $script:MissingDir
|
||||||
$resolved.Blocking | Should -BeNullOrEmpty # 源不存在不是致命错误
|
$resolved.Blocking | Should -BeNullOrEmpty # 源不存在不是致命错误
|
||||||
@@ -184,7 +184,7 @@ Describe '软件名录:Slot 形状(新契约)' {
|
|||||||
|
|
||||||
It '文件 Slot:归档项是文件项(归档里就是名为 Slot 的文件)' {
|
It '文件 Slot:归档项是文件项(归档里就是名为 Slot 的文件)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'fileapp'
|
$entry = ConvertFrom-BackupListLine -Line 'fileapp'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
@($resolved.Items).Count | Should -Be 1
|
@($resolved.Items).Count | Should -Be 1
|
||||||
$resolved.Items[0].IsFile | Should -BeTrue
|
$resolved.Items[0].IsFile | Should -BeTrue
|
||||||
$resolved.Items[0].ArchivePath | Should -Be 'Cfg'
|
$resolved.Items[0].ArchivePath | Should -Be 'Cfg'
|
||||||
@@ -193,13 +193,13 @@ Describe '软件名录:Slot 形状(新契约)' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '旧的裸字符串 / 字符串数组写法被拒绝(ERROR + 跳过)' {
|
It '旧的裸字符串 / 字符串数组写法被拒绝(ERROR + 跳过)' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
|
||||||
$catalog.ContainsKey('legacystr') | Should -BeFalse
|
$catalog.ContainsKey('legacystr') | Should -BeFalse
|
||||||
$catalog.ContainsKey('legacyarr') | Should -BeFalse
|
$catalog.ContainsKey('legacyarr') | Should -BeFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
It '旧的 @{ Dirs = @(...) } 写法不再展开,留下 Invalid 与原因' {
|
It '旧的 @{ Dirs = @(...) } 写法不再展开,留下 Invalid 与原因' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:FormatCatalog -NoCache
|
||||||
$catalog.ContainsKey('legacydirs') | Should -BeTrue
|
$catalog.ContainsKey('legacydirs') | Should -BeTrue
|
||||||
$catalog['legacydirs'].Kind | Should -Be 'Invalid'
|
$catalog['legacydirs'].Kind | Should -Be 'Invalid'
|
||||||
$catalog['legacydirs'].Error | Should -Not -BeNullOrEmpty
|
$catalog['legacydirs'].Error | Should -Not -BeNullOrEmpty
|
||||||
@@ -208,7 +208,7 @@ Describe '软件名录:Slot 形状(新契约)' {
|
|||||||
|
|
||||||
It '多 Slot 的名录条目在清单里仍然按软件名命名归档' {
|
It '多 Slot 的名录条目在清单里仍然按软件名命名归档' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'pair'
|
$entry = ConvertFrom-BackupListLine -Line 'pair'
|
||||||
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3) | Should -Be 'pair'
|
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog) | Should -Be 'pair'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ Describe '清单修饰符:新契约格式' {
|
|||||||
It ':: 覆盖 Path:单 Slot 条目直接生效' {
|
It ':: 覆盖 Path:单 Slot 条目直接生效' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line "solo :: $script:DirB"
|
$entry = ConvertFrom-BackupListLine -Line "solo :: $script:DirB"
|
||||||
$entry.Overrides.ContainsKey('Path') | Should -BeTrue
|
$entry.Overrides.ContainsKey('Path') | Should -BeTrue
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
@($resolved.Items).Count | Should -Be 1
|
@($resolved.Items).Count | Should -Be 1
|
||||||
$resolved.Items[0].ArchivePath | Should -Be 'Only'
|
$resolved.Items[0].ArchivePath | Should -Be 'Only'
|
||||||
$resolved.Items[0].RealPath | Should -Be $script:DirB
|
$resolved.Items[0].RealPath | Should -Be $script:DirB
|
||||||
@@ -236,7 +236,7 @@ Describe '清单修饰符:新契约格式' {
|
|||||||
|
|
||||||
It ':: 覆盖遇到多 Slot 条目 -> Blocking(不知道给哪一个,绝不猜)' {
|
It ':: 覆盖遇到多 Slot 条目 -> Blocking(不知道给哪一个,绝不猜)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line "pair :: $script:DirB"
|
$entry = ConvertFrom-BackupListLine -Line "pair :: $script:DirB"
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
@($resolved.Items).Count | Should -Be 0
|
@($resolved.Items).Count | Should -Be 0
|
||||||
$resolved.Blocking | Should -Match '不能用一个'
|
$resolved.Blocking | Should -Match '不能用一个'
|
||||||
}
|
}
|
||||||
@@ -246,7 +246,7 @@ Describe '清单修饰符:新契约格式' {
|
|||||||
(@($entry.ExcludePatterns) -join '|') | Should -Be 'logs\|!*Cache'
|
(@($entry.ExcludePatterns) -join '|') | Should -Be 'logs\|!*Cache'
|
||||||
(@($entry.Includes) -join '|') | Should -Be "Mods:$script:DirB"
|
(@($entry.Includes) -join '|') | Should -Be "Mods:$script:DirB"
|
||||||
|
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:FormatCatalog
|
||||||
$resolved.HasExcludeOverride | Should -BeTrue
|
$resolved.HasExcludeOverride | Should -BeTrue
|
||||||
$resolved.HasIncludeOverride | Should -BeTrue
|
$resolved.HasIncludeOverride | Should -BeTrue
|
||||||
@($resolved.Items | ForEach-Object { $_.ArchivePath }) | Should -Contain 'Mods'
|
@($resolved.Items | ForEach-Object { $_.ArchivePath }) | Should -Contain 'Mods'
|
||||||
@@ -261,13 +261,13 @@ Describe '清单修饰符:新契约格式' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It ':encrypt / :!encrypt 覆盖名录里的加密默认值' {
|
It ':encrypt / :!encrypt 覆盖名录里的加密默认值' {
|
||||||
$base = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp') -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$base = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp') -CatalogPath $script:FormatCatalog
|
||||||
$base.Encrypt | Should -BeTrue # 名录里 Cfg Slot 标了 Encrypt
|
$base.Encrypt | Should -BeTrue # 名录里 Cfg Slot 标了 Encrypt
|
||||||
|
|
||||||
$off = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp :!encrypt') -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$off = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'fileapp :!encrypt') -CatalogPath $script:FormatCatalog
|
||||||
$off.Encrypt | Should -BeFalse
|
$off.Encrypt | Should -BeFalse
|
||||||
|
|
||||||
$on = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'pair :encrypt') -CatalogPath $script:FormatCatalog -MaxDepth 3
|
$on = Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'pair :encrypt') -CatalogPath $script:FormatCatalog
|
||||||
$on.Encrypt | Should -BeTrue
|
$on.Encrypt | Should -BeTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ Describe '清单修饰符:新契约格式' {
|
|||||||
# @pathname 对软件名条目也会改用真实路径命名
|
# @pathname 对软件名条目也会改用真实路径命名
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'pair @pathname'
|
$entry = ConvertFrom-BackupListLine -Line 'pair @pathname'
|
||||||
$expected = Get-BakNRetBackupBaseName -RawPath $script:DirA
|
$expected = Get-BakNRetBackupBaseName -RawPath $script:DirA
|
||||||
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog -MaxDepth 3) | Should -Be $expected
|
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:FormatCatalog) | Should -Be $expected
|
||||||
}
|
}
|
||||||
|
|
||||||
It '同一行里重复写同类记号会累积(不静默丢掉前一条规则)' {
|
It '同一行里重复写同类记号会累积(不静默丢掉前一条规则)' {
|
||||||
|
|||||||
+43
-43
@@ -407,24 +407,24 @@ Describe '归档命名' {
|
|||||||
|
|
||||||
It '软件名条目:默认用软件名做归档名' {
|
It '软件名条目:默认用软件名做归档名' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'my-app'
|
$entry = ConvertFrom-BackupListLine -Line 'my-app'
|
||||||
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be 'my-app'
|
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be 'my-app'
|
||||||
}
|
}
|
||||||
|
|
||||||
It '字面路径条目:仍用路径命名算法(现有清单无需改写)' {
|
It '字面路径条目:仍用路径命名算法(现有清单无需改写)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'C:\Programs\FooClolor'
|
$entry = ConvertFrom-BackupListLine -Line 'C:\Programs\FooClolor'
|
||||||
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be 'FooClolor_from_C_+Programs'
|
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be 'FooClolor_from_C_+Programs'
|
||||||
}
|
}
|
||||||
|
|
||||||
It '@pathname 用名录里的真实路径命名,而不是软件名' {
|
It '@pathname 用名录里的真实路径命名,而不是软件名' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'my-app @pathname'
|
$entry = ConvertFrom-BackupListLine -Line 'my-app @pathname'
|
||||||
$expected = Get-BakNRetBackupBaseName -RawPath $script:NamingApp
|
$expected = Get-BakNRetBackupBaseName -RawPath $script:NamingApp
|
||||||
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be $expected
|
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be $expected
|
||||||
}
|
}
|
||||||
|
|
||||||
It '名录里没有该名字:归档名退回可读目录名,并给出 Error' {
|
It '名录里没有该名字:归档名退回可读目录名,并给出 Error' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'no-such-thing'
|
$entry = ConvertFrom-BackupListLine -Line 'no-such-thing'
|
||||||
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3) | Should -Be 'no-such-thing'
|
(Get-BakNRetItemArchiveName -Entry $entry -CatalogPath $script:NamingCatalog) | Should -Be 'no-such-thing'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:NamingCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:NamingCatalog
|
||||||
$resolved.Error | Should -Not -BeNullOrEmpty
|
$resolved.Error | Should -Not -BeNullOrEmpty
|
||||||
@($resolved.Items).Count | Should -Be 0
|
@($resolved.Items).Count | Should -Be 0
|
||||||
}
|
}
|
||||||
@@ -827,7 +827,7 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '名录解析:条目与 Slot 的字段集合就是新契约' {
|
It '名录解析:条目与 Slot 的字段集合就是新契约' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$entry = $catalog['single']
|
$entry = $catalog['single']
|
||||||
(@($entry.PSObject.Properties.Name) -join ',') | Should -Be 'Name,Path,Description,Slots,Kind,Missing,Error,Raw'
|
(@($entry.PSObject.Properties.Name) -join ',') | Should -Be 'Name,Path,Description,Slots,Kind,Missing,Error,Raw'
|
||||||
$entry.Name | Should -Be 'single'
|
$entry.Name | Should -Be 'single'
|
||||||
@@ -849,7 +849,7 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '一个软件多个 Slot:Kind=Multi,Slot 按名字排序' {
|
It '一个软件多个 Slot:Kind=Multi,Slot 按名字排序' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$catalog['multi'].Kind | Should -Be 'Multi'
|
$catalog['multi'].Kind | Should -Be 'Multi'
|
||||||
@($catalog['multi'].Slots).Count | Should -Be 2
|
@($catalog['multi'].Slots).Count | Should -Be 2
|
||||||
(@($catalog['multi'].Slots | ForEach-Object { $_.Name }) -join ',') | Should -Be 'Alpha,Zeta'
|
(@($catalog['multi'].Slots | ForEach-Object { $_.Name }) -join ',') | Should -Be 'Alpha,Zeta'
|
||||||
@@ -858,7 +858,7 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It 'Kind:Single / Multi / Partial / Unresolved / Invalid' {
|
It 'Kind:Single / Multi / Partial / Unresolved / Invalid' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$catalog['single'].Kind | Should -Be 'Single'
|
$catalog['single'].Kind | Should -Be 'Single'
|
||||||
$catalog['multi'].Kind | Should -Be 'Multi'
|
$catalog['multi'].Kind | Should -Be 'Multi'
|
||||||
$catalog['partial'].Kind | Should -Be 'Partial'
|
$catalog['partial'].Kind | Should -Be 'Partial'
|
||||||
@@ -873,7 +873,7 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '前缀补全:<名>_<后缀> 与 <名>-<后缀> 都会被补全' {
|
It '前缀补全:<名>_<后缀> 与 <名>-<后缀> 都会被补全' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$catalog['legendary'].Slots[0].Resolved | Should -Be (Join-Path $script:CatRoot 'legendary_2.0.4')
|
$catalog['legendary'].Slots[0].Resolved | Should -Be (Join-Path $script:CatRoot 'legendary_2.0.4')
|
||||||
$catalog['legendary'].Slots[0].Suffixed | Should -BeTrue
|
$catalog['legendary'].Slots[0].Suffixed | Should -BeTrue
|
||||||
|
|
||||||
@@ -882,12 +882,12 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '不会把 Legendary 误配成 LegendarySomething' {
|
It '不会把 Legendary 误配成 LegendarySomething' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$catalog['legendary'].Slots[0].Resolved | Should -Not -Be (Join-Path $script:CatRoot 'LegendarySomething')
|
$catalog['legendary'].Slots[0].Resolved | Should -Not -Be (Join-Path $script:CatRoot 'LegendarySomething')
|
||||||
}
|
}
|
||||||
|
|
||||||
It '一个 Slot 命中多个候选目录:报 Error,绝不悄悄挑一棵树' {
|
It '一个 Slot 命中多个候选目录:报 Error,绝不悄悄挑一棵树' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$entry = $catalog['dupslot']
|
$entry = $catalog['dupslot']
|
||||||
$entry.Error | Should -Match '只能对应一个目录'
|
$entry.Error | Should -Match '只能对应一个目录'
|
||||||
$entry.Error | Should -Match 'dup_1'
|
$entry.Error | Should -Match 'dup_1'
|
||||||
@@ -897,14 +897,14 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '文件 Slot:Path 指向文件时 IsFile 为真,Encrypt 也带上' {
|
It '文件 Slot:Path 指向文件时 IsFile 为真,Encrypt 也带上' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$slot = $catalog['fileslot'].Slots[0]
|
$slot = $catalog['fileslot'].Slots[0]
|
||||||
$slot.IsFile | Should -BeTrue
|
$slot.IsFile | Should -BeTrue
|
||||||
$slot.Encrypt | Should -BeTrue
|
$slot.Encrypt | Should -BeTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
It '%变量% 会在名录路径里展开' {
|
It '%变量% 会在名录路径里展开' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
$catalog['envpath'].Slots[0].Resolved | Should -Be ([Environment]::ExpandEnvironmentVariables('%TEMP%'))
|
$catalog['envpath'].Slots[0].Resolved | Should -Be ([Environment]::ExpandEnvironmentVariables('%TEMP%'))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,39 +916,39 @@ Describe '软件名录' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '读取结果按"路径 + 时间戳 + 长度 + 内容 MD5"缓存' {
|
It '读取结果按"路径 + 时间戳 + 长度 + 内容 MD5"缓存' {
|
||||||
$first = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3
|
$first = Get-BakNRetSoftwareCatalog -Path $script:CatFile
|
||||||
$second = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3
|
$second = Get-BakNRetSoftwareCatalog -Path $script:CatFile
|
||||||
[object]::ReferenceEquals($first, $second) | Should -BeTrue
|
[object]::ReferenceEquals($first, $second) | Should -BeTrue
|
||||||
|
|
||||||
$fresh = Get-BakNRetSoftwareCatalog -Path $script:CatFile -MaxDepth 3 -NoCache
|
$fresh = Get-BakNRetSoftwareCatalog -Path $script:CatFile -NoCache
|
||||||
[object]::ReferenceEquals($first, $fresh) | Should -BeFalse
|
[object]::ReferenceEquals($first, $fresh) | Should -BeFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
It '名录文件内容变了以后缓存自动失效' {
|
It '名录文件内容变了以后缓存自动失效' {
|
||||||
$path = Write-ListFile -Path (Join-Path $script:CatRoot 'cache.psd1') -Content "@{ 'x' = @{ S = @{ Path = '$script:CatReal'; Description = 'one' } } }"
|
$path = Write-ListFile -Path (Join-Path $script:CatRoot 'cache.psd1') -Content "@{ 'x' = @{ S = @{ Path = '$script:CatReal'; Description = 'one' } } }"
|
||||||
(Get-BakNRetSoftwareCatalog -Path $path -MaxDepth 3)['x'].Description | Should -Be 'one'
|
(Get-BakNRetSoftwareCatalog -Path $path)['x'].Description | Should -Be 'one'
|
||||||
|
|
||||||
Write-ListFile -Path $path -Content "@{ 'x' = @{ S = @{ Path = '$script:CatReal'; Description = 'two' } } }" | Out-Null
|
Write-ListFile -Path $path -Content "@{ 'x' = @{ S = @{ Path = '$script:CatReal'; Description = 'two' } } }" | Out-Null
|
||||||
(Get-BakNRetSoftwareCatalog -Path $path -MaxDepth 3)['x'].Description | Should -Be 'two'
|
(Get-BakNRetSoftwareCatalog -Path $path)['x'].Description | Should -Be 'two'
|
||||||
}
|
}
|
||||||
|
|
||||||
It 'Includes:分文件维护的名录会被合并' {
|
It 'Includes:分文件维护的名录会被合并' {
|
||||||
Write-ListFile -Path (Join-Path $script:CatRoot 'Extra.psd1') -Content "@{ 'extra-app' = @{ S = @{ Path = '$script:CatReal' } } }" | Out-Null
|
Write-ListFile -Path (Join-Path $script:CatRoot 'Extra.psd1') -Content "@{ 'extra-app' = @{ S = @{ Path = '$script:CatReal' } } }" | Out-Null
|
||||||
$main = Write-ListFile -Path (Join-Path $script:CatRoot 'Main.psd1') -Content "@{ Includes = @('Extra.psd1'); 'main-app' = @{ S = @{ Path = '$script:CatReal' } } }"
|
$main = Write-ListFile -Path (Join-Path $script:CatRoot 'Main.psd1') -Content "@{ Includes = @('Extra.psd1'); 'main-app' = @{ S = @{ Path = '$script:CatReal' } } }"
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $main -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $main -NoCache
|
||||||
$catalog.ContainsKey('main-app') | Should -BeTrue
|
$catalog.ContainsKey('main-app') | Should -BeTrue
|
||||||
$catalog.ContainsKey('extra-app') | Should -BeTrue
|
$catalog.ContainsKey('extra-app') | Should -BeTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
It '旧的裸字符串 / 字符串数组 / 对象数组写法都会报 ERROR 并被跳过' {
|
It '旧的裸字符串 / 字符串数组 / 对象数组写法都会报 ERROR 并被跳过' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -NoCache
|
||||||
$catalog.ContainsKey('bare') | Should -BeFalse
|
$catalog.ContainsKey('bare') | Should -BeFalse
|
||||||
$catalog.ContainsKey('arr') | Should -BeFalse
|
$catalog.ContainsKey('arr') | Should -BeFalse
|
||||||
$catalog.ContainsKey('objarr') | Should -BeFalse
|
$catalog.ContainsKey('objarr') | Should -BeFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
It '旧的 @{ Dirs = @(...) } 写法不再展开:留下 Invalid 条目和原因' {
|
It '旧的 @{ Dirs = @(...) } 写法不再展开:留下 Invalid 条目和原因' {
|
||||||
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -MaxDepth 3 -NoCache
|
$catalog = Get-BakNRetSoftwareCatalog -Path $script:LegacyFile -NoCache
|
||||||
$catalog.ContainsKey('dirstyle') | Should -BeTrue
|
$catalog.ContainsKey('dirstyle') | Should -BeTrue
|
||||||
$catalog['dirstyle'].Kind | Should -Be 'Invalid'
|
$catalog['dirstyle'].Kind | Should -Be 'Invalid'
|
||||||
$catalog['dirstyle'].Error | Should -Not -BeNullOrEmpty
|
$catalog['dirstyle'].Error | Should -Not -BeNullOrEmpty
|
||||||
@@ -976,7 +976,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It 'resolve 与归档项的字段集合就是新契约(旧字段已删除)' {
|
It 'resolve 与归档项的字段集合就是新契约(旧字段已删除)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'single'
|
$entry = ConvertFrom-BackupListLine -Line 'single'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
(@($resolved.PSObject.Properties.Name) -join ',') | Should -Be 'IsName,CatalogEntry,BaseName,ArchiveFlavor,Direction,Items,Encrypt,ExcludePatterns,HasExcludeOverride,Includes,HasIncludeOverride,Source,Error,Blocking'
|
(@($resolved.PSObject.Properties.Name) -join ',') | Should -Be 'IsName,CatalogEntry,BaseName,ArchiveFlavor,Direction,Items,Encrypt,ExcludePatterns,HasExcludeOverride,Includes,HasIncludeOverride,Source,Error,Blocking'
|
||||||
@($resolved.Items)[0].PSObject.Properties.Name | Should -Contain 'ArchivePath'
|
@($resolved.Items)[0].PSObject.Properties.Name | Should -Contain 'ArchivePath'
|
||||||
@($resolved.Items)[0].PSObject.Properties.Name | Should -Contain 'Origin'
|
@($resolved.Items)[0].PSObject.Properties.Name | Should -Contain 'Origin'
|
||||||
@@ -985,7 +985,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It '软件名条目:isName/CatalogEntry/BaseName/ArchiveFlavor/Source' {
|
It '软件名条目:isName/CatalogEntry/BaseName/ArchiveFlavor/Source' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'single'
|
$entry = ConvertFrom-BackupListLine -Line 'single'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.IsName | Should -BeTrue
|
$resolved.IsName | Should -BeTrue
|
||||||
$resolved.BaseName | Should -Be 'single'
|
$resolved.BaseName | Should -Be 'single'
|
||||||
$resolved.ArchiveFlavor | Should -Be 'name'
|
$resolved.ArchiveFlavor | Should -Be 'name'
|
||||||
@@ -997,7 +997,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It '软件名条目:Items 来自 Slot(ArchivePath=Slot 名,Kind=slot,Origin=catalog)' {
|
It '软件名条目:Items 来自 Slot(ArchivePath=Slot 名,Kind=slot,Origin=catalog)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'multi'
|
$entry = ConvertFrom-BackupListLine -Line 'multi'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
@($resolved.Items).Count | Should -Be 2
|
@($resolved.Items).Count | Should -Be 2
|
||||||
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'Alpha,Zeta'
|
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'Alpha,Zeta'
|
||||||
(@($resolved.Items | ForEach-Object { $_.Kind }) -join ',') | Should -Be 'slot,slot'
|
(@($resolved.Items | ForEach-Object { $_.Kind }) -join ',') | Should -Be 'slot,slot'
|
||||||
@@ -1009,7 +1009,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It '字面路径条目:一个 path 项(ArchivePath 是末级名)' {
|
It '字面路径条目:一个 path 项(ArchivePath 是末级名)' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'C:\Programs\FooClolor'
|
$entry = ConvertFrom-BackupListLine -Line 'C:\Programs\FooClolor'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.IsName | Should -BeFalse
|
$resolved.IsName | Should -BeFalse
|
||||||
$resolved.ArchiveFlavor | Should -Be 'path'
|
$resolved.ArchiveFlavor | Should -Be 'path'
|
||||||
@($resolved.Items).Count | Should -Be 1
|
@($resolved.Items).Count | Should -Be 1
|
||||||
@@ -1021,7 +1021,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It '字面路径条目上的 @ Path= 覆盖目标路径,但归档名仍按原路径' {
|
It '字面路径条目上的 @ Path= 覆盖目标路径,但归档名仍按原路径' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line "C:\Programs\Foo @ Path='D:\Elsewhere'"
|
$entry = ConvertFrom-BackupListLine -Line "C:\Programs\Foo @ Path='D:\Elsewhere'"
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.Items[0].RealPath | Should -Be 'D:\Elsewhere'
|
$resolved.Items[0].RealPath | Should -Be 'D:\Elsewhere'
|
||||||
$resolved.BaseName | Should -Be 'Foo_from_C_+Programs'
|
$resolved.BaseName | Should -Be 'Foo_from_C_+Programs'
|
||||||
}
|
}
|
||||||
@@ -1029,7 +1029,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
It '名录里的路径不存在时仍给出 Items(恢复要靠它还原回原位)' {
|
It '名录里的路径不存在时仍给出 Items(恢复要靠它还原回原位)' {
|
||||||
$missingCatalog = Write-ListFile -Path (Join-Path $script:Sandbox 'catalog\Missing.psd1') -Content "@{ 'gone' = @{ S = @{ Path = 'C:\definitely-not-here-98765' } } }"
|
$missingCatalog = Write-ListFile -Path (Join-Path $script:Sandbox 'catalog\Missing.psd1') -Content "@{ 'gone' = @{ S = @{ Path = 'C:\definitely-not-here-98765' } } }"
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'gone'
|
$entry = ConvertFrom-BackupListLine -Line 'gone'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $missingCatalog -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $missingCatalog
|
||||||
@($resolved.Items).Count | Should -Be 1
|
@($resolved.Items).Count | Should -Be 1
|
||||||
$resolved.Items[0].Exists | Should -BeFalse
|
$resolved.Items[0].Exists | Should -BeFalse
|
||||||
$resolved.Items[0].RealPath | Should -Be 'C:\definitely-not-here-98765'
|
$resolved.Items[0].RealPath | Should -Be 'C:\definitely-not-here-98765'
|
||||||
@@ -1037,7 +1037,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It ':: 覆盖 Path:单 Slot 条目直接生效' {
|
It ':: 覆盖 Path:单 Slot 条目直接生效' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line "single :: $script:CatOther"
|
$entry = ConvertFrom-BackupListLine -Line "single :: $script:CatOther"
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
@($resolved.Items).Count | Should -Be 1
|
@($resolved.Items).Count | Should -Be 1
|
||||||
$resolved.Items[0].ArchivePath | Should -Be 'Main'
|
$resolved.Items[0].ArchivePath | Should -Be 'Main'
|
||||||
$resolved.Items[0].RealPath | Should -Be $script:CatOther
|
$resolved.Items[0].RealPath | Should -Be $script:CatOther
|
||||||
@@ -1047,7 +1047,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
It ':: / @ Path= 覆盖遇到多 Slot 条目 -> Blocking(不猜是哪一个)' {
|
It ':: / @ Path= 覆盖遇到多 Slot 条目 -> Blocking(不猜是哪一个)' {
|
||||||
foreach ($line in @("multi :: $script:CatOther", "multi @ Path='$script:CatOther'")) {
|
foreach ($line in @("multi :: $script:CatOther", "multi @ Path='$script:CatOther'")) {
|
||||||
$entry = ConvertFrom-BackupListLine -Line $line
|
$entry = ConvertFrom-BackupListLine -Line $line
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
@($resolved.Items).Count | Should -Be 0
|
@($resolved.Items).Count | Should -Be 0
|
||||||
$resolved.Blocking | Should -Match '不能用一个'
|
$resolved.Blocking | Should -Match '不能用一个'
|
||||||
}
|
}
|
||||||
@@ -1055,14 +1055,14 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
|
|
||||||
It '条目级 :- 覆盖名录里的排除:HasExcludeOverride 为真' {
|
It '条目级 :- 覆盖名录里的排除:HasExcludeOverride 为真' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'single :- logs\,!*Cache'
|
$entry = ConvertFrom-BackupListLine -Line 'single :- logs\,!*Cache'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.HasExcludeOverride | Should -BeTrue
|
$resolved.HasExcludeOverride | Should -BeTrue
|
||||||
(@($resolved.ExcludePatterns) -join '|') | Should -Be 'logs\|!*Cache'
|
(@($resolved.ExcludePatterns) -join '|') | Should -Be 'logs\|!*Cache'
|
||||||
}
|
}
|
||||||
|
|
||||||
It '名录 Slot 的 Include 会追加成 include 项' {
|
It '名录 Slot 的 Include 会追加成 include 项' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'incapp'
|
$entry = ConvertFrom-BackupListLine -Line 'incapp'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
@($resolved.Items).Count | Should -Be 2
|
@($resolved.Items).Count | Should -Be 2
|
||||||
$include = @($resolved.Items | Where-Object { $_.Origin -eq 'include' })
|
$include = @($resolved.Items | Where-Object { $_.Origin -eq 'include' })
|
||||||
$include.Count | Should -Be 1
|
$include.Count | Should -Be 1
|
||||||
@@ -1074,7 +1074,7 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
It '条目级 :+ / @ Include= 覆盖名录里的 Include' {
|
It '条目级 :+ / @ Include= 覆盖名录里的 Include' {
|
||||||
foreach ($line in @("incapp :+ Other:$script:CatOther", "incapp @ Include='Other:$script:CatOther'")) {
|
foreach ($line in @("incapp :+ Other:$script:CatOther", "incapp @ Include='Other:$script:CatOther'")) {
|
||||||
$entry = ConvertFrom-BackupListLine -Line $line
|
$entry = ConvertFrom-BackupListLine -Line $line
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.HasIncludeOverride | Should -BeTrue
|
$resolved.HasIncludeOverride | Should -BeTrue
|
||||||
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'A,Other'
|
(@($resolved.Items | ForEach-Object { $_.ArchivePath }) -join ',') | Should -Be 'A,Other'
|
||||||
@($resolved.Items)[1].RealPath | Should -Be $script:CatOther
|
@($resolved.Items)[1].RealPath | Should -Be $script:CatOther
|
||||||
@@ -1082,34 +1082,34 @@ Describe 'Resolve-BakNRetBackupEntry:条目解析' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
It '加密:名录里各 Slot 取或;条目级 :encrypt / :!encrypt 覆盖' {
|
It '加密:名录里各 Slot 取或;条目级 :encrypt / :!encrypt 覆盖' {
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeFalse
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile).Encrypt | Should -BeFalse
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeTrue
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp') -CatalogPath $script:CatFile).Encrypt | Should -BeTrue
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp :!encrypt') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeFalse
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'encapp :!encrypt') -CatalogPath $script:CatFile).Encrypt | Should -BeFalse
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single :encrypt') -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeTrue
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single :encrypt') -CatalogPath $script:CatFile).Encrypt | Should -BeTrue
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line "single @ Encrypt='true'") -CatalogPath $script:CatFile -MaxDepth 3).Encrypt | Should -BeTrue
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line "single @ Encrypt='true'") -CatalogPath $script:CatFile).Encrypt | Should -BeTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
It '方向标记会传递到 Resolve-BakNRetBackupEntry.Direction' {
|
It '方向标记会传递到 Resolve-BakNRetBackupEntry.Direction' {
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '+ single') -CatalogPath $script:CatFile -MaxDepth 3).Direction | Should -Be 'backup'
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '+ single') -CatalogPath $script:CatFile).Direction | Should -Be 'backup'
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '- single') -CatalogPath $script:CatFile -MaxDepth 3).Direction | Should -Be 'restore'
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line '- single') -CatalogPath $script:CatFile).Direction | Should -Be 'restore'
|
||||||
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile -MaxDepth 3).Direction | Should -Be 'both'
|
(Resolve-BakNRetBackupEntry -Entry (ConvertFrom-BackupListLine -Line 'single') -CatalogPath $script:CatFile).Direction | Should -Be 'both'
|
||||||
}
|
}
|
||||||
|
|
||||||
It '归档内路径冲突(include 与 Slot 同名)-> Blocking' {
|
It '归档内路径冲突(include 与 Slot 同名)-> Blocking' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line "conflict :+ Data:$script:CatOther"
|
$entry = ConvertFrom-BackupListLine -Line "conflict :+ Data:$script:CatOther"
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.Blocking | Should -Match '归档内路径冲突'
|
$resolved.Blocking | Should -Match '归档内路径冲突'
|
||||||
}
|
}
|
||||||
|
|
||||||
It '归档内路径冲突(父子关系)-> Blocking' {
|
It '归档内路径冲突(父子关系)-> Blocking' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line "conflict :+ Data\sub:$script:CatOther"
|
$entry = ConvertFrom-BackupListLine -Line "conflict :+ Data\sub:$script:CatOther"
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.Blocking | Should -Match '父子关系'
|
$resolved.Blocking | Should -Match '父子关系'
|
||||||
}
|
}
|
||||||
|
|
||||||
It '名录里没有该名字:Error 给出,Items 为空' {
|
It '名录里没有该名字:Error 给出,Items 为空' {
|
||||||
$entry = ConvertFrom-BackupListLine -Line 'no-such-thing'
|
$entry = ConvertFrom-BackupListLine -Line 'no-such-thing'
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile -MaxDepth 3
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $script:CatFile
|
||||||
$resolved.Error | Should -Match 'no-such-thing'
|
$resolved.Error | Should -Match 'no-such-thing'
|
||||||
@($resolved.Items).Count | Should -Be 0
|
@($resolved.Items).Count | Should -Be 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ foreach ($name in $Entries) {
|
|||||||
$entry = ConvertFrom-BackupListLine -Line $name
|
$entry = ConvertFrom-BackupListLine -Line $name
|
||||||
if (-not $entry) { continue }
|
if (-not $entry) { continue }
|
||||||
|
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $catalogPath -MaxDepth $config.CatalogMaxDepth
|
$resolved = Resolve-BakNRetBackupEntry -Entry $entry -CatalogPath $catalogPath
|
||||||
|
|
||||||
if (-not $resolved.BaseName) {
|
if (-not $resolved.BaseName) {
|
||||||
$failures += "$name :解析不出归档名"
|
$failures += "$name :解析不出归档名"
|
||||||
@@ -456,7 +456,6 @@ foreach ($name in $Entries) {
|
|||||||
BackupDir = '$scratchBackupRoot'
|
BackupDir = '$scratchBackupRoot'
|
||||||
LogDir = '$scratchLogDir'
|
LogDir = '$scratchLogDir'
|
||||||
SoftwareCatalog = '$scratchCatalog'
|
SoftwareCatalog = '$scratchCatalog'
|
||||||
CatalogMaxDepth = $($config.CatalogMaxDepth)
|
|
||||||
VerifyArchive = `$true
|
VerifyArchive = `$true
|
||||||
}
|
}
|
||||||
"@, [System.Text.UTF8Encoding]::new($false))
|
"@, [System.Text.UTF8Encoding]::new($false))
|
||||||
|
|||||||
+4
-6
@@ -61,8 +61,7 @@ function New-E2EConfig {
|
|||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$Path,
|
[Parameter(Mandatory = $true)][string]$Path,
|
||||||
[Parameter(Mandatory = $true)][string]$LogDir,
|
[Parameter(Mandatory = $true)][string]$LogDir,
|
||||||
[string]$SoftwareCatalog,
|
[string]$SoftwareCatalog
|
||||||
[int]$CatalogMaxDepth = 5
|
|
||||||
)
|
)
|
||||||
$lines = @(
|
$lines = @(
|
||||||
'@{'
|
'@{'
|
||||||
@@ -72,7 +71,6 @@ function New-E2EConfig {
|
|||||||
' MinFreeSpaceGB = 0'
|
' MinFreeSpaceGB = 0'
|
||||||
)
|
)
|
||||||
if ($SoftwareCatalog) { $lines += " SoftwareCatalog = '$SoftwareCatalog'" }
|
if ($SoftwareCatalog) { $lines += " SoftwareCatalog = '$SoftwareCatalog'" }
|
||||||
$lines += " CatalogMaxDepth = $CatalogMaxDepth"
|
|
||||||
$lines += '}'
|
$lines += '}'
|
||||||
[System.IO.File]::WriteAllText($Path, ($lines -join "`r`n"), [System.Text.UTF8Encoding]::new($true))
|
[System.IO.File]::WriteAllText($Path, ($lines -join "`r`n"), [System.Text.UTF8Encoding]::new($true))
|
||||||
}
|
}
|
||||||
@@ -84,13 +82,13 @@ function Get-NewestLog {
|
|||||||
Sort-Object LastWriteTime | Select-Object -Last 1
|
Sort-Object LastWriteTime | Select-Object -Last 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-ArchiveNames {
|
function Get-ArchiveName {
|
||||||
param([Parameter(Mandatory = $true)][string]$Dir)
|
param([Parameter(Mandatory = $true)][string]$Dir)
|
||||||
return @(Get-ChildItem -LiteralPath $Dir -File -Filter *.7z -ErrorAction SilentlyContinue |
|
return @(Get-ChildItem -LiteralPath $Dir -File -Filter *.7z -ErrorAction SilentlyContinue |
|
||||||
Select-Object -ExpandProperty BaseName)
|
Select-Object -ExpandProperty BaseName)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-OrphanNames {
|
function Get-OrphanName {
|
||||||
<# .SYNOPSIS 从备份日志里解析出"孤儿归档"那一段点名的归档名。 #>
|
<# .SYNOPSIS 从备份日志里解析出"孤儿归档"那一段点名的归档名。 #>
|
||||||
param([Parameter(Mandatory = $true)][string]$LogPath)
|
param([Parameter(Mandatory = $true)][string]$LogPath)
|
||||||
|
|
||||||
@@ -528,7 +526,7 @@ Test-Case '行首 - = 仅备份端跳过(日志点名),不产生归档' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Test-Case '孤儿审计:`-` 条目的归档名算有主,真孤儿才被点名' {
|
Test-Case '孤儿审计:`-` 条目的归档名算有主,真孤儿才被点名' {
|
||||||
$orphans = Get-OrphanNames -LogPath $dirLog.FullName
|
$orphans = Get-OrphanName -LogPath $dirLog.FullName
|
||||||
Assert-True ($orphans -contains 'zzz-orphan.7z') '真孤儿必须被点名'
|
Assert-True ($orphans -contains 'zzz-orphan.7z') '真孤儿必须被点名'
|
||||||
Assert-False ($orphans -contains 'app-b.7z') '`-` 条目的归档不能被误报成孤儿'
|
Assert-False ($orphans -contains 'app-b.7z') '`-` 条目的归档不能被误报成孤儿'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
.\tests\Run-RealSmoke.ps1
|
.\tests\Run-RealSmoke.ps1
|
||||||
#>
|
#>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '',
|
||||||
|
Justification = '误判:这些参数的值是在传给 Test-Case / It 的 scriptblock 里用的,静态分析看不到那层使用。')]
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
[string]$ModulePath,
|
[string]$ModulePath,
|
||||||
@@ -130,7 +132,7 @@ Test-Case '真实清单里每个条目都能解析出方向,且软件名都能
|
|||||||
if ($item.Direction -eq 'backup') { $backupOnly++ }
|
if ($item.Direction -eq 'backup') { $backupOnly++ }
|
||||||
if ($item.Direction -eq 'restore') { $restoreOnly++ }
|
if ($item.Direction -eq 'restore') { $restoreOnly++ }
|
||||||
|
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath -MaxDepth $config.CatalogMaxDepth
|
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath
|
||||||
if ($resolved.Error -and $resolved.Error -like '*名录里没有*') { $catalogMiss += $resolved.Error }
|
if ($resolved.Error -and $resolved.Error -like '*名录里没有*') { $catalogMiss += $resolved.Error }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ function Assert-Null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Assert-FileExists {
|
function Assert-FileExists {
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
|
||||||
|
Justification = '误判:规则把结尾的 s 当复数,而这里的名词是 FileExists(Exists 不是复数)。')]
|
||||||
param([string]$Path, [string]$Because)
|
param([string]$Path, [string]$Because)
|
||||||
if (-not (Test-Path -LiteralPath $Path)) {
|
if (-not (Test-Path -LiteralPath $Path)) {
|
||||||
throw ("文件应当存在但不存在:{0}{1}" -f $Path, $(if ($Because) { "($Because)" } else { '' }))
|
throw ("文件应当存在但不存在:{0}{1}" -f $Path, $(if ($Because) { "($Because)" } else { '' }))
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ foreach ($line in (Get-Content -Encoding UTF8 -LiteralPath $BackupListPath)) {
|
|||||||
$item = ConvertFrom-BackupListLine -Line $line
|
$item = ConvertFrom-BackupListLine -Line $line
|
||||||
if (-not $item) { continue }
|
if (-not $item) { continue }
|
||||||
|
|
||||||
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath -MaxDepth $config.CatalogMaxDepth
|
$resolved = Resolve-BakNRetBackupEntry -Entry $item -CatalogPath $catalogPath
|
||||||
$newName = $resolved.BaseName
|
$newName = $resolved.BaseName
|
||||||
if (-not $newName) { continue }
|
if (-not $newName) { continue }
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ function Save-LabCredential {
|
|||||||
|
|
||||||
function Get-LabCredential {
|
function Get-LabCredential {
|
||||||
<# .SYNOPSIS 读出 VM 凭据为 PSCredential。 #>
|
<# .SYNOPSIS 读出 VM 凭据为 PSCredential。 #>
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '',
|
||||||
|
Justification = '实验机的随机口令本来就得明文生成再注入 unattend.xml(Windows Setup 只接受那种形式)。它只活在本机实验环境,不进生产路径。')]
|
||||||
param()
|
param()
|
||||||
$path = Get-LabCredentialPath
|
$path = Get-LabCredentialPath
|
||||||
if (-not (Test-Path -LiteralPath $path)) { throw "找不到 VM 凭据:$path(先跑 New-BakNRetLab.ps1)" }
|
if (-not (Test-Path -LiteralPath $path)) { throw "找不到 VM 凭据:$path(先跑 New-BakNRetLab.ps1)" }
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#>
|
#>
|
||||||
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '',
|
||||||
|
Justification = '误判:-Recreate 是在遍历 VHDX 的 scriptblock 里用的,静态分析看不到那层使用。')]
|
||||||
param(
|
param(
|
||||||
[ValidateSet('all', 'disk', 'vm', 'provision')][string]$Stage = 'all',
|
[ValidateSet('all', 'disk', 'vm', 'provision')][string]$Stage = 'all',
|
||||||
[switch]$Recreate,
|
[switch]$Recreate,
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
参数只传字符串,数组用 ';' 拼 —— 与 run-drill.ps1 同一套约定。
|
参数只传字符串,数组用 ';' 拼 —— 与 run-drill.ps1 同一套约定。
|
||||||
#>
|
#>
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '',
|
||||||
|
Justification = 'Scoop 官方的安装方式就是 irm | iex 那种一行式;实验脚本照抄官方写法比自己包一层更不容易出错。')]
|
||||||
param(
|
param(
|
||||||
[string]$RepoPath = 'C:\BakNRet',
|
[string]$RepoPath = 'C:\BakNRet',
|
||||||
[string]$WorkRoot = 'C:\BakNRet-Lab\acl',
|
[string]$WorkRoot = 'C:\BakNRet-Lab\acl',
|
||||||
@@ -137,7 +139,7 @@ function Invoke-BakNRetChild {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Stop-VscodeProcesses {
|
function Stop-VscodeProcess {
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
把 vscode 相关进程清掉。
|
把 vscode 相关进程清掉。
|
||||||
@@ -159,7 +161,7 @@ function Stop-VscodeProcesses {
|
|||||||
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
|
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { $null = $_ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Start-Sleep -Milliseconds 700
|
Start-Sleep -Milliseconds 700
|
||||||
@@ -412,7 +414,7 @@ Test-Scenario '每个条目都写了 .acl.json' (@(Get-ChildItem -LiteralPath $B
|
|||||||
# 删源 → 恢复
|
# 删源 → 恢复
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
foreach ($path in $entries) {
|
foreach ($path in $entries) {
|
||||||
if ($path -ieq $vscodeApp) { Stop-VscodeProcesses -AppRoot $vscodeApp }
|
if ($path -ieq $vscodeApp) { Stop-VscodeProcess -AppRoot $vscodeApp }
|
||||||
Remove-TreeHard -Path $path
|
Remove-TreeHard -Path $path
|
||||||
}
|
}
|
||||||
$leftovers = @($entries | Where-Object { Test-Path -LiteralPath $_ })
|
$leftovers = @($entries | Where-Object { Test-Path -LiteralPath $_ })
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
# 不是按本配置文件所在目录;而且路径不存在时会**静默回退**到仓库真实的
|
# 不是按本配置文件所在目录;而且路径不存在时会**静默回退**到仓库真实的
|
||||||
# SoftwareCatalog.psd1。沙盒必须写成仓库根相对路径,否则软件名条目会悄悄用错名录。
|
# SoftwareCatalog.psd1。沙盒必须写成仓库根相对路径,否则软件名条目会悄悄用错名录。
|
||||||
SoftwareCatalog = 'tools\lab\payload\sandbox\SoftwareCatalog.psd1'
|
SoftwareCatalog = 'tools\lab\payload\sandbox\SoftwareCatalog.psd1'
|
||||||
CatalogMaxDepth = 5
|
|
||||||
MinFreeSpaceGB = 0
|
MinFreeSpaceGB = 0
|
||||||
VerifyArchive = $true
|
VerifyArchive = $true
|
||||||
ComputeHash = $true
|
ComputeHash = $true
|
||||||
|
|||||||
Reference in new issue
Block a user