diff --git a/Backup.ps1 b/Backup.ps1 index 9f90877..46b09b6 100644 --- a/Backup.ps1 +++ b/Backup.ps1 @@ -95,18 +95,10 @@ if ($PSBoundParameters.ContainsKey('Verbose')) { Set-BakNRetDebug } $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 } -$logDir = Resolve-ConfigPath -Path $null -Default $script:Config.LogDir -$snapshotDir = Resolve-ConfigPath -Path $null -Default $script:Config.SnapshotDir +if (-not $BackupDir) { $BackupDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.BackupDir -Root $PSScriptRoot } +$logDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.LogDir -Root $PSScriptRoot +$snapshotDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.SnapshotDir -Root $PSScriptRoot $catalogPath = Resolve-BakNRetCatalogPath -Configured $script:Config.SoftwareCatalog -Root $PSScriptRoot $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 { param([string]$BaseName, [string]$Source, [string]$ResolvedSource, [string]$Phase) @@ -439,7 +417,7 @@ foreach ($planLine in $lines) { $planDisplayPath = $planItem.Path $planResolved = Resolve-BakNRetBackupEntry -Entry $planItem -CatalogPath $catalogPath 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.Blocking) { continue } @@ -554,7 +532,7 @@ foreach ($line in $lines) { $baseName = $resolved.BaseName $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 continue } diff --git a/BakNRet/BakNRet.psd1 b/BakNRet/BakNRet.psd1 index dfa935e..c846c11 100644 --- a/BakNRet/BakNRet.psd1 +++ b/BakNRet/BakNRet.psd1 @@ -19,6 +19,8 @@ CompatiblePSEditions = @('Desktop', 'Core') FunctionsToExport = @( + 'Resolve-BakNRetRootedPath', + 'Test-BakNRetItemSelected', 'Enter-BakNRetRunLock', 'Exit-BakNRetRunLock', 'Get-BakNRetRunLockPath', diff --git a/BakNRet/BakNRet.psm1 b/BakNRet/BakNRet.psm1 index d23be5f..93193f0 100644 --- a/BakNRet/BakNRet.psm1 +++ b/BakNRet/BakNRet.psm1 @@ -133,7 +133,12 @@ . (Join-Path $PSScriptRoot 'Public\Get-BakNRetConfig.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 @( + 'Resolve-BakNRetRootedPath', + 'Test-BakNRetItemSelected', 'Enter-BakNRetRunLock', 'Exit-BakNRetRunLock', 'Get-BakNRetRunLockPath', diff --git a/BakNRet/Public/Resolve-BakNRetRootedPath.ps1 b/BakNRet/Public/Resolve-BakNRetRootedPath.ps1 new file mode 100644 index 0000000..be3378a --- /dev/null +++ b/BakNRet/Public/Resolve-BakNRetRootedPath.ps1 @@ -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 +} diff --git a/BakNRet/Public/Test-BakNRetItemSelected.ps1 b/BakNRet/Public/Test-BakNRetItemSelected.ps1 new file mode 100644 index 0000000..9b9deef --- /dev/null +++ b/BakNRet/Public/Test-BakNRetItemSelected.ps1 @@ -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 +} diff --git a/Restore.ps1 b/Restore.ps1 index 879eed6..660cd90 100644 --- a/Restore.ps1 +++ b/Restore.ps1 @@ -86,17 +86,9 @@ if ($PSBoundParameters.ContainsKey('Verbose')) { Set-BakNRetDebug } $script:Config = Get-BakNRetConfig -Path $ConfigPath $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 } -$logDir = Resolve-ConfigPath -Path $null -Default $script:Config.LogDir +if (-not $BackupDir) { $BackupDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.BackupDir -Root $PSScriptRoot } +$logDir = Resolve-BakNRetRootedPath -Path $null -Default $script:Config.LogDir -Root $PSScriptRoot $catalogPath = Resolve-BakNRetCatalogPath -Configured $script:Config.SoftwareCatalog -Root $PSScriptRoot $manifestPath = Join-Path $BackupDir 'manifest.json'