Build-ServerBundle.ps1
Rama main · réplica de lectura del repositorio original.
param(
[string]$OutputDirectory = $(if ([string]::IsNullOrWhiteSpace($env:CLIPMAN_SERVER_PACKAGE_DIR)) { Join-Path ([IO.Path]::GetTempPath()) 'Clipman-server-package' } else { $env:CLIPMAN_SERVER_PACKAGE_DIR }),
[string]$MacHost = $(if ([string]::IsNullOrWhiteSpace($env:CLIPMAN_MAC_HOST)) { 'mac' } else { $env:CLIPMAN_MAC_HOST }),
[string]$MacRepo = $(if ([string]::IsNullOrWhiteSpace($env:CLIPMAN_MAC_REPO)) { '$HOME/clipman' } else { $env:CLIPMAN_MAC_REPO }),
[string]$GoPath = $(if ([string]::IsNullOrWhiteSpace($env:CLIPMAN_GO)) { 'go' } else { $env:CLIPMAN_GO })
)
$ErrorActionPreference = 'Stop'
$OutputDirectory = [IO.Path]::GetFullPath($OutputDirectory)
$repoFullPath = [IO.Path]::GetFullPath($PSScriptRoot).TrimEnd('\')
if ($OutputDirectory.TrimEnd('\').StartsWith($repoFullPath + '\', [StringComparison]::OrdinalIgnoreCase)) {
throw "OutputDirectory must be outside the source repository: $OutputDirectory"
}
function Get-ClipmanVersion {
$versionFile = Join-Path $PSScriptRoot 'ClipmanServer\version.txt'
$version = (Get-Content -LiteralPath $versionFile -Raw).Trim()
if ($version -notmatch '^\d+\.\d+\.\d+$') {
throw "Clipman Server version is invalid in $versionFile"
}
return $version
}
function Build-WindowsServerWrapper([string]$outputPath, [string]$serverScript) {
$csc = Join-Path $env:WINDIR 'Microsoft.NET\Framework64\v4.0.30319\csc.exe'
if (-not (Test-Path -LiteralPath $csc)) {
throw "Could not find the .NET Framework C# compiler at $csc"
}
$version = Get-ClipmanVersion
$assemblyVersion = if ($version -match '^\d+\.\d+\.\d+$') { "$version.0" } else { $version }
$generatedDirectory = Split-Path -Parent $outputPath
$generatedAssemblyInfo = Join-Path $generatedDirectory 'GeneratedAssemblyInfo.cs'
New-Item -ItemType Directory -Force -Path $generatedDirectory | Out-Null
@(
'using System.Reflection;',
'using System.Runtime.InteropServices;',
'',
'[assembly: AssemblyTitle("Clipman Server")]',
'[assembly: AssemblyDescription("Background server wrapper for Clipman")]',
'[assembly: AssemblyCompany("Andre Louis")]',
'[assembly: AssemblyProduct("Clipman Server")]',
'[assembly: AssemblyCopyright("Copyright (c) Andre Louis")]',
'[assembly: ComVisible(false)]',
"[assembly: AssemblyVersion(`"$assemblyVersion`")]",
"[assembly: AssemblyFileVersion(`"$assemblyVersion`")]",
"[assembly: AssemblyInformationalVersion(`"$version`")]"
) -join [Environment]::NewLine | Set-Content -LiteralPath $generatedAssemblyInfo -Encoding UTF8
$sources = @(Get-ChildItem -LiteralPath (Join-Path $PSScriptRoot 'ClipmanServerWindows') -Filter '*.cs' | Sort-Object Name | ForEach-Object { $_.FullName })
$sources += $generatedAssemblyInfo
if ($sources.Count -eq 0) {
throw 'Windows Clipman Server wrapper source is missing.'
}
$references = @(
'System.dll',
'System.Core.dll',
'System.Drawing.dll',
'System.IO.Compression.FileSystem.dll',
'System.Windows.Forms.dll',
'System.Web.Extensions.dll'
) -join ','
if (-not (Test-Path -LiteralPath $serverScript)) {
throw "Shared Python server script is missing: $serverScript"
}
& $csc /nologo /target:winexe /platform:x64 /out:$outputPath /reference:$references "/resource:$serverScript,ClipmanServerWrapper.clipman_server.py" $sources
if ($LASTEXITCODE -ne 0) {
throw "Windows Clipman Server wrapper build failed with exit code $LASTEXITCODE"
}
# Use a child process so loading the EXE for verification does not lock build scratch.
$verificationScript = Join-Path $generatedDirectory 'VerifyServerUpdater.ps1'
@'
param([string]$AssemblyPath, [string]$Version)
$ErrorActionPreference = 'Stop'
$assembly = [Reflection.Assembly]::LoadFile($AssemblyPath)
$updateType = $assembly.GetType('ClipmanServerWrapper.ServerUpdateService', $true)
$versionText = $updateType.GetMethod('VersionText', [Reflection.BindingFlags]'NonPublic,Static')
if ($null -eq $versionText) {
throw 'Windows Clipman Server updater tag validator was not found in the built executable.'
}
if ([string]$versionText.Invoke($null, @("v$Version")) -ne '') {
throw 'Windows Clipman Server updater incorrectly accepted a Clipman client release tag.'
}
if ([string]$versionText.Invoke($null, @("server-v$Version")) -ne $Version) {
throw 'Windows Clipman Server updater rejected its versioned server release tag.'
}
'@ | Set-Content -LiteralPath $verificationScript -Encoding UTF8
& powershell -NoProfile -ExecutionPolicy Bypass -File $verificationScript -AssemblyPath $outputPath -Version $version
if ($LASTEXITCODE -ne 0) {
throw "Windows Clipman Server updater verification failed with exit code $LASTEXITCODE"
}
}
$version = Get-ClipmanVersion
$zipPath = Join-Path $OutputDirectory "ClipmanServer-$version.zip"
$localBuildDirectory = Join-Path ([IO.Path]::GetTempPath()) ('Clipman-server-build-' + [guid]::NewGuid().ToString('N'))
$windowsWrapperDist = Join-Path $localBuildDirectory 'Clipman Server.exe'
$remoteHome = (& ssh $MacHost 'printf %s "$HOME"').Trim()
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($remoteHome)) {
throw "Could not determine the home folder on $MacHost."
}
$remoteRunDirectory = "$remoteHome/Projects/Codex/Temp/clipman/server-bundle-$version-$([guid]::NewGuid().ToString('N'))"
$remoteTempWindowsExe = "$remoteRunDirectory/windows-wrapper.exe"
$remoteMacDist = "$remoteRunDirectory/mac-dist"
$remoteCombinedDist = "$remoteRunDirectory/combined-dist"
$remoteTempZip = "$remoteRunDirectory/ClipmanServer-$version.zip"
$remoteWebAssets = "$remoteRunDirectory/web"
$remoteServerScript = "$remoteRunDirectory/clipman_server.py"
New-Item -ItemType Directory -Force -Path $OutputDirectory | Out-Null
try {
New-Item -ItemType Directory -Force -Path $localBuildDirectory | Out-Null
$localWebAssets = Join-Path $localBuildDirectory 'web'
$localServerScript = Join-Path $localBuildDirectory 'clipman_server.py'
& python (Join-Path $PSScriptRoot 'ClipmanServer\build_web.py') --output $localWebAssets --go $GoPath --server-output $localServerScript
if ($LASTEXITCODE -ne 0) { throw 'Clipman browser asset build failed.' }
Build-WindowsServerWrapper $windowsWrapperDist $localServerScript
Remove-Item -LiteralPath $zipPath -Force -ErrorAction SilentlyContinue
& ssh $MacHost "/bin/rm -rf '$remoteRunDirectory'; /bin/mkdir -p '$remoteMacDist' '$remoteCombinedDist'"
if ($LASTEXITCODE -ne 0) {
throw "Could not prepare Mac server bundle folders on $MacHost."
}
& scp $windowsWrapperDist "${MacHost}:$remoteTempWindowsExe"
if ($LASTEXITCODE -ne 0) {
throw "Could not copy Windows server wrapper to $MacHost."
}
& scp -r $localWebAssets "${MacHost}:$remoteWebAssets"
if ($LASTEXITCODE -ne 0) { throw 'Could not copy browser assets to the server package staging folder.' }
& scp $localServerScript "${MacHost}:$remoteServerScript"
if ($LASTEXITCODE -ne 0) { throw 'Could not copy the self-contained server to package staging.' }
& ssh $MacHost "cd `"$MacRepo`" && CLIPMAN_SERVER_SCRIPT='$remoteServerScript' CLIPMAN_WEB_ASSETS='$remoteWebAssets' CLIPMAN_SERVER_MAC_DIST_DIR='$remoteMacDist' zsh ClipmanServerMac/Scripts/package-release.sh && CLIPMAN_SERVER_SCRIPT='$remoteServerScript' CLIPMAN_WEB_ASSETS='$remoteWebAssets' CLIPMAN_SERVER_WINDOWS_EXE='$remoteTempWindowsExe' CLIPMAN_SERVER_MAC_APP='$remoteMacDist/Clipman Server.app' CLIPMAN_SERVER_COMBINED_OUTPUT_DIR='$remoteCombinedDist' zsh ClipmanServerMac/Scripts/package-combined-server.sh && cp '$remoteCombinedDist/ClipmanServer-$version.zip' '$remoteTempZip'"
if ($LASTEXITCODE -ne 0) {
throw "Mac-side Clipman Server bundle build failed on $MacHost."
}
& scp "${MacHost}:$remoteTempZip" $zipPath
if ($LASTEXITCODE -ne 0) {
throw "Could not copy Mac-built server bundle from $MacHost."
}
if (-not (Test-Path -LiteralPath $zipPath)) {
throw "Server bundle ZIP was not created: $zipPath"
}
if (![string]::IsNullOrWhiteSpace($env:CLIPMAN_SERVER_BUILDS)) {
New-Item -ItemType Directory -Force -Path $env:CLIPMAN_SERVER_BUILDS | Out-Null
Copy-Item -LiteralPath $zipPath -Destination (Join-Path $env:CLIPMAN_SERVER_BUILDS (Split-Path -Leaf $zipPath)) -Force
}
Write-Host "Built $zipPath"
}
finally {
for ($attempt = 1; $attempt -le 10 -and (Test-Path -LiteralPath $localBuildDirectory); $attempt++) {
try {
Remove-Item -LiteralPath $localBuildDirectory -Recurse -Force -ErrorAction Stop
}
catch {
if ($attempt -eq 10) {
throw "Could not clean local Clipman Server build scratch: $localBuildDirectory"
}
Start-Sleep -Milliseconds 300
}
}
& ssh $MacHost "/bin/rm -rf '$remoteRunDirectory'" 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not remove one or more remote Clipman Server scratch paths from $MacHost."
}
$LASTEXITCODE = 0
}