Files
dingMCP/distribution/bootstrap-windows.template.ps1
T
gitea-admin dd189c2acb
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
feat: bootstrap portable Node runtimes
2026-08-18 13:53:54 +00:00

112 lines
5.8 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
$dingSourceBases = @({{NODE_SOURCE_BASES_POWERSHELL}})
$dingInstallerUrl = "{{INSTALLER_URL}}"
$dingInstallerSha256 = "{{INSTALLER_SHA256}}"
$dingPublicKeyUrl = "{{PUBLIC_KEY_URL}}"
$dingPublicKeySha256 = "{{PUBLIC_KEY_SHA256}}"
$dingManifestUrl = "{{MANIFEST_URL}}"
function Get-DingSha256([string] $dingPath) {
return (Get-FileHash -Algorithm SHA256 -LiteralPath $dingPath).Hash.ToLowerInvariant()
}
function Save-DingDownload([string[]] $dingUrls, [string] $dingTarget, [string] $dingExpectedSha256) {
$dingLastError = $null
foreach ($dingUrl in $dingUrls) {
try {
if (Test-Path -LiteralPath $dingTarget) { Remove-Item -LiteralPath $dingTarget -Force }
Invoke-WebRequest -UseBasicParsing -Uri $dingUrl -OutFile $dingTarget -TimeoutSec 300
} catch {
$dingLastError = $_.Exception.Message
$dingStatusCode = $null
if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
try { $dingStatusCode = [int]$_.Exception.Response.StatusCode } catch { $dingStatusCode = $null }
}
if ($null -eq $dingStatusCode -or $dingStatusCode -eq 404) { continue }
throw "下载失败且不允许换源(HTTP $dingStatusCode):$dingUrl;$dingLastError"
}
$dingActualSha256 = Get-DingSha256 $dingTarget
if ($dingActualSha256 -ne $dingExpectedSha256) {
throw "下载文件 SHA-256 不匹配,停止安装:$dingUrl"
}
return
}
throw "所有下载源均不可用:$dingLastError"
}
function Test-DingNode([string] $dingNodePath, [bool] $dingRequireAdjacentNpm) {
if (-not $dingNodePath -or -not (Test-Path -LiteralPath $dingNodePath -PathType Leaf)) { return $false }
try {
& $dingNodePath -e 'const [a,b]=process.versions.node.split(".").map(Number);process.exit(a>22||(a===22&&b>=13)?0:1)'
if ($LASTEXITCODE -ne 0) { return $false }
if ($dingRequireAdjacentNpm) {
$dingNpmCli = Join-Path (Split-Path -Parent $dingNodePath) "node_modules\npm\bin\npm-cli.js"
return Test-Path -LiteralPath $dingNpmCli -PathType Leaf
}
return $null -ne (Get-Command npm -ErrorAction SilentlyContinue)
} catch { return $false }
}
$dingArchitecture = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant()
switch ($dingArchitecture) {
"x64" { $dingNodeFile = "{{NODE_WIN32_X64_FILE}}"; $dingNodeSha256 = "{{NODE_WIN32_X64_SHA256}}" }
"arm64" { $dingNodeFile = "{{NODE_WIN32_ARM64_FILE}}"; $dingNodeSha256 = "{{NODE_WIN32_ARM64_SHA256}}" }
default { throw "不支持的 Windows CPU 架构:$dingArchitecture" }
}
$dingSystemNode = Get-Command node -ErrorAction SilentlyContinue
$dingNodePath = if ($dingSystemNode) { $dingSystemNode.Source } else { $null }
if (-not (Test-DingNode $dingNodePath $false)) {
if (-not $env:LOCALAPPDATA -and -not $env:DINGTALK_APPROVAL_CLIENT_HOME) {
throw "无法确定当前用户数据目录:LOCALAPPDATA 为空"
}
$dingClientRoot = if ($env:DINGTALK_APPROVAL_CLIENT_HOME) {
[IO.Path]::GetFullPath($env:DINGTALK_APPROVAL_CLIENT_HOME)
} else {
Join-Path $env:LOCALAPPDATA "DingTalkApproval"
}
$dingRuntimeParent = Join-Path $dingClientRoot "node"
$dingRuntimeName = [IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetFileNameWithoutExtension($dingNodeFile))
$dingRuntimeDir = Join-Path $dingRuntimeParent $dingRuntimeName
$dingNodePath = Join-Path $dingRuntimeDir "node.exe"
if (-not (Test-DingNode $dingNodePath $true)) {
New-Item -ItemType Directory -Path $dingRuntimeParent -Force | Out-Null
$dingRuntimeTemp = Join-Path ([IO.Path]::GetTempPath()) ("dingmcp-node-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingRuntimeTemp -Force | Out-Null
try {
$dingRuntimeArchive = Join-Path $dingRuntimeTemp $dingNodeFile
$dingRuntimeUrls = @($dingSourceBases | ForEach-Object { $_ + $dingNodeFile })
Save-DingDownload $dingRuntimeUrls $dingRuntimeArchive $dingNodeSha256
$dingExtractRoot = Join-Path $dingRuntimeTemp "extract"
Expand-Archive -LiteralPath $dingRuntimeArchive -DestinationPath $dingExtractRoot -Force
$dingExtractedDir = Join-Path $dingExtractRoot $dingRuntimeName
$dingExtractedNode = Join-Path $dingExtractedDir "node.exe"
if (-not (Test-DingNode $dingExtractedNode $true)) { throw "便携 Node 归档缺少可用的 node.exe 或 npm-cli.js" }
if (Test-Path -LiteralPath $dingRuntimeDir) { Remove-Item -LiteralPath $dingRuntimeDir -Recurse -Force }
Move-Item -LiteralPath $dingExtractedDir -Destination $dingRuntimeDir
} finally {
if (Test-Path -LiteralPath $dingRuntimeTemp) { Remove-Item -LiteralPath $dingRuntimeTemp -Recurse -Force }
}
}
}
$dingInstallTemp = Join-Path ([IO.Path]::GetTempPath()) ("dingmcp-install-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingInstallTemp -Force | Out-Null
try {
$dingInstaller = Join-Path $dingInstallTemp "installer.mjs"
$dingPublicKey = Join-Path $dingInstallTemp "release-signing-public.pem"
Save-DingDownload @($dingInstallerUrl) $dingInstaller $dingInstallerSha256
Save-DingDownload @($dingPublicKeyUrl) $dingPublicKey $dingPublicKeySha256
$dingInstallOutput = & $dingNodePath $dingInstaller install --manifest-url $dingManifestUrl --public-key $dingPublicKey --json
$dingInstallExit = $LASTEXITCODE
if ($dingInstallExit -ne 0) { throw "钉钉审批安装器执行失败:$dingInstallOutput" }
$dingResult = $dingInstallOutput | ConvertFrom-Json
if ($dingResult.ok -ne $true) { throw "钉钉审批安装失败:$($dingResult.error)" }
$dingResult | ConvertTo-Json -Depth 20 -Compress
} finally {
if (Test-Path -LiteralPath $dingInstallTemp) { Remove-Item -LiteralPath $dingInstallTemp -Recurse -Force }
}