|
@@ -0,0 +1,149 @@
|
|
|
|
|
+# Regenerate index.json for THIS gallery repository (PLT\Gallery).
|
|
|
|
|
+#
|
|
|
|
|
+# 为什么自带一份:
|
|
|
|
|
+# 主仓库 build\regen-gallery-index.ps1 写死了 "<脚本父目录的父目录>\gallery",
|
|
|
|
|
+# 只能服务 TeamAAS-2.1\gallery,无法指向这里。
|
|
|
|
|
+#
|
|
|
|
|
+# 格式:对齐远端 Gallery 仓库的 GalleryPackage schema(含多版本 versions[]),
|
|
|
|
|
+# 以保持内容为准:字段全部来自包内 manifest.json,不再手写,避免 index 与包不一致。
|
|
|
|
|
+# 版本历史会继承旧 index 中同 id 的其它版本条目(releasedAt / status / notes 不丢)。
|
|
|
|
|
+#
|
|
|
|
|
+# 用法(改了 packages\ 下任何 zip 之后执行):
|
|
|
|
|
+# powershell -NoProfile -ExecutionPolicy Bypass -File .\regen-index.ps1
|
|
|
|
|
+#
|
|
|
|
|
+# 布局约定:packages\<host>\<id>\<id>-<version>.zip(zip 根目录必须含 manifest.json)
|
|
|
|
|
+$ErrorActionPreference = 'Stop'
|
|
|
|
|
+
|
|
|
|
|
+$galleryDir = $PSScriptRoot
|
|
|
|
|
+$packagesDir = Join-Path $galleryDir 'packages'
|
|
|
|
|
+$indexPath = Join-Path $galleryDir 'index.json'
|
|
|
|
|
+
|
|
|
|
|
+if (-not (Test-Path $packagesDir)) {
|
|
|
|
|
+ throw "packages directory not found: $packagesDir"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
|
|
|
+
|
|
|
|
|
+# 旧 index:仅用于继承版本历史
|
|
|
|
|
+$history = @{}
|
|
|
|
|
+if (Test-Path $indexPath) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $old = (Get-Content $indexPath -Raw) | ConvertFrom-Json
|
|
|
|
|
+ foreach ($p in $old.packages) {
|
|
|
|
|
+ foreach ($v in $p.versions) {
|
|
|
|
|
+ $history["$($p.id)@$($v.version)"] = @{
|
|
|
|
|
+ releasedAt = $v.releasedAt
|
|
|
|
|
+ status = if ($v.status) { $v.status } else { 'stable' }
|
|
|
|
|
+ notes = $v.notes
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ Write-Warning "旧 index.json 解析失败,版本历史不继承:$($_.Exception.Message)"
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+$today = (Get-Date).ToString('yyyy-MM-dd')
|
|
|
|
|
+$sha = [System.Security.Cryptography.SHA256]::Create()
|
|
|
|
|
+$entries = New-Object System.Collections.Generic.List[object]
|
|
|
|
|
+$seen = @{}
|
|
|
|
|
+
|
|
|
|
|
+foreach ($zipFile in (Get-ChildItem -Path $packagesDir -Recurse -Filter '*.zip' | Sort-Object FullName)) {
|
|
|
|
|
+ $zip = [System.IO.Compression.ZipFile]::OpenRead($zipFile.FullName)
|
|
|
|
|
+ try {
|
|
|
|
|
+ $manifestEntry = $zip.Entries |
|
|
|
|
|
+ Where-Object { $_.FullName -replace '\\', '/' -eq 'manifest.json' } |
|
|
|
|
|
+ Select-Object -First 1
|
|
|
|
|
+ if (-not $manifestEntry) {
|
|
|
|
|
+ Write-Warning "skip (no manifest.json at root): $($zipFile.Name)"
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $reader = New-Object System.IO.StreamReader($manifestEntry.Open(), [System.Text.Encoding]::UTF8)
|
|
|
|
|
+ try { $manifest = $reader.ReadToEnd() } finally { $reader.Dispose() }
|
|
|
|
|
+
|
|
|
|
|
+ $j = $manifest | ConvertFrom-Json
|
|
|
|
|
+ if (-not $j.id -or -not $j.version) {
|
|
|
|
|
+ Write-Warning "skip (manifest missing id/version): $($zipFile.Name)"
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $key = "$($j.id)@$($j.version)"
|
|
|
|
|
+ if ($seen.ContainsKey($key)) {
|
|
|
|
|
+ Write-Warning "skip duplicate: $key ($($zipFile.Name))"
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ $seen[$key] = $true
|
|
|
|
|
+
|
|
|
|
|
+ $fs = [System.IO.File]::OpenRead($zipFile.FullName)
|
|
|
|
|
+ try {
|
|
|
|
|
+ $hashBytes = $sha.ComputeHash($fs)
|
|
|
|
|
+ $size = $fs.Length
|
|
|
|
|
+ } finally { $fs.Dispose() }
|
|
|
|
|
+ $hashHex = ([System.BitConverter]::ToString($hashBytes) -replace '-', '').ToLowerInvariant()
|
|
|
|
|
+
|
|
|
|
|
+ # downloadUrl 存相对路径:GalleryClient 会按实际源根拼接,源换域名也不用改包。
|
|
|
|
|
+ $relativeUrl = $zipFile.FullName.Substring($galleryDir.Length + 1) -replace '\\', '/'
|
|
|
|
|
+
|
|
|
|
|
+ $hostName = if ($j.host) { [string]$j.host } else { 'platform' }
|
|
|
|
|
+ $kind = if ($j.kind) { [string]$j.kind } else { 'extension' }
|
|
|
|
|
+ $requires = $null
|
|
|
|
|
+ if ($j.requiresHost) {
|
|
|
|
|
+ $requires = if ($j.requiresHost.minVersion) {
|
|
|
|
|
+ "$($j.requiresHost.id)>=$($j.requiresHost.minVersion)"
|
|
|
|
|
+ } else { [string]$j.requiresHost.id }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $prev = $history[$key]
|
|
|
|
|
+ $versionEntry = [ordered]@{
|
|
|
|
|
+ version = [string]$j.version
|
|
|
|
|
+ downloadUrl = $relativeUrl
|
|
|
|
|
+ sha256 = $hashHex
|
|
|
|
|
+ size = $size
|
|
|
|
|
+ releasedAt = if ($prev) { $prev.releasedAt } else { $today }
|
|
|
|
|
+ status = if ($prev) { $prev.status } else { 'stable' }
|
|
|
|
|
+ notes = if ($prev -and $prev.notes) { $prev.notes } else { '首次收录' }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $entry = [ordered]@{
|
|
|
|
|
+ id = [string]$j.id
|
|
|
|
|
+ name = [string]$j.name
|
|
|
|
|
+ version = [string]$j.version
|
|
|
|
|
+ publisher = if ($j.publisher) { [string]$j.publisher } else { $null }
|
|
|
|
|
+ kind = $kind
|
|
|
|
|
+ host = $hostName
|
|
|
|
|
+ description = if ($j.description) { [string]$j.description } else { $null }
|
|
|
|
|
+ notes = if ($j.notes) { [string]$j.notes } else { $null }
|
|
|
|
|
+ downloadUrl = $relativeUrl
|
|
|
|
|
+ sha256 = $hashHex
|
|
|
|
|
+ size = $size
|
|
|
|
|
+ references = @($j.references)
|
|
|
|
|
+ targetFramework = if ($j.targetFramework) { [string]$j.targetFramework } else { $null }
|
|
|
|
|
+ requiresHost = $requires
|
|
|
|
|
+ arch = @($j.arch)
|
|
|
|
|
+ dependencies = @($j.dependencies)
|
|
|
|
|
+ versions = @($versionEntry)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $entries.Add([PSCustomObject]$entry)
|
|
|
|
|
+ Write-Host ("indexed {0} {1} [{2}] {3} bytes {4}" -f $j.id, $j.version, $hostName, $size, $hashHex)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ $zip.Dispose()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+$sha.Dispose()
|
|
|
|
|
+
|
|
|
|
|
+# Stable order: host (platform first), then id.
|
|
|
|
|
+$sorted = @($entries | Sort-Object @{ Expression = { $_.host } }, @{ Expression = { $_.id } })
|
|
|
|
|
+
|
|
|
|
|
+$index = [ordered]@{
|
|
|
|
|
+ schemaVersion = 1
|
|
|
|
|
+ generatedAt = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
|
|
|
|
|
+ packages = $sorted
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+$json = $index | ConvertTo-Json -Depth 12
|
|
|
|
|
+# ConvertTo-Json 会把 ">" 转义成 \u003e(合法 JSON 但可读性差,且与线上文件不一致),还原。
|
|
|
|
|
+$json = $json -replace '\\u003e', '>' -replace '\\u003c', '<' -replace '\\u0026', '&'
|
|
|
|
|
+[System.IO.File]::WriteAllText($indexPath, $json, (New-Object System.Text.UTF8Encoding($false)))
|
|
|
|
|
+Write-Host "REGEN DONE: $($sorted.Count) package(s) -> $indexPath"
|