fix: 让 5.1 真正可用(显式编码 + 原生 stderr 处理 + .psd1 夹具带 BOM)
上一提交让 5.1 能解析源码,但 Unit 与 Smoke 在 5.1 上仍然是红的。根因是三类彼此 无关的 5.1/7 行为差,全部实测确认: 1) 不写 -Encoding 时,5.1 的 Get-Content / Set-Content 默认是 ANSI,7 是 UTF-8。 症状是 UTF-8 字节被按 GBK 解出「璇存槑」这类乱码。62 处补上显式 -Encoding UTF8。 用 AST 而不是正则定位,避免把注释里的散文也改掉。 2) .psd1 夹具用无 BOM 写,而引擎的 .psd1 读取器(Import-PowerShellDataFile)只能靠 BOM 判断编码、没有参数可传,于是 5.1 按 ANSI 解。40 处夹具改为带 BOM 写 —— 这正是 .editorconfig 里 [*.psd1] charset = utf-8-bom 本来就要求的,是夹具违反了自己的约定。 .cmd 批次文件刻意保持无 BOM:cmd.exe 会被 BOM 弄坏。 3) 5.1 在 $ErrorActionPreference = Stop 下会把原生命令写到 stderr 的内容升级成终止性 NativeCommandError,7 改了这条。takeown/icacls 的 ACL 复位调用、以及 test.ps1 自己 调子进程的地方,都需要在 Continue 下跑。 验收:test.ps1 9/9 全绿(Encode + Parse + Unit + Smoke + E2E,在 7 与 5.1 上各跑一遍)。 已知未处理(留待后续提交):tools/lab/** 里还有若干「原生命令 + 2>&1 + Stop」的同类 写法(takeown / icacls / scoop / code / Get-WimInfo)。它们要 Hyper-V 实验机才跑得到, 不在验收门槛内。
This commit is contained in:
1 parent
2d26f78d15
commit
e10503be76
13 files changed
+122
-104
No files matched your search
+19
-19
@@ -74,7 +74,7 @@ function New-E2EConfig {
|
||||
if ($SoftwareCatalog) { $lines += " SoftwareCatalog = '$SoftwareCatalog'" }
|
||||
$lines += " CatalogMaxDepth = $CatalogMaxDepth"
|
||||
$lines += '}'
|
||||
[System.IO.File]::WriteAllText($Path, ($lines -join "`r`n"), [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($Path, ($lines -join "`r`n"), [System.Text.UTF8Encoding]::new($true))
|
||||
}
|
||||
|
||||
function Get-NewestLog {
|
||||
@@ -141,7 +141,7 @@ $blob = New-Object byte[] 8192
|
||||
(New-Object System.Random 42).NextBytes($blob)
|
||||
[System.IO.File]::WriteAllBytes((Join-Path $source 'blob.bin'), $blob)
|
||||
|
||||
[System.IO.File]::WriteAllText($listPath, "# e2e`n$source :- logs\,!*Cache`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($listPath, "# e2e`n$source :- logs\,!*Cache`n", [System.Text.UTF8Encoding]::new($true))
|
||||
|
||||
$expectedHashes = @{}
|
||||
foreach ($relative in 'keep.txt', 'sub\b.txt', 'blob.bin') {
|
||||
@@ -243,7 +243,7 @@ $cfg2 = Join-Path $WorkRoot 'cfg2.psd1'
|
||||
New-E2EConfig -Path $cfg2 -LogDir $logDir2
|
||||
New-Item -ItemType Directory -Path $lockSource -Force | Out-Null
|
||||
Set-Content -LiteralPath (Join-Path $lockSource 'a.txt') -Value 'aaa' -Encoding UTF8
|
||||
[System.IO.File]::WriteAllText($lockList, "$lockSource`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($lockList, "$lockSource`n", [System.Text.UTF8Encoding]::new($true))
|
||||
|
||||
& $backupScript -BackupListPath $lockList -BackupDir $lockBackupDir -ConfigPath $cfg2 -Force -QuietTool
|
||||
$cleanExitCode = $LASTEXITCODE
|
||||
@@ -335,7 +335,7 @@ Set-Content -LiteralPath (Join-Path $incDir 'i.txt') -Value 'included' -Encoding
|
||||
"@, [System.Text.UTF8Encoding]::new($false))
|
||||
|
||||
# 条目级排除用 Slot 前缀点名(AlphaData\plain)+ 任意层级(!*skip);:+ 把 inc 放到归档内 Modules\
|
||||
[System.IO.File]::WriteAllText($catList, "my-app :- AlphaData\plain,!*skip :+ Modules:$incDir`ncat-excl`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($catList, "my-app :- AlphaData\plain,!*skip :+ Modules:$incDir`ncat-excl`n", [System.Text.UTF8Encoding]::new($true))
|
||||
New-E2EConfig -Path $catConfig -LogDir $catLogDir -SoftwareCatalog $catFile
|
||||
|
||||
$catHashes = @{
|
||||
@@ -433,7 +433,7 @@ Test-Case '恢复不会把被排除的内容带回来' {
|
||||
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 :+ Modules:$settingsFile`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($pathList, "my-app @pathname :+ Modules:$settingsFile`n", [System.Text.UTF8Encoding]::new($true))
|
||||
# settings.json 刚才被删了,重建一份,让 Include 的宿主机路径存在
|
||||
Set-Content -LiteralPath $settingsFile -Value '{"slot":"file"}' -Encoding UTF8
|
||||
$expectedBase = Get-BackupBaseName -RawPath $dirA
|
||||
@@ -455,8 +455,8 @@ $ovrConfig = Join-Path $ovrRoot 'config.psd1'
|
||||
$ovrExtract = Join-Path $ovrRoot 'verify'
|
||||
New-Item -ItemType Directory -Path $ovrTarget -Force | Out-Null
|
||||
Set-Content -LiteralPath (Join-Path $ovrTarget 't.txt') -Value 'override-target' -Encoding UTF8
|
||||
[System.IO.File]::WriteAllText($ovrCatalog, "@{`n 'ovr-app' = @{ DefaultData = @{ Path = '$ovrRoot\missing-src' } }`n}`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($ovrList, "ovr-app :: $ovrTarget`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($ovrCatalog, "@{`n 'ovr-app' = @{ DefaultData = @{ Path = '$ovrRoot\missing-src' } }`n}`n", [System.Text.UTF8Encoding]::new($true))
|
||||
[System.IO.File]::WriteAllText($ovrList, "ovr-app :: $ovrTarget`n", [System.Text.UTF8Encoding]::new($true))
|
||||
New-E2EConfig -Path $ovrConfig -LogDir (Join-Path $ovrRoot 'logs') -SoftwareCatalog $ovrCatalog
|
||||
|
||||
& $backupScript -BackupListPath $ovrList -BackupDir $ovrBackupDir -ConfigPath $ovrConfig -Force -QuietTool
|
||||
@@ -471,7 +471,7 @@ Test-Case ':: 覆盖:备份包内容来自被覆盖的路径,且归档项名
|
||||
$null = Invoke-ExternalCommand -FilePath $sevenZip -ArgumentList @('x', '-bso0', '-bsp0', '-y', "-o$ovrExtract", $ovrArchives[0].FullName)
|
||||
}
|
||||
Assert-FileExists (Join-Path $ovrExtract 'DefaultData\t.txt')
|
||||
Assert-Equal 'override-target' (Get-Content -LiteralPath (Join-Path $ovrExtract 'DefaultData\t.txt') -Raw).Trim()
|
||||
Assert-Equal 'override-target' (Get-Content -Encoding UTF8 -LiteralPath (Join-Path $ovrExtract 'DefaultData\t.txt') -Raw).Trim()
|
||||
}
|
||||
|
||||
Test-Case ':: 覆盖:删掉被覆盖的源后仍能恢复回该路径' {
|
||||
@@ -479,7 +479,7 @@ Test-Case ':: 覆盖:删掉被覆盖的源后仍能恢复回该路径' {
|
||||
& $restoreScript -BackupListPath $ovrList -BackupDir $ovrBackupDir -ConfigPath $ovrConfig -Force
|
||||
Assert-Equal 0 $LASTEXITCODE
|
||||
Assert-FileExists (Join-Path $ovrTarget 't.txt')
|
||||
Assert-Equal 'override-target' (Get-Content -LiteralPath (Join-Path $ovrTarget 't.txt') -Raw).Trim()
|
||||
Assert-Equal 'override-target' (Get-Content -Encoding UTF8 -LiteralPath (Join-Path $ovrTarget 't.txt') -Raw).Trim()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
@@ -499,10 +499,10 @@ New-Item -ItemType Directory -Path $appA -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $appB -Force | Out-Null
|
||||
Set-Content -LiteralPath (Join-Path $appA 'a.txt') -Value 'dir-a' -Encoding UTF8
|
||||
Set-Content -LiteralPath (Join-Path $appB 'b.txt') -Value 'dir-b' -Encoding UTF8
|
||||
[System.IO.File]::WriteAllText($dirCatalog, "@{`n 'app-a' = @{ DefaultData = @{ Path = '$appA' } }`n 'app-b' = @{ DefaultData = @{ Path = '$appB' } }`n}`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($dirCatalog, "@{`n 'app-a' = @{ DefaultData = @{ Path = '$appA' } }`n 'app-b' = @{ DefaultData = @{ Path = '$appB' } }`n}`n", [System.Text.UTF8Encoding]::new($true))
|
||||
New-E2EConfig -Path $dirConfig -LogDir $dirLogDir -SoftwareCatalog $dirCatalog
|
||||
[System.IO.File]::WriteAllText($dirList1, "+ app-a`napp-b`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($dirList2, "+ app-a`n- app-b`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($dirList1, "+ app-a`napp-b`n", [System.Text.UTF8Encoding]::new($true))
|
||||
[System.IO.File]::WriteAllText($dirList2, "+ app-a`n- app-b`n", [System.Text.UTF8Encoding]::new($true))
|
||||
|
||||
& $backupScript -BackupListPath $dirList1 -BackupDir $dirBackupDir -ConfigPath $dirConfig -Force -QuietTool
|
||||
Test-Case '行首 + = 仅备份:仍然会被打包' {
|
||||
@@ -539,7 +539,7 @@ Test-Case '恢复端跳过行首 + 的条目、照常恢复 - 的条目' {
|
||||
Assert-Equal 0 $LASTEXITCODE
|
||||
Assert-FileMissing $appA '行首 + 的条目不该被恢复'
|
||||
Assert-FileExists (Join-Path $appB 'b.txt')
|
||||
Assert-Equal 'dir-b' (Get-Content -LiteralPath (Join-Path $appB 'b.txt') -Raw).Trim()
|
||||
Assert-Equal 'dir-b' (Get-Content -Encoding UTF8 -LiteralPath (Join-Path $appB 'b.txt') -Raw).Trim()
|
||||
|
||||
$restoreLog = Get-NewestLog -LogDir $dirLogDir -Prefix 'restore'
|
||||
$restoreContent = Get-Content -LiteralPath $restoreLog.FullName -Raw -Encoding UTF8
|
||||
@@ -572,8 +572,8 @@ if ($sevenZip) {
|
||||
-WorkingDirectory $legacyScratch
|
||||
}
|
||||
|
||||
[System.IO.File]::WriteAllText($legacyCatalog, "@{`n 'legacy-file' = @{ LegacyData = @{ Path = '$legacyLive' } }`n}`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($legacyList, "legacy-file`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($legacyCatalog, "@{`n 'legacy-file' = @{ LegacyData = @{ Path = '$legacyLive' } }`n}`n", [System.Text.UTF8Encoding]::new($true))
|
||||
[System.IO.File]::WriteAllText($legacyList, "legacy-file`n", [System.Text.UTF8Encoding]::new($true))
|
||||
New-E2EConfig -Path $legacyConfig -LogDir $legacyLogDir -SoftwareCatalog $legacyCatalog
|
||||
|
||||
$legacyManifest = Read-BaknretManifest -Path (Join-Path $legacyBackupDir 'manifest.json')
|
||||
@@ -595,7 +595,7 @@ if ($sevenZip) {
|
||||
|
||||
Test-Case '旧布局归档:按 <末级名> 回退,把文件还原回原位' {
|
||||
Assert-Equal 0 $legacyExitCode
|
||||
Assert-Equal '{"version":"old-layout"}' (Get-Content -LiteralPath $legacyLive -Raw).Trim()
|
||||
Assert-Equal '{"version":"old-layout"}' (Get-Content -Encoding UTF8 -LiteralPath $legacyLive -Raw).Trim()
|
||||
$legacyLog = Get-NewestLog -LogDir $legacyLogDir -Prefix 'restore'
|
||||
$legacyContent = Get-Content -LiteralPath $legacyLog.FullName -Raw -Encoding UTF8
|
||||
Assert-True ($legacyContent -like '*按旧布局回退*') '回退时必须给出明确告警'
|
||||
@@ -633,7 +633,7 @@ Test-Case 'Backup -DryRun:退出码 0、不写归档也不写 manifest' {
|
||||
|
||||
Test-Case '归档名重复时直接报失败,不静默互相覆盖' {
|
||||
$dupList = Join-Path $catRoot 'dup.txt'
|
||||
[System.IO.File]::WriteAllText($dupList, "my-app`nmy-app`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($dupList, "my-app`nmy-app`n", [System.Text.UTF8Encoding]::new($true))
|
||||
& $backupScript -BackupListPath $dupList -BackupDir $catBackupDir -ConfigPath $catConfig -Force -QuietTool
|
||||
Assert-Equal 1 $LASTEXITCODE '重复条目应让退出码为 1'
|
||||
}
|
||||
@@ -641,14 +641,14 @@ Test-Case '归档名重复时直接报失败,不静默互相覆盖' {
|
||||
Test-Case '字面路径不受名录影响,仍走路径命名' {
|
||||
$literalList = Join-Path $catRoot 'list-literal.txt'
|
||||
$literalDir = Join-Path $catRoot 'Backups-literal'
|
||||
[System.IO.File]::WriteAllText($literalList, "$dirA2`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($literalList, "$dirA2`n", [System.Text.UTF8Encoding]::new($true))
|
||||
& $backupScript -BackupListPath $literalList -BackupDir $literalDir -ConfigPath $catConfig -Force -QuietTool
|
||||
Assert-Equal 0 $LASTEXITCODE
|
||||
Assert-FileExists (Join-Path $literalDir ((Get-BackupBaseName -RawPath $dirA2) + '.7z'))
|
||||
}
|
||||
|
||||
$missingList = Join-Path $WorkRoot 'missing.txt'
|
||||
[System.IO.File]::WriteAllText($missingList, "Z:\definitely-not-here-12345`n", [System.Text.UTF8Encoding]::new($false))
|
||||
[System.IO.File]::WriteAllText($missingList, "Z:\definitely-not-here-12345`n", [System.Text.UTF8Encoding]::new($true))
|
||||
& $backupScript -BackupListPath $missingList -BackupDir $backupDir -ConfigPath $cfg1 -Force -QuietTool
|
||||
$missingExitCode = $LASTEXITCODE
|
||||
|
||||
|
||||
Reference in new issue
Block a user