Skip to content

Commit 728b292

Browse files
committed
build: add postgresql toolkit bundler
1 parent 0ae70a7 commit 728b292

3 files changed

Lines changed: 203 additions & 0 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"test:pwsh:slowest": "pnpm test:pwsh:assertions:slowest",
4040
"test:pwsh:all:slowest": "node ./scripts/pester-duration-report.mjs --command \"pnpm test:pwsh:all\"",
4141
"benchmark": "pwsh -NoProfile -File ./scripts/pwsh/devops/Invoke-Benchmark.ps1",
42+
"build:pwsh:postgresql": "pwsh -NoProfile -File ./scripts/pwsh/devops/postgresql/build/Build-PostgresToolkit.ps1",
4243
"scripts:install": "pwsh -File ./install.ps1",
4344
"scoop:update": "scoop update -a",
4445
"choco:update": "choco upgrade all -y",
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
#!/usr/bin/env pwsh
2+
<#
3+
.SYNOPSIS
4+
构建 PostgreSQL Toolkit 的单文件脚本与帮助文档。
5+
6+
.DESCRIPTION
7+
将 PostgreSQL Toolkit 的多文件源码按固定顺序拼装为单文件 PowerShell 脚本,
8+
并同步输出独立 Markdown 帮助文档,便于分发与离线查看。
9+
10+
.PARAMETER SourceRoot
11+
PostgreSQL Toolkit 源码目录,默认为当前 build 目录的上一级。
12+
13+
.PARAMETER OutputScriptPath
14+
单文件脚本输出路径。
15+
16+
.PARAMETER OutputHelpPath
17+
独立帮助文档输出路径。
18+
#>
19+
[CmdletBinding()]
20+
param(
21+
[string]$SourceRoot = (Join-Path $PSScriptRoot '..'),
22+
[string]$OutputScriptPath = (Join-Path $PSScriptRoot '..' '..' 'Postgres-Toolkit.ps1'),
23+
[string]$OutputHelpPath = (Join-Path $PSScriptRoot '..' '..' 'Postgres-Toolkit.Help.md')
24+
)
25+
26+
Set-StrictMode -Version Latest
27+
$ErrorActionPreference = 'Stop'
28+
29+
<#
30+
.SYNOPSIS
31+
读取脚本文件并返回原始内容。
32+
33+
.DESCRIPTION
34+
在拼装前统一校验文件存在性,避免遗漏源码片段导致 bundle 不完整。
35+
36+
.PARAMETER Path
37+
待读取的脚本文件路径。
38+
39+
.OUTPUTS
40+
string
41+
返回脚本文件的原始文本内容。
42+
#>
43+
function Get-BundleFileContent {
44+
[CmdletBinding()]
45+
param(
46+
[Parameter(Mandatory)]
47+
[string]$Path
48+
)
49+
50+
if (-not (Test-Path -Path $Path -PathType Leaf)) {
51+
throw "缺少源码片段: $Path"
52+
}
53+
54+
return Get-Content -Path $Path -Raw
55+
}
56+
57+
<#
58+
.SYNOPSIS
59+
从 `main.ps1` 提取命令分发函数定义。
60+
61+
.DESCRIPTION
62+
使用 PowerShell AST 读取 `Invoke-PostgresToolkitCommand` 的源码范围,
63+
避免直接拼接 `main.ps1` 时把 `param(...)` 块放到非法位置。
64+
65+
.PARAMETER MainScriptPath
66+
`main.ps1` 的完整路径。
67+
68+
.OUTPUTS
69+
string
70+
返回函数定义源码文本。
71+
#>
72+
function Get-MainDispatchFunctionContent {
73+
[CmdletBinding()]
74+
param(
75+
[Parameter(Mandatory)]
76+
[string]$MainScriptPath
77+
)
78+
79+
$tokens = $null
80+
$errors = $null
81+
$ast = [System.Management.Automation.Language.Parser]::ParseFile($MainScriptPath, [ref]$tokens, [ref]$errors)
82+
if ($errors.Count -gt 0) {
83+
$errorText = ($errors | ForEach-Object { $_.Message }) -join '; '
84+
throw "解析 main.ps1 失败: $errorText"
85+
}
86+
87+
$functionAst = $ast.Find(
88+
{
89+
param($node)
90+
$node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $node.Name -eq 'Invoke-PostgresToolkitCommand'
91+
},
92+
$true
93+
)
94+
95+
if ($null -eq $functionAst) {
96+
throw "未在 main.ps1 中找到 Invoke-PostgresToolkitCommand。"
97+
}
98+
99+
return $functionAst.Extent.Text
100+
}
101+
102+
$bundleParts = @(
103+
'core/logging.ps1'
104+
'core/process.ps1'
105+
'core/arguments.ps1'
106+
'core/connection.ps1'
107+
'core/context.ps1'
108+
'core/formats.ps1'
109+
'core/validation.ps1'
110+
'platforms/windows.ps1'
111+
'platforms/macos.ps1'
112+
'platforms/linux.ps1'
113+
'commands/help.ps1'
114+
'commands/backup.ps1'
115+
'commands/restore.ps1'
116+
'commands/import-csv.ps1'
117+
'commands/install-tools.ps1'
118+
)
119+
120+
$mainScriptPath = Join-Path $SourceRoot 'main.ps1'
121+
$bundleContent = New-Object 'System.Collections.Generic.List[string]'
122+
123+
$bundleContent.Add('#!/usr/bin/env pwsh')
124+
$bundleContent.Add('<#')
125+
$bundleContent.Add('.SYNOPSIS')
126+
$bundleContent.Add(' PostgreSQL 常用备份、恢复、CSV 导入与工具安装命令行工具。')
127+
$bundleContent.Add('')
128+
$bundleContent.Add('.DESCRIPTION')
129+
$bundleContent.Add(' 单文件分发产物,内嵌 PostgreSQL Toolkit 的核心 helper、命令翻译和帮助输出。')
130+
$bundleContent.Add('')
131+
$bundleContent.Add('.PARAMETER CommandName')
132+
$bundleContent.Add(' 要执行的子命令名称,例如 `backup`、`restore`、`import-csv`、`install-tools`。')
133+
$bundleContent.Add('')
134+
$bundleContent.Add('.PARAMETER RawArguments')
135+
$bundleContent.Add(' 透传给子命令解析器的剩余参数数组。')
136+
$bundleContent.Add('#>')
137+
$bundleContent.Add('[CmdletBinding(PositionalBinding = $false)]')
138+
$bundleContent.Add('param(')
139+
$bundleContent.Add(' [Parameter(Position = 0)]')
140+
$bundleContent.Add(' [string]$CommandName,')
141+
$bundleContent.Add('')
142+
$bundleContent.Add(' [Parameter(ValueFromRemainingArguments = $true)]')
143+
$bundleContent.Add(' [string[]]$RawArguments')
144+
$bundleContent.Add(')')
145+
$bundleContent.Add('')
146+
$bundleContent.Add('Set-StrictMode -Version Latest')
147+
$bundleContent.Add('$ErrorActionPreference = ''Stop''')
148+
149+
foreach ($relativePath in $bundleParts) {
150+
$fullPath = Join-Path $SourceRoot $relativePath
151+
$bundleContent.Add('')
152+
$bundleContent.Add("# region $relativePath")
153+
$bundleContent.Add((Get-BundleFileContent -Path $fullPath))
154+
$bundleContent.Add("# endregion $relativePath")
155+
}
156+
157+
$bundleContent.Add('')
158+
$bundleContent.Add('# region main-dispatch')
159+
$bundleContent.Add((Get-MainDispatchFunctionContent -MainScriptPath $mainScriptPath))
160+
$bundleContent.Add('# endregion main-dispatch')
161+
$bundleContent.Add('')
162+
$bundleContent.Add('if ($env:PWSH_TEST_SKIP_POSTGRES_TOOLKIT_MAIN -ne ''1'') {')
163+
$bundleContent.Add(' $result = Invoke-PostgresToolkitCommand -CommandName $CommandName -RawArguments $RawArguments')
164+
$bundleContent.Add(' if (-not [string]::IsNullOrWhiteSpace($result.Output)) {')
165+
$bundleContent.Add(' Write-Output $result.Output')
166+
$bundleContent.Add(' }')
167+
$bundleContent.Add('')
168+
$bundleContent.Add(' exit $result.ExitCode')
169+
$bundleContent.Add('}')
170+
171+
$scriptDirectory = Split-Path -Path $OutputScriptPath -Parent
172+
$helpDirectory = Split-Path -Path $OutputHelpPath -Parent
173+
if (-not [string]::IsNullOrWhiteSpace($scriptDirectory)) {
174+
New-Item -Path $scriptDirectory -ItemType Directory -Force | Out-Null
175+
}
176+
if (-not [string]::IsNullOrWhiteSpace($helpDirectory)) {
177+
New-Item -Path $helpDirectory -ItemType Directory -Force | Out-Null
178+
}
179+
180+
Set-Content -Path $OutputScriptPath -Value ($bundleContent -join [Environment]::NewLine) -Encoding utf8NoBOM
181+
Copy-Item -Path (Join-Path $SourceRoot 'docs/help.md') -Destination $OutputHelpPath -Force
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Set-StrictMode -Version Latest
2+
3+
Describe 'Build-PostgresToolkit.ps1' {
4+
It '生成单文件脚本和帮助文档,并且脚本可直接执行 help' {
5+
$outputScript = Join-Path $TestDrive 'Postgres-Toolkit.ps1'
6+
$outputHelp = Join-Path $TestDrive 'Postgres-Toolkit.Help.md'
7+
$sourceRoot = Join-Path $PSScriptRoot '..' 'scripts' 'pwsh' 'devops' 'postgresql'
8+
$builderPath = Join-Path $sourceRoot 'build' 'Build-PostgresToolkit.ps1'
9+
10+
& $builderPath -SourceRoot $sourceRoot -OutputScriptPath $outputScript -OutputHelpPath $outputHelp
11+
12+
(Test-Path $outputScript) | Should -BeTrue
13+
(Test-Path $outputHelp) | Should -BeTrue
14+
(Get-Content -Path $outputScript -Raw) | Should -Match 'Invoke-PostgresToolkitCommand'
15+
(Get-Content -Path $outputHelp -Raw) | Should -Match 'import-csv'
16+
17+
$helpOutput = @(& pwsh -NoProfile -File $outputScript help)
18+
$LASTEXITCODE | Should -Be 0
19+
($helpOutput -join [Environment]::NewLine) | Should -Match 'install-tools'
20+
}
21+
}

0 commit comments

Comments
 (0)