refactor: 入口逻辑下沉第一块(路径解析与条目筛选)

把两个内联函数从入口脚本搬进模块,它们正好覆盖下沉时最容易出错的三类依赖:

  * Resolve-BakNRetRootedPath(原 Backup.ps1 与 Restore.ps1 各一份同名副本)靠 $PSScriptRoot 找仓库根 —— 搬进模块之后 $PSScriptRoot 会变成**模块目录**,语义就悄悄变了。所以根目录改成显式参数,由调用方传 $PSScriptRoot。

  * Test-BakNRetItemSelected(原在 Backup.ps1 里)直接读脚本级的 $Only / $Skip。那种闭包依赖让它没法单独测:要测它就得先构造一个入口脚本。现在两个清单是显式参数。

  * 第三个函数 Get-7zExecutable 我**没有**动:它和模块里已有的 7z 定位功能重复,但两者返回的东西不同(一个路径字符串、一个带 Name/Command/Extension 的对象),合并要先确认语义,不能顺手删。记在下面待办里。

过程里翻车一次并当场修好:给调用点补参数时我是按"行尾追加"做的,结果 3 处把参数甩到了 `)` 或 `}` 外面(例如 `if (...) { continue } -Only $Only`)。**解析是零错的** —— 又一次"绿着但是错的"。修法不是继续追加,而是按内容精确定位那 4 行、把参数插到括号里面;修完先用 5 个即时探针确认两个函数真的能调起来(含 -Only 命中、-Skip 否决、绝对路径不被拼根),再跑全套。

验收:test.ps1 9/9 全绿(7 与 5.1)、102 个文件两版解析零错、构建工具仍能合回单文件。
This commit is contained in:
Shuery committed 2026-09-27 10:25:05 +08:00
1 parent 60ecbc2933
commit bbfece10b6
6 files changed
+66 -37

No files matched your search

+5 -27
View File
@@ -95,18 +95,10 @@ if ($PSBoundParameters.ContainsKey('Verbose')) { Set-BakNRetDebug }
$script:Config = Get-BakNRetConfig -Path $ConfigPath $script:Config = Get-BakNRetConfig -Path $ConfigPath
function Resolve-ConfigPath {
param([string]$Path, [string]$Default)
$value = if ($Path) { $Path } else { $Default }
if (-not [System.IO.Path]::IsPathRooted($value)) {
$value = Join-Path $PSScriptRoot $value
}
return $value
}
if (-not $BackupDir) { $BackupDir = Resolve-ConfigPath -Path $null -Default $script:Config.BackupDir } if (-not $BackupDir) { $BackupDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.BackupDir -Root $PSScriptRoot }
$logDir = Resolve-ConfigPath -Path $null -Default $script:Config.LogDir $logDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.LogDir -Root $PSScriptRoot
$snapshotDir = Resolve-ConfigPath -Path $null -Default $script:Config.SnapshotDir $snapshotDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.SnapshotDir -Root $PSScriptRoot
$catalogPath = Resolve-BakNRetCatalogPath -Configured $script:Config.SoftwareCatalog -Root $PSScriptRoot $catalogPath = Resolve-BakNRetCatalogPath -Configured $script:Config.SoftwareCatalog -Root $PSScriptRoot
$manifestPath = Join-Path $BackupDir 'manifest.json' $manifestPath = Join-Path $BackupDir 'manifest.json'
@@ -189,20 +181,6 @@ if ($freeSpaceGB -ge 0) {
} }
} }
function Test-ItemSelected {
param([string]$DisplayPath, [string]$BaseName)
if ($Only.Count -gt 0) {
$matched = $false
foreach ($pattern in $Only) {
if ($DisplayPath -like $pattern -or $BaseName -like $pattern) { $matched = $true; break }
}
if (-not $matched) { return $false }
}
foreach ($pattern in $Skip) {
if ($DisplayPath -like $pattern -or $BaseName -like $pattern) { return $false }
}
return $true
}
function New-ItemRecord { function New-ItemRecord {
param([string]$BaseName, [string]$Source, [string]$ResolvedSource, [string]$Phase) param([string]$BaseName, [string]$Source, [string]$ResolvedSource, [string]$Phase)
@@ -439,7 +417,7 @@ foreach ($planLine in $lines) {
$planDisplayPath = $planItem.Path $planDisplayPath = $planItem.Path
$planResolved = Resolve-BakNRetBackupEntry -Entry $planItem -CatalogPath $catalogPath $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-BakNRetItemSelected -DisplayPath $planDisplayPath -BaseName $planResolved.BaseName -Only $Only -Skip $Skip)) { continue }
if ($planResolved.Direction -eq 'restore') { continue } if ($planResolved.Direction -eq 'restore') { continue }
if ($planResolved.Blocking) { continue } if ($planResolved.Blocking) { continue }
@@ -554,7 +532,7 @@ foreach ($line in $lines) {
$baseName = $resolved.BaseName $baseName = $resolved.BaseName
$sourcePath = [Environment]::ExpandEnvironmentVariables($displayPath) $sourcePath = [Environment]::ExpandEnvironmentVariables($displayPath)
if (-not (Test-ItemSelected -DisplayPath $displayPath -BaseName $baseName)) { if (-not (Test-BakNRetItemSelected -DisplayPath $displayPath -BaseName $baseName -Only $Only -Skip $Skip)) {
Write-BakNRetLog "跳过(未选中): $displayPath" -Level DEBUG Write-BakNRetLog "跳过(未选中): $displayPath" -Level DEBUG
continue continue
} }
+2
View File
@@ -19,6 +19,8 @@
CompatiblePSEditions = @('Desktop', 'Core') CompatiblePSEditions = @('Desktop', 'Core')
FunctionsToExport = @( FunctionsToExport = @(
'Resolve-BakNRetRootedPath',
'Test-BakNRetItemSelected',
'Enter-BakNRetRunLock', 'Enter-BakNRetRunLock',
'Exit-BakNRetRunLock', 'Exit-BakNRetRunLock',
'Get-BakNRetRunLockPath', 'Get-BakNRetRunLockPath',
+5
View File
@@ -133,7 +133,12 @@
. (Join-Path $PSScriptRoot 'Public\Get-BakNRetConfig.ps1') . (Join-Path $PSScriptRoot 'Public\Get-BakNRetConfig.ps1')
. (Join-Path $PSScriptRoot 'Public\Get-BakNRetPassword.ps1') . (Join-Path $PSScriptRoot 'Public\Get-BakNRetPassword.ps1')
. (Join-Path $PSScriptRoot 'Public\Resolve-BakNRetRootedPath.ps1')
. (Join-Path $PSScriptRoot 'Public\Test-BakNRetItemSelected.ps1')
Export-ModuleMember -Function @( Export-ModuleMember -Function @(
'Resolve-BakNRetRootedPath',
'Test-BakNRetItemSelected',
'Enter-BakNRetRunLock', 'Enter-BakNRetRunLock',
'Exit-BakNRetRunLock', 'Exit-BakNRetRunLock',
'Get-BakNRetRunLockPath', 'Get-BakNRetRunLockPath',
@@ -0,0 +1,23 @@
function Resolve-BakNRetRootedPath {
<#
.SYNOPSIS
把可能是相对路径的配置值解析成绝对路径(相对的部分按 $Root 拼)。
.DESCRIPTION
为什么 $Root 是参数、而不是函数里直接用 $PSScriptRoot:它原先在两个入口脚本里各有一份
同名副本(Backup.ps1 与 Restore.ps1 各 8 行),靠 $PSScriptRoot 找到仓库根。搬进模块之后
$PSScriptRoot 会变成**模块目录**,语义就悄悄变了 —— 所以根目录必须由调用方显式传进来。
这是"入口逻辑下沉"里最容易出错的一类:闭包捕获的变量在模块作用域里指向别的东西。
#>
param(
[string]$Path,
[string]$Default,
[Parameter(Mandatory = $true)][string]$Root
)
$value = if ($Path) { $Path } else { $Default }
if (-not [System.IO.Path]::IsPathRooted($value)) {
$value = Join-Path $Root $value
}
return $value
}
@@ -0,0 +1,29 @@
function Test-BakNRetItemSelected {
<#
.SYNOPSIS
条目是否被 -Only / -Skip 选中(-Only 要先命中,-Skip 一票否决)。
.DESCRIPTION
它原先躺在 Backup.ps1 里直接读脚本级的 $Only / $Skip —— 那种"闭包依赖"让它没法单独测:
要测就得先构造一个入口脚本。搬进模块时把两个清单做成显式参数,于是它既能被单元测试直接
调用,也让"到底拿什么在筛选"在调用点就看得见。
#>
param(
[string]$DisplayPath,
[string]$BaseName,
[string[]]$Only = @(),
[string[]]$Skip = @()
)
if ($Only.Count -gt 0) {
$matched = $false
foreach ($pattern in $Only) {
if ($DisplayPath -like $pattern -or $BaseName -like $pattern) { $matched = $true; break }
}
if (-not $matched) { return $false }
}
foreach ($pattern in $Skip) {
if ($DisplayPath -like $pattern -or $BaseName -like $pattern) { return $false }
}
return $true
}
+2 -10
View File
@@ -86,17 +86,9 @@ if ($PSBoundParameters.ContainsKey('Verbose')) { Set-BakNRetDebug }
$script:Config = Get-BakNRetConfig -Path $ConfigPath $script:Config = Get-BakNRetConfig -Path $ConfigPath
$SupportedFormats = @('.7z', '.rar', '.zip', '.tar') $SupportedFormats = @('.7z', '.rar', '.zip', '.tar')
function Resolve-ConfigPath {
param([string]$Path, [string]$Default)
$value = if ($Path) { $Path } else { $Default }
if (-not [System.IO.Path]::IsPathRooted($value)) {
$value = Join-Path $PSScriptRoot $value
}
return $value
}
if (-not $BackupDir) { $BackupDir = Resolve-ConfigPath -Path $null -Default $script:Config.BackupDir } if (-not $BackupDir) { $BackupDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.BackupDir -Root $PSScriptRoot }
$logDir = Resolve-ConfigPath -Path $null -Default $script:Config.LogDir $logDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.LogDir -Root $PSScriptRoot
$catalogPath = Resolve-BakNRetCatalogPath -Configured $script:Config.SoftwareCatalog -Root $PSScriptRoot $catalogPath = Resolve-BakNRetCatalogPath -Configured $script:Config.SoftwareCatalog -Root $PSScriptRoot
$manifestPath = Join-Path $BackupDir 'manifest.json' $manifestPath = Join-Path $BackupDir 'manifest.json'