|
2 | 2 |
|
3 | 3 | <# |
4 | 4 | .SYNOPSIS |
5 | | - 管理bin目录脚本映射的自动化工具 |
| 5 | + 管理 `bin` 目录脚本 shim 的自动化工具。 |
6 | 6 |
|
7 | 7 | .DESCRIPTION |
8 | | - 该脚本用于自动生成bin目录下的脚本映射,将项目中的PowerShell脚本 |
9 | | - 复制到bin目录(作为Shim),保持原始文件名。 |
10 | | - |
11 | | - 功能特点: |
12 | | - 1. 性能优化:自动忽略 node_modules, .git 等目录 |
13 | | - 2. 灵活配置:支持 glob 模式过滤 |
14 | | - 3. 相对路径:保持脚本内部 $PSScriptRoot 正确性 |
15 | | - 4. 冲突检测:支持自动重命名解决冲突 |
| 8 | + 该脚本用于扫描项目中的 PowerShell 与 Python 脚本,并在 `bin` 目录生成可直接执行的 shim。 |
| 9 | +
|
| 10 | + 主要能力: |
| 11 | + 1. 自动扫描脚本,并跳过 `.git`、`node_modules`、`bin` 等无关目录。 |
| 12 | + 2. 支持使用 `Patterns` 按相对路径筛选要生成 shim 的脚本。 |
| 13 | + 3. 支持多种重名处理策略,避免生成到 `bin` 时发生文件名冲突。 |
| 14 | + 4. 生成的 shim 保留相对路径语义,确保源脚本中的 `$PSScriptRoot` 或调用路径正常工作。 |
| 15 | + 5. 在 `sync` 时自动清理失效的旧 shim:如果源脚本已不存在,或同一源脚本因改名生成了新的目标文件名,会移除旧的自动生成 shim。 |
16 | 16 |
|
17 | 17 | .PARAMETER Action |
18 | | - 要执行的操作:'sync'(同步脚本到bin目录)或'clean'(清理bin目录) |
| 18 | + 要执行的操作: |
| 19 | + - `sync`:扫描项目脚本并同步生成 `bin` 下的 shim。 |
| 20 | + - `clean`:清理 `bin` 目录下的 `.ps1` 文件。 |
19 | 21 |
|
20 | 22 | .PARAMETER Force |
21 | | - 强制覆盖bin目录中已存在的文件 |
| 23 | + 强制覆盖 `bin` 目录中已存在的目标文件;未指定时,已存在文件会被跳过。 |
22 | 24 |
|
23 | 25 | .PARAMETER Patterns |
24 | | - 可选的 Glob 模式列表,用于筛选要安装的脚本。 |
25 | | - 例如: 'scripts/pwsh/*.ps1', 'ai/**/*.ps1' |
26 | | - 如果未指定,默认扫描除忽略目录外的所有 .ps1 文件。 |
| 26 | + 可选的 Glob 模式列表,用于筛选需要生成 shim 的脚本。 |
| 27 | + 例如:`scripts/pwsh/*.ps1`、`ai/**/*.ps1` |
| 28 | +
|
| 29 | + 如果未指定,则使用脚本内置的默认模式。 |
27 | 30 |
|
28 | 31 | .PARAMETER DuplicateStrategy |
29 | 32 | 重名处理策略: |
30 | | - - PrefixParent (默认): 使用父目录名作为前缀 (e.g. parent_script.ps1) |
31 | | - - Overwrite: 覆盖同名文件 (旧行为) |
32 | | - - Skip: 跳过重名文件 |
| 33 | + - `PrefixParent`(默认):使用父目录或更深层路径作为前缀生成唯一文件名,例如 `devops_Clean-DockerImages.ps1` |
| 34 | + - `Overwrite`:后扫描到的脚本覆盖同名目标文件 |
| 35 | + - `Skip`:遇到重名时仅保留第一个脚本 |
33 | 36 |
|
34 | 37 | .EXAMPLE |
35 | 38 | .\Manage-BinScripts.ps1 -Action sync |
36 | | - 同步所有查找的到的 PowerShell 脚本到 bin 目录,自动处理重名 |
| 39 | + 使用默认模式同步生成 `bin` shim,并自动清理失效的旧 shim。 |
| 40 | +
|
| 41 | +.EXAMPLE |
| 42 | + .\Manage-BinScripts.ps1 -Action sync -Patterns 'scripts/pwsh/devops/*.ps1' -Force |
| 43 | + 仅同步 `scripts/pwsh/devops` 下的脚本,并强制覆盖已存在的目标文件。 |
37 | 44 |
|
38 | 45 | .EXAMPLE |
39 | 46 | .\Manage-BinScripts.ps1 -Action sync -DuplicateStrategy Overwrite |
40 | | - 同步脚本,遇到重名直接覆盖(最后扫描到的生效) |
| 47 | + 同步脚本,并在目标文件重名时使用覆盖策略。 |
41 | 48 | #> |
42 | 49 |
|
43 | 50 | [CmdletBinding(SupportsShouldProcess = $true)] |
@@ -194,6 +201,91 @@ function Resolve-ScriptTargetNames { |
194 | 201 | return $mapping |
195 | 202 | } |
196 | 203 |
|
| 204 | +function Get-ManagedBinShimMetadata { |
| 205 | + param([string]$Path) |
| 206 | + |
| 207 | + if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { |
| 208 | + return $null |
| 209 | + } |
| 210 | + |
| 211 | + $headerLines = Get-Content -LiteralPath $Path -TotalCount 8 -ErrorAction SilentlyContinue |
| 212 | + if (-not $headerLines) { |
| 213 | + return $null |
| 214 | + } |
| 215 | + |
| 216 | + $isManagedShim = $headerLines | Where-Object { $_ -eq '# Auto-generated shim by Manage-BinScripts.ps1' } | Select-Object -First 1 |
| 217 | + if (-not $isManagedShim) { |
| 218 | + return $null |
| 219 | + } |
| 220 | + |
| 221 | + $sourceMatch = $headerLines | ForEach-Object { |
| 222 | + if ($_ -match '^# Source:\s*(.+)$') { |
| 223 | + $Matches[1].Trim() |
| 224 | + } |
| 225 | + } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -First 1 |
| 226 | + |
| 227 | + if (-not $sourceMatch) { |
| 228 | + return $null |
| 229 | + } |
| 230 | + |
| 231 | + $item = Get-Item -LiteralPath $Path -ErrorAction SilentlyContinue |
| 232 | + if (-not $item) { |
| 233 | + return $null |
| 234 | + } |
| 235 | + |
| 236 | + return [PSCustomObject]@{ |
| 237 | + Name = $item.Name |
| 238 | + FullName = $item.FullName |
| 239 | + SourcePath = $sourceMatch |
| 240 | + } |
| 241 | +} |
| 242 | + |
| 243 | +function Remove-StaleManagedBinScripts { |
| 244 | + [CmdletBinding(SupportsShouldProcess = $true)] |
| 245 | + param([hashtable]$CurrentMapping) |
| 246 | + |
| 247 | + if (-not (Test-Path $BinDir)) { |
| 248 | + return 0 |
| 249 | + } |
| 250 | + |
| 251 | + $removedCount = 0 |
| 252 | + $binScripts = Get-ChildItem -Path $BinDir -Filter '*.ps1' -File -ErrorAction SilentlyContinue |
| 253 | + |
| 254 | + foreach ($binScript in $binScripts) { |
| 255 | + $metadata = Get-ManagedBinShimMetadata -Path $binScript.FullName |
| 256 | + if ($null -eq $metadata) { |
| 257 | + continue |
| 258 | + } |
| 259 | + |
| 260 | + $shouldRemove = $false |
| 261 | + $removeReason = $null |
| 262 | + |
| 263 | + if ($CurrentMapping.ContainsKey($metadata.SourcePath)) { |
| 264 | + $expectedName = $CurrentMapping[$metadata.SourcePath] |
| 265 | + if ($metadata.Name -cne $expectedName) { |
| 266 | + $shouldRemove = $true |
| 267 | + $removeReason = "renamed to $expectedName" |
| 268 | + } |
| 269 | + } |
| 270 | + elseif (-not (Test-Path -LiteralPath $metadata.SourcePath -PathType Leaf)) { |
| 271 | + $shouldRemove = $true |
| 272 | + $removeReason = 'source script no longer exists' |
| 273 | + } |
| 274 | + |
| 275 | + if (-not $shouldRemove) { |
| 276 | + continue |
| 277 | + } |
| 278 | + |
| 279 | + if ($PSCmdlet.ShouldProcess($metadata.Name, "Remove stale shim ($removeReason)")) { |
| 280 | + Remove-Item -LiteralPath $metadata.FullName -Force |
| 281 | + Write-Host "清理旧 Shim: $($metadata.Name)" -ForegroundColor DarkYellow |
| 282 | + $removedCount++ |
| 283 | + } |
| 284 | + } |
| 285 | + |
| 286 | + return $removedCount |
| 287 | +} |
| 288 | + |
197 | 289 | function Sync-BinScripts { |
198 | 290 | [CmdletBinding(SupportsShouldProcess = $true)] |
199 | 291 | param([switch]$Force) |
@@ -397,10 +489,13 @@ function Sync-BinScripts { |
397 | 489 | } |
398 | 490 | } |
399 | 491 | } |
| 492 | + |
| 493 | + $removedCount = Remove-StaleManagedBinScripts -CurrentMapping $scriptMapping |
400 | 494 |
|
401 | 495 | Write-Host "`n处理完成!" -ForegroundColor Green |
402 | 496 | Write-Host " 新增/更新: $syncedCount" -ForegroundColor White |
403 | 497 | Write-Host " 跳过(已存在): $skippedCount" -ForegroundColor White |
| 498 | + Write-Host " 清理旧文件: $removedCount" -ForegroundColor White |
404 | 499 | } |
405 | 500 |
|
406 | 501 | function Clean-BinScripts { |
@@ -435,3 +530,4 @@ switch ($Action) { |
435 | 530 | Clean-BinScripts |
436 | 531 | } |
437 | 532 | } |
| 533 | + |
0 commit comments