<# .SYNOPSIS Publishes the Mbproxy binary in two flavours: self-contained and framework-dependent. .DESCRIPTION Produces two single-file builds for the requested runtime under \publish-out\: self-contained\ ~100 MB — bundles the .NET 10 + ASP.NET Core runtime; no .NET install needed on the target. framework-dependent\ ~1.6 MB — requires the .NET 10 + ASP.NET Core runtime preinstalled on the target. Each folder also receives a current appsettings.json — the platform-appropriate install template (Windows or Linux, selected by -Rid) — so every publish-out flavour is a complete, deployable folder. For a win-* RID the four service batch files (install/remove/start/stop-service.bat) are copied in as well. The runtime is selected with -Rid (default win-x64). The binary is Mbproxy.exe on Windows RIDs and Mbproxy on Linux/macOS RIDs. Both builds use the Release configuration and inherit the publish settings declared in src\Mbproxy\Mbproxy.csproj (PublishSingleFile=true, SelfContained=true, IncludeNativeLibrariesForSelfExtract=true; those settings are gated on an explicit RID, which is supplied here). The framework-dependent build overrides SelfContained=false on the command line. .PARAMETER Rid .NET runtime identifier to publish for. Examples: win-x64, linux-x64. Default: win-x64 .PARAMETER OutputDir Root output directory. Two subfolders are created beneath it. Default: \publish-out .PARAMETER Clean Delete OutputDir before publishing. .EXAMPLE .\publish.ps1 .\publish.ps1 -Rid linux-x64 .\publish.ps1 -Rid win-x64 -Clean #> [CmdletBinding()] param( [string]$Rid = 'win-x64', [string]$OutputDir = (Join-Path (Split-Path -Parent $PSScriptRoot) 'publish-out'), [switch]$Clean ) $ErrorActionPreference = 'Stop' $repoRoot = Split-Path -Parent $PSScriptRoot $csproj = Join-Path $repoRoot 'src\Mbproxy\Mbproxy.csproj' if (-not (Test-Path $csproj)) { throw "Cannot find $csproj" } if ($Clean -and (Test-Path $OutputDir)) { Write-Host "Cleaning $OutputDir" -ForegroundColor Yellow Remove-Item -Recurse -Force $OutputDir } # Binary name: Windows RIDs produce an .exe, every other RID produces an extensionless ELF/Mach-O. $exeName = if ($Rid -like 'win-*') { 'Mbproxy.exe' } else { 'Mbproxy' } $selfContainedOut = Join-Path $OutputDir 'self-contained' $frameworkDependentOut = Join-Path $OutputDir 'framework-dependent' Write-Host "`n=== Publishing self-contained ($Rid, ~100 MB) ===" -ForegroundColor Cyan & dotnet publish $csproj -c Release -r $Rid -o $selfContainedOut --nologo if ($LASTEXITCODE -ne 0) { throw "self-contained publish failed (exit $LASTEXITCODE)" } Write-Host "`n=== Publishing framework-dependent ($Rid, ~1.6 MB) ===" -ForegroundColor Cyan & dotnet publish $csproj -c Release -r $Rid -p:SelfContained=false -p:PublishSingleFile=true -o $frameworkDependentOut --nologo if ($LASTEXITCODE -ne 0) { throw "framework-dependent publish failed (exit $LASTEXITCODE)" } # ── Ship the platform-appropriate config template as appsettings.json ────────── # dotnet publish already copies it via the Mbproxy.csproj link, but that # link uses PreserveNewest — an incremental (non-Clean) run can leave a stale # config behind. Copy it explicitly so every publish-out flavour is guaranteed a # current appsettings.json, and so the config's source is obvious. $configTemplate = if ($Rid -like 'win-*') { Join-Path $repoRoot 'install\mbproxy.config.template.json' } else { Join-Path $repoRoot 'install\mbproxy.linux.config.template.json' } if (-not (Test-Path $configTemplate)) { throw "Cannot find config template: $configTemplate" } Write-Host "`n=== Config (appsettings.json) ===" -ForegroundColor Cyan foreach ($flavour in 'self-contained','framework-dependent') { $dest = Join-Path $OutputDir "$flavour\appsettings.json" Copy-Item -LiteralPath $configTemplate -Destination $dest -Force Write-Host (" {0,-22} <- {1}" -f $flavour, $configTemplate) } # ── Ship the Windows service-management batch files (win RIDs only) ───────────── # install-service / remove-service / start-service / stop-service all act on the # Mbproxy.exe in their own folder, so the published folder is self-managing. if ($Rid -like 'win-*') { $serviceScripts = 'install-service.bat','remove-service.bat','start-service.bat','stop-service.bat' Write-Host "`n=== Service scripts ===" -ForegroundColor Cyan foreach ($flavour in 'self-contained','framework-dependent') { foreach ($script in $serviceScripts) { $src = Join-Path $repoRoot "install\$script" if (-not (Test-Path $src)) { throw "Cannot find service script: $src" } Copy-Item -LiteralPath $src -Destination (Join-Path $OutputDir "$flavour\$script") -Force } Write-Host (" {0,-22} <- install\*-service.bat" -f $flavour) } } function Format-Size { param([long]$Bytes) if ($Bytes -ge 1MB) { '{0:N1} MB' -f ($Bytes / 1MB) } else { '{0:N1} KB' -f ($Bytes / 1KB) } } Write-Host "`n=== Result ($Rid) ===" -ForegroundColor Green foreach ($flavour in 'self-contained','framework-dependent') { $bin = Join-Path $OutputDir "$flavour\$exeName" if (Test-Path $bin) { $size = (Get-Item $bin).Length Write-Host (" {0,-22} {1,10} {2}" -f $flavour, (Format-Size $size), $bin) } else { # A missing expected binary means the publish silently produced nothing usable — # fail the script rather than emit a warning a CI job would scroll past. throw "Expected published binary not found: $bin" } } Write-Host ""