fix: 源文件改存 UTF-8 with BOM,让 Windows PowerShell 5.1 真正可用
改造前:全仓 6/6 个源文件在 5.1 上解析失败(README 却承诺支持 5.1)。原因是文件是无 BOM 的 UTF-8,而 5.1 没有 BOM 就按 ANSI 代码页解码源码,中文变乱码、全角问号吃掉引号,整块语法塌掉。 现在 28/28 个文件在 5.1 与 7 上都解析零错误,E2E 36 项在 5.1 上全绿。 顺带修掉一个被 5.1 掩盖的缺陷:带 [CmdletBinding()] 的脚本在 5.1 上,param() 默认值里 拿不到 $PSScriptRoot(实测为空串,7 上正常)。于是 Backup.ps1 / Restore.ps1 在 5.1 上不传 路径参数就报错退出 —— 而计划任务恰恰不传。E2E 之所以看不见,是因为它总是显式传路径。 8 处默认值全部移到 param() 之后的解析段,沿用本仓库对 -BackupDir 一直在用的写法。 新增三条可重放的约定,让编码不再是一次性动作: .gitattributes 接管行尾(本机 core.autocrlf=true,会把工作区改成 CRLF 制造伪 diff) .editorconfig 用 charset = utf-8-bom 锁住 BOM tools\Set-SourceEncoding.ps1 是规范化脚本,tools\Invoke-* 之外的任何改动之后都能重放 test.ps1 是唯一验收入口:Encode + Parse + Unit + Smoke + E2E,在 7 与 5.1 上各跑一遍 test.ps1 的 Encode 层直接检查"必须有 BOM"这条规则。加它的原因很实际:实测本仓库用的 编辑工具在保存时会悄悄去掉 BOM,而丢了 BOM 的文件只在 5.1 上出错、在 7 上完全正常, 没有这条检查就会一直漏过去。 已知未修(下一步处理):5.1 上 Unit 有 6 项、Smoke 有 1 项失败,全部源于测试夹具写 临时文件时没指定编码(5.1 的 Set-Content 默认 ANSI),与产品代码无关。
This commit is contained in:
1 parent
dda36cfae5
commit
2d26f78d15
24 files changed
+457
-28
No files matched your search
@@ -1,4 +1,4 @@
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
把测试用的 Pester 5 装进仓库内的 .tools\modules(不动机器上的全局模块)。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
注册 / 移除 BakNRet 的每日备份计划任务。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
把归档名对齐到当前清单规则,并重建 manifest.json。
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$BackupListPath = (Join-Path (Split-Path -Parent $PSScriptRoot) 'BackupList.txt'),
|
||||
[string]$BackupListPath,
|
||||
[string]$BackupDir,
|
||||
[string]$ConfigPath,
|
||||
[switch]$Apply
|
||||
@@ -41,6 +41,13 @@ param(
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
|
||||
# 默认值不能写在 param() 里:Windows PowerShell 5.1 在带 [CmdletBinding()] 的脚本上,
|
||||
# 参数绑定阶段还没有给 $PSScriptRoot 赋值,默认值表达式会拿到空串(实测:带
|
||||
# [CmdletBinding()] -> 空串,不带 -> 正常;PowerShell 7 两种都正常)。所以默认值
|
||||
# 一律在这里补 —— 这也是本仓库对 -BackupDir / -ConfigPath 一直在用的写法。
|
||||
if (-not $BackupListPath) { $BackupListPath = Join-Path $projectRoot 'BackupList.txt' }
|
||||
|
||||
Import-Module (Join-Path $projectRoot 'Common.psm1') -Force
|
||||
|
||||
if (-not $ConfigPath) { $ConfigPath = Join-Path $projectRoot 'BackupConfig.psd1' }
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
把受管文本文件规范成仓库约定的编码:UTF-8 with BOM、LF 行尾。
|
||||
|
||||
.DESCRIPTION
|
||||
为什么需要一个可重放的脚本,而不是"改一次就完了":
|
||||
|
||||
* Windows PowerShell 5.1 在没有 BOM 时会按 ANSI 代码页解码源码文件,
|
||||
中文变乱码,而全角问号之类的字节序列会吃掉字符串引号、整块语法失效。
|
||||
* 但很多编辑器与工具在保存时会**悄悄去掉 BOM**。实测本仓库用的编辑工具就会
|
||||
(改过一次 test.ps1 之后它只在 5.1 上解析失败,在 7 上完全正常,极其隐蔽)。
|
||||
* 所以"加过 BOM"必须是一次能在任何改动之后重放的规范化操作。
|
||||
|
||||
受管范围与 .editorconfig 一致:
|
||||
* *.ps1 / *.psm1 / *.psd1 —— PowerShell 引擎直接读取,必须有 BOM
|
||||
* BackupList.txt —— 被 Get-Content 读取,必须有 BOM
|
||||
|
||||
只做两件事:补 BOM、把 CRLF 归一成 LF。不动缩进、不动内容、不换编码以外的东西。
|
||||
文件按 UTF-8 解码:本仓库的所有文本文件都是 UTF-8(见 .editorconfig)。
|
||||
|
||||
.PARAMETER WhatIf
|
||||
只报告将要改动什么,不写任何文件。
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\Set-SourceEncoding.ps1 -WhatIf
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\Set-SourceEncoding.ps1
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $true)]
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
|
||||
$excluded = '\\(\.git|\.tools|Backups|logs|dist|snapshots)\\'
|
||||
$targets = @(Get-ChildItem -LiteralPath $projectRoot -Recurse -File |
|
||||
Where-Object { $_.Extension -in '.ps1', '.psm1', '.psd1' -or $_.Name -eq 'BackupList.txt' } |
|
||||
Where-Object { $_.FullName -notmatch $excluded })
|
||||
|
||||
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
|
||||
$addedBom = @()
|
||||
$normalizedLf = @()
|
||||
|
||||
foreach ($file in $targets) {
|
||||
$bytes = [System.IO.File]::ReadAllBytes($file.FullName)
|
||||
$hasBom = $bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF
|
||||
$text = if ($hasBom) { $utf8NoBom.GetString($bytes, 3, $bytes.Length - 3) } else { $utf8NoBom.GetString($bytes) }
|
||||
|
||||
$normalized = ($text -split "`r?`n") -join "`n"
|
||||
$needsWrite = (-not $hasBom) -or ($normalized -ne $text)
|
||||
|
||||
if (-not $hasBom) { $addedBom += $file.FullName.Substring($projectRoot.Length).TrimStart('\') }
|
||||
if ($normalized -ne $text) { $normalizedLf += $file.FullName.Substring($projectRoot.Length).TrimStart('\') }
|
||||
|
||||
if ($needsWrite -and $PSCmdlet.ShouldProcess($file.FullName, '规范成 UTF-8 with BOM 与 LF')) {
|
||||
[System.IO.File]::WriteAllText($file.FullName, $normalized, $utf8Bom)
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ("受管文件 {0} 个" -f $targets.Count)
|
||||
if ($addedBom.Count -gt 0) {
|
||||
Write-Host ("补上 BOM {0} 个:" -f $addedBom.Count) -ForegroundColor Yellow
|
||||
$addedBom | ForEach-Object { Write-Host " $_" }
|
||||
} else {
|
||||
Write-Host '所有文件都已经带 BOM。' -ForegroundColor Green
|
||||
}
|
||||
if ($normalizedLf.Count -gt 0) {
|
||||
Write-Host ("行尾归一成 LF {0} 个:" -f $normalizedLf.Count) -ForegroundColor Yellow
|
||||
$normalizedLf | ForEach-Object { Write-Host " $_" }
|
||||
}
|
||||
|
||||
if (-not $WhatIfPreference) {
|
||||
Write-Host ''
|
||||
Write-Host '下一步:.\test.ps1 -Suite Parse 确认两个版本都能解析。' -ForegroundColor Cyan
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
BakNRet 隔离测试环境(Hyper-V 真机级 VM)的日常入口。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
BakNRet 隔离沙盒的假数据生成器(在 VM 内运行)。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<#
|
||||
<#
|
||||
.SYNOPSIS
|
||||
BakNRet 的安全描述符(属主 / ACL)场景演练 —— 在 lab 虚拟机内运行。
|
||||
|
||||
|
||||
Reference in new issue
Block a user