diff --git a/BakNRet/BakNRet.psd1 b/BakNRet/BakNRet.psd1 index ac17b20..f5a824f 100644 --- a/BakNRet/BakNRet.psd1 +++ b/BakNRet/BakNRet.psd1 @@ -19,6 +19,7 @@ CompatiblePSEditions = @('Desktop', 'Core') FunctionsToExport = @( + 'Set-BakNRetBackupListDirection', 'Save-BakNRetConfigFile', 'Get-BakNRetBackupListRow', 'Set-BakNRetBackupListRow', diff --git a/BakNRet/BakNRet.psm1 b/BakNRet/BakNRet.psm1 index 87d32ac..fbcf18e 100644 --- a/BakNRet/BakNRet.psm1 +++ b/BakNRet/BakNRet.psm1 @@ -162,7 +162,10 @@ . (Join-Path $PSScriptRoot 'Public\Save-BakNRetConfigFile.ps1') +. (Join-Path $PSScriptRoot 'Public\Set-BakNRetBackupListDirection.ps1') + Export-ModuleMember -Function @( + 'Set-BakNRetBackupListDirection', 'Save-BakNRetConfigFile', 'Get-BakNRetBackupListRow', 'Set-BakNRetBackupListRow', diff --git a/BakNRet/Public/Set-BakNRetBackupListDirection.ps1 b/BakNRet/Public/Set-BakNRetBackupListDirection.ps1 new file mode 100644 index 0000000..9df9506 --- /dev/null +++ b/BakNRet/Public/Set-BakNRetBackupListDirection.ps1 @@ -0,0 +1,47 @@ +function Set-BakNRetBackupListDirection { + <# + .SYNOPSIS + 改一行的方向(both / backup / restore),其余部分逐字节保持。 + + .DESCRIPTION + 为什么先只做"方向"这一种编辑:它是清单上最常改的东西,而且**能在文本层精确完成** —— + 加/去一个行首标记就行。要改别的字段就得把整行拆成字段再拼回去,而"拼回去"要在 + `Overrides` / `Flags` / 引号 / 转义之间做逆向,任何一处不精确都会把用户的清单改花。 + 外科式改写的底线是"只动我要动的那一处"(ADR-0013)。 + + **保留用户的写法风格**:仓库的真实清单里同时存在贴着写(`+WindowsTerminal`)与留空格 + (`+ WindowsTerminal`)两种。原样保留风格比统一成一种更安全 —— 统一意味着顺带改动了 + 那些我本来不该碰的行,而那正是"改一个字段却多出几十行 diff"的来源。 + + 注释行与空行**没有方向可改**,所以直接抛错:静默返回原样会制造"改了但没变"。 + #> + param( + [Parameter(Mandatory = $true)][AllowEmptyString()][string]$Raw, + [Parameter(Mandatory = $true)][ValidateSet('both', 'backup', 'restore')][string]$Direction + ) + + $record = ConvertFrom-BackupListLine -Line $Raw + if (-not $record) { throw '这一行不是条目(注释或空行),没有方向可改。' } + + # 拆出:行首缩进 + 原有标记的写法风格 + 标记之后的正文 + $indent = '' + $rest = $Raw + if ($rest -match '^(\s+)(.+)$') { + $indent = $Matches[1] + $rest = $Matches[2] + } + + $spaced = $false + $body = $rest + if ($body.Length -gt 0 -and ($body[0] -eq '+' -or $body[0] -eq '-')) { + $spaced = ($body.Length -gt 1 -and $body[1] -eq ' ') + $body = $body.Substring(1) + if ($spaced) { $body = $body.Substring(1) } + } + + if ($Direction -eq 'both') { return $indent + $body } + + $marker = if ($Direction -eq 'backup') { '+' } else { '-' } + if ($spaced) { return $indent + $marker + ' ' + $body } + return $indent + $marker + $body +} diff --git a/tests/Run-Tests.ps1 b/tests/Run-Tests.ps1 index 02376d5..62f9bce 100644 --- a/tests/Run-Tests.ps1 +++ b/tests/Run-Tests.ps1 @@ -1624,6 +1624,29 @@ Test-Case '保存配置:校验不过什么都不动,过了才备份 + 原子 } } +Test-Case '改方向:只动行首标记,其余逐字节保持,且保留用户写法风格' { + Assert-Equal '+Edge' (Set-BakNRetBackupListDirection -Raw 'Edge' -Direction 'backup') '裸行加 +' + Assert-Equal 'Edge' (Set-BakNRetBackupListDirection -Raw '+Edge' -Direction 'both') '去掉标记回到 both' + Assert-Equal '-Edge' (Set-BakNRetBackupListDirection -Raw '+Edge' -Direction 'restore') '备份改恢复' + Assert-Equal '-Edge :encrypt :- logs\' (Set-BakNRetBackupListDirection -Raw '+Edge :encrypt :- logs\' -Direction 'restore') '其余部分逐字节保持' + + # 风格保留:留空格的写法不能被改成贴着写(真实清单里两种都有) + Assert-Equal '+ WindowsTerminal' (Set-BakNRetBackupListDirection -Raw '+ WindowsTerminal' -Direction 'backup') '留空格风格保留' + Assert-Equal '- WindowsTerminal' (Set-BakNRetBackupListDirection -Raw '+ WindowsTerminal' -Direction 'restore') '改完仍是留空格' + Assert-Equal 'WindowsTerminal' (Set-BakNRetBackupListDirection -Raw '+ WindowsTerminal' -Direction 'both') '去掉留空格的标记' + + # 往返:设成当前方向 → 一行都不该变 + foreach ($line in @('Edge', '+Edge', '-Edge', '+ WindowsTerminal', '+Edge :encrypt # 说明')) { + $current = (ConvertFrom-BackupListLine -Line $line).Direction + Assert-Equal $line (Set-BakNRetBackupListDirection -Raw $line -Direction $current) ("设成当前方向应当原样返回:" + $line) + } + + # 注释行没有方向可改:抛错而不是静默返回原样 + $threw = $false + try { Set-BakNRetBackupListDirection -Raw '# 注释' -Direction 'backup' | Out-Null } catch { $threw = $true } + Assert-True $threw '注释行改方向必须抛错' +} + # ============================================================================ Remove-Item -LiteralPath $sandbox -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath $itemSandbox -Recurse -Force -ErrorAction SilentlyContinue