需求
- 支持两种条目写法:1) 直接写软件名录里的软件名;2) 用户手写目录。
- 两种写法都必须支持追加(:+)与排除(:-)。
- 软件名录要改进:scoop 合并成"一个软件 + 一个目录数组"。
- 运行时要把"分别是哪些目录、每个目录是干什么的、排除/追加的理由"讲清楚。
实现
- 名录(SoftwareCatalog.psd1 / Get-SoftwareCatalog)
* 一个软件挂多个目录时写成**对象数组**:@{ Path = '...'; Description = '...' };
也接受纯字符串数组与旧的 @{ Dirs = ... } / @{ Variants = ... }。
* 目录说明(Description)一路带到运行日志里。
* "声明了但当前不存在"的目录不再被丢掉:备份跳过,恢复仍然知道它该回到哪个位置。
* scoop 合并成一个数组条目(%UserProfile%\scoop\persist + %UserProfile%\.config\scoop);
ScoopApps-persist 保持独立条目 —— 它和前者末级名同为 persist,并进同一个归档会在包里撞名。
- 解析与解析结果(ConvertFrom-BackupListLine / Resolve-BackupEntry)
* `:+` 以前只对"软件名且能解析出目录"的写法生效,**手写目录的 :+ 会被整段丢掉**;
现在统一生效,且 :+ 后面写软件名会按名录展开。
* 行尾 `# 说明` 解析成 Comment,运行时打印。
- 归档与恢复
* 同一条目里两个同名目录:打包前明确报错(退出码 1),不再静默混成一棵树。
(7z 命令行没有"入库改名"的能力,归档内顶层名只能是文件系统上的那个名字。)
* 恢复时每个源只解出**它自己那棵子树**,不会再往别的父目录里复制兄弟目录。
- 可解释性
* 新增 Write-BackupEntryPlan:打包前打印条目的目录(含来源与介绍)以及排除/追加的出处;
Restore.ps1 同样打印"哪棵子树还原到哪、会新建还是覆盖"。
- 孤儿归档审计修正:判据只看当前清单,不再把 manifest 的历史记录当成"已知"。
否则"条目被合并/改名后留下的旧归档"会被历史记录遮住,永远不会报警。
验证
- Pester 84 项、零依赖单元 49 项、端到端 23 项,全部通过。
- 真实机器:合并后的 scoop.7z 233 MB / 29478 项 / 7z t 通过,manifest.roots=[persist|scoop];
恢复演练 26982/26982 逐字节一致(.ssh、legendary、Aria 同批通过)。
- 迁移提醒:scoop-config.7z 与 scoop-persist.7z 已无清单条目指向,会出现在孤儿审计里;
确认 scoop.7z 无误后可以自行删除。
87 lines
3.3 KiB
PowerShell
87 lines
3.3 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
跑 BakNRet 的 Pester 测试套件(tests/BakNRet.Tests.ps1)。
|
||
|
||
.DESCRIPTION
|
||
Pester 从哪儿来,按优先级:
|
||
1. 仓库内的 .tools\modules(由 tools/Install-TestDependencies.ps1 放的本地副本,已 gitignore);
|
||
2. 机器上已安装的 Pester 5+。
|
||
|
||
两者都没有时给出一条明确的安装命令并以退出码 2 结束,而不是抛一堆看不懂的错。
|
||
|
||
为什么显式要求 Pester 5.0+:3.4.0 没有 `Should -Be`,本套件会直接语法错误。
|
||
本脚本只把 .tools\modules 临时加进 PSModulePath,**不会**去改机器上的全局模块。
|
||
|
||
.EXAMPLE
|
||
pwsh -File .\tests\Run-Pester.ps1
|
||
|
||
.EXAMPLE
|
||
pwsh -File .\tests\Run-Pester.ps1 -Verbosity Minimal
|
||
#>
|
||
|
||
[CmdletBinding()]
|
||
param(
|
||
[ValidateSet('Detailed', 'Normal', 'Minimal', 'None')]
|
||
[string]$Verbosity = 'Detailed',
|
||
|
||
[string[]]$Tag,
|
||
|
||
# 默认跑 tests/ 下所有 *.Tests.ps1(Pester 按这个命名约定发现)
|
||
[string]$TestPath = $PSScriptRoot
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||
$localModules = Join-Path $projectRoot '.tools\modules'
|
||
if (Test-Path -LiteralPath $localModules) {
|
||
$env:PSModulePath = $localModules + [System.IO.Path]::PathSeparator + $env:PSModulePath
|
||
}
|
||
|
||
$pester = Get-Module -ListAvailable Pester |
|
||
Where-Object { [version]$_.Version -ge [version]'5.0.0' } |
|
||
Sort-Object { [version]$_.Version } -Descending |
|
||
Select-Object -First 1
|
||
|
||
if (-not $pester) {
|
||
$installed = @(Get-Module -ListAvailable Pester | ForEach-Object { $_.Version.ToString() })
|
||
|
||
Write-Host ''
|
||
Write-Host '找不到 Pester 5.0+,无法运行 Pester 套件。' -ForegroundColor Red
|
||
if ($installed.Count -gt 0) {
|
||
Write-Host ("已安装的版本:{0}(3.x 没有 Should -Be,本套件会语法错误)" -f ($installed -join '、')) -ForegroundColor Yellow
|
||
}
|
||
Write-Host ''
|
||
Write-Host '两种拿到 Pester 5+ 的方式(任选其一):' -ForegroundColor Cyan
|
||
Write-Host ' A. 只装到仓库里(推荐,不动机器上的全局模块):' -ForegroundColor Cyan
|
||
Write-Host ' .\tools\Install-TestDependencies.ps1' -ForegroundColor Gray
|
||
Write-Host ' B. 装到当前用户:' -ForegroundColor Cyan
|
||
Write-Host ' Install-Module Pester -Scope CurrentUser -MinimumVersion 5.0.0' -ForegroundColor Gray
|
||
Write-Host ''
|
||
Write-Host '零依赖的替代方案:.\tests\Run-Tests.ps1(不需要 Pester)' -ForegroundColor Cyan
|
||
Write-Host ''
|
||
exit 2
|
||
}
|
||
|
||
Import-Module $pester.Path -Force
|
||
Write-Host ("Pester {0} ({1})" -f $pester.Version, $pester.ModuleBase) -ForegroundColor DarkGray
|
||
Write-Host ("测试文件:{0}" -f $TestPath) -ForegroundColor DarkGray
|
||
|
||
$configuration = New-PesterConfiguration
|
||
$configuration.Run.Path = $TestPath
|
||
$configuration.Run.PassThru = $true
|
||
$configuration.Run.Exit = $false
|
||
$configuration.Output.Verbosity = $Verbosity
|
||
if ($Tag) { $configuration.Filter.Tag = $Tag }
|
||
|
||
$result = Invoke-Pester -Configuration $configuration
|
||
|
||
Write-Host ''
|
||
if ($result.FailedCount -gt 0) {
|
||
Write-Host ("Pester 测试通过 {0} 项,失败 {1} 项,跳过 {2} 项" -f $result.PassedCount, $result.FailedCount, $result.SkippedCount) -ForegroundColor Red
|
||
exit 1
|
||
}
|
||
|
||
Write-Host ("Pester 测试全部通过:{0} 项(跳过 {1} 项)" -f $result.PassedCount, $result.SkippedCount) -ForegroundColor Green
|
||
exit 0
|