装配:Get-BakNRetCatalogField → 菜单选字段 → Read-BakNRetLine → Set-BakNRetCatalogField → Save-BakNRetConfigFile(校验通过才原子替换 + 时间戳备份)。 菜单里**只列可编辑的字段**(单行的 Encrypt / Description):把只读的 Path / Exclude 也列出来再拒绝,会让每个只读项浪费用户一次回车。 校验用模块自己的 Import-BaknretDataFile:这份名录有 $( ) 动态表达式与跨行拼接,普通数据文件读取器读不了 —— 而正是它保证"改完整份文件还能被程序读回来"(值能读回来才算改成功)。定位用 (软件名, Slot, 字段名) 三元组,因为同一软件可以有多个 Slot。 Edit-Config 的三个界面(清单 / 设置 / 名录)至此全部完成。 判据 9 条:改一个值后只动一行、注释行数不变、改完能读回新值、留下时间戳备份且备份里是原文;取消时不写盘也不产生备份。 验收:test.ps1 9/9 全绿(5.1 与 7);真实清单只读冒烟 4/4。
127 lines
5.7 KiB
PowerShell
127 lines
5.7 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
配置管理入口:改清单 / 改设置 / 改名录。
|
||
|
||
.DESCRIPTION
|
||
三个界面共用一个底色(ADR-0013):**外科式改写**(只动被编辑的那一处,注释与其它行一字节不动)、
|
||
**校验通过才落盘**(先写临时文件、用模块自己的读取器验、过了才原子替换)、**保存前留时间戳备份**
|
||
(logs\config-backups\)。
|
||
|
||
目前只有**清单**界面做完了;设置(BackupConfig.psd1)与名录(SoftwareCatalog.psd1)分别是
|
||
第二轮与第三轮的工作 —— 现在选它们会明确说"还没做"并返回非零,而不是假装成功。
|
||
|
||
进不了交互界面时明确失败(退出码 2)而不是挂起:TUI 的异常不该改退出码,但"根本没法交互"
|
||
是个必须让调用方知道的状态。
|
||
|
||
.EXAMPLE
|
||
.\Edit-Config.ps1 -Target List
|
||
|
||
.EXAMPLE
|
||
.\Edit-Config.ps1 -Target List -ListPath .\BackupList.txt -InputScript @('Enter','Down','Enter')
|
||
#>
|
||
[CmdletBinding()]
|
||
param(
|
||
[ValidateSet('List', 'Settings', 'Catalog')][string]$Target,
|
||
[string]$ListPath,
|
||
[string[]]$InputScript
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
$savedVerbosePreference = $VerbosePreference
|
||
$VerbosePreference = 'SilentlyContinue'
|
||
Import-Module (Join-Path $PSScriptRoot 'BakNRet\BakNRet.psd1') -Force
|
||
$VerbosePreference = $savedVerbosePreference
|
||
|
||
if (-not $ListPath) { $ListPath = Join-Path $PSScriptRoot 'BackupList.txt' }
|
||
|
||
function Invoke-BakNRetListEditorEntry {
|
||
param([string]$Path, [string[]]$Script)
|
||
$driver = New-BakNRetInputDriver -Script $Script -NonInteractive:$([bool]$Script)
|
||
$result = Invoke-BakNRetBackupListEditor -Path $Path -Driver $driver
|
||
if ($result.Saved) {
|
||
Write-Host ("已保存:{0}" -f $Path) -ForegroundColor Green
|
||
Write-Host ("原文件备份:{0}" -f $result.BackupPath) -ForegroundColor DarkGray
|
||
return 0
|
||
}
|
||
if ($result.Error) {
|
||
Write-Host $result.Error -ForegroundColor Yellow
|
||
return 1
|
||
}
|
||
Write-Host '没有改动。' -ForegroundColor DarkGray
|
||
return 0
|
||
}
|
||
|
||
if ($Target -eq 'List') {
|
||
exit (Invoke-BakNRetListEditorEntry -Path $ListPath -Script $InputScript)
|
||
}
|
||
|
||
if ($Target -eq 'Settings') {
|
||
$configPath = Join-Path $PSScriptRoot 'BackupConfig.psd1'
|
||
$driver = New-BakNRetInputDriver -Script $InputScript -NonInteractive:$([bool]$InputScript)
|
||
$saved = Invoke-BakNRetConfigEditor -Path $configPath -Driver $driver
|
||
if ($saved.Saved) { Write-Host ("已保存:{0}" -f $configPath) -ForegroundColor Green; Write-Host ("原文件备份:{0}" -f $saved.BackupPath) -ForegroundColor DarkGray; exit 0 }
|
||
if ($saved.Error) { Write-Host $saved.Error -ForegroundColor Yellow; exit 1 }
|
||
Write-Host '没有改动。' -ForegroundColor DarkGray
|
||
exit 0
|
||
}
|
||
|
||
if ($Target -eq 'Catalog') {
|
||
$catalogPath = Join-Path $PSScriptRoot 'SoftwareCatalog.psd1'
|
||
$driver = New-BakNRetInputDriver -Script $InputScript -NonInteractive:$([bool]$InputScript)
|
||
$saved = Invoke-BakNRetCatalogEditor -Path $catalogPath -Driver $driver
|
||
if ($saved.Saved) { Write-Host ("已保存:{0}" -f $catalogPath) -ForegroundColor Green; Write-Host ("原文件备份:{0}" -f $saved.BackupPath) -ForegroundColor DarkGray; exit 0 }
|
||
if ($saved.Error) { Write-Host $saved.Error -ForegroundColor Yellow; exit 1 }
|
||
Write-Host '没有改动。' -ForegroundColor DarkGray
|
||
exit 0
|
||
}
|
||
|
||
if ($Target) {
|
||
Write-Host ("{0} 的编辑器还没做:清单 / 设置 / 名录三个界面都已完成。" -f $Target) -ForegroundColor Yellow
|
||
exit 1
|
||
}
|
||
|
||
# 不带 -Target:进配置菜单
|
||
if ([Console]::IsOutputRedirected -and -not $InputScript) {
|
||
Write-Host '没有可用的控制台,也没有给出 -InputScript:无法进入交互界面。' -ForegroundColor Red
|
||
Write-Host '要非交互执行,请指定目标,例如:-Target List' -ForegroundColor Red
|
||
exit 2
|
||
}
|
||
|
||
$driver = New-BakNRetInputDriver -Script $InputScript -NonInteractive:$([bool]$InputScript)
|
||
$items = @(
|
||
[pscustomobject]@{ Key = 'List'; Text = '清单 BackupList.txt —— 改方向,改完校验' }
|
||
[pscustomobject]@{ Key = 'Settings'; Text = '设置 BackupConfig.psd1 —— 还没做(第二轮)' }
|
||
[pscustomobject]@{ Key = 'Catalog'; Text = '名录 SoftwareCatalog.psd1 —— 还没做(第三轮)' }
|
||
)
|
||
|
||
$picked = Invoke-BakNRetMenu -Title '配置' -Items $items -Driver $driver -MultiSelect $false -Hint '↑↓ 选择 回车 进入 Esc 返回'
|
||
if ($picked.Action -ne 'confirm') { exit 0 }
|
||
|
||
if ($picked.Chosen.Key -eq 'List') {
|
||
exit (Invoke-BakNRetListEditorEntry -Path $ListPath -Script $InputScript)
|
||
}
|
||
|
||
if ($picked.Chosen.Key -eq 'Settings') {
|
||
$configPath = Join-Path $PSScriptRoot 'BackupConfig.psd1'
|
||
$driver2 = New-BakNRetInputDriver -Script $InputScript -NonInteractive:$([bool]$InputScript)
|
||
$saved2 = Invoke-BakNRetConfigEditor -Path $configPath -Driver $driver2
|
||
if ($saved2.Saved) { Write-Host ("已保存:{0}" -f $configPath) -ForegroundColor Green; exit 0 }
|
||
if ($saved2.Error) { Write-Host $saved2.Error -ForegroundColor Yellow; exit 1 }
|
||
Write-Host '没有改动。' -ForegroundColor DarkGray
|
||
exit 0
|
||
}
|
||
|
||
if ($picked.Chosen.Key -eq 'Catalog') {
|
||
$catalogPath = Join-Path $PSScriptRoot 'SoftwareCatalog.psd1'
|
||
$driver3 = New-BakNRetInputDriver -Script $InputScript -NonInteractive:$([bool]$InputScript)
|
||
$saved3 = Invoke-BakNRetCatalogEditor -Path $catalogPath -Driver $driver3
|
||
if ($saved3.Saved) { Write-Host ("已保存:{0}" -f $catalogPath) -ForegroundColor Green; exit 0 }
|
||
if ($saved3.Error) { Write-Host $saved3.Error -ForegroundColor Yellow; exit 1 }
|
||
Write-Host '没有改动。' -ForegroundColor DarkGray
|
||
exit 0
|
||
}
|
||
|
||
Write-Host ("未知的目标:{0}" -f $picked.Chosen.Key) -ForegroundColor Yellow
|
||
exit 1
|