Lumi/companion/scripts/publish-companion.ps1
2026-07-25 00:04:03 +02:00

143 lines
7.5 KiB
PowerShell

param(
[string]$Version = "0.2.2",
[string]$BridgeVersion = "0.2.1",
[string]$ObsVersion = "31.1.1"
)
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
$project = Join-Path $repoRoot "companion\src\Lumi.Companion.App\Lumi.Companion.App.csproj"
$outputRoot = Join-Path $repoRoot "companion\installer\output"
$publishRoot = Join-Path $outputRoot "publish"
$stageRoot = Join-Path $outputRoot "package"
$sourceStageRoot = Join-Path $outputRoot "obs-bridge-source"
$archive = Join-Path $outputRoot "Lumi.Companion-win-x64.zip"
$installer = Join-Path $outputRoot "Lumi.Companion-Setup.exe"
$legalSourceRoot = Join-Path $repoRoot "companion\legal"
$publishLegalRoot = Join-Path $publishRoot "legal"
function Invoke-Native([string]$FilePath, [string[]]$Arguments) {
$argumentLine = ($Arguments | ForEach-Object { '"' + ([string]$_).Replace('"', '\"') + '"' }) -join ' '
$process = Start-Process -FilePath $FilePath -ArgumentList $argumentLine -NoNewWindow -Wait -PassThru
return $process.ExitCode
}
function Compress-ArchiveWithRetry {
param(
[Parameter(Mandatory = $true)][string]$Path,
[Parameter(Mandatory = $true)][string]$DestinationPath,
[int]$Attempts = 8
)
for ($attempt = 1; $attempt -le $Attempts; $attempt++) {
try {
Remove-Item $DestinationPath -Force -ErrorAction SilentlyContinue
Compress-Archive -Path $Path -DestinationPath $DestinationPath -CompressionLevel Optimal -ErrorAction Stop
return
} catch {
if ($attempt -eq $Attempts) { throw }
Start-Sleep -Seconds 2
}
}
}
& (Join-Path $PSScriptRoot "generate-companion-icon.ps1")
& (Join-Path $PSScriptRoot "build-obs-bridge.ps1") -BridgeVersion $BridgeVersion -ObsVersion $ObsVersion
Remove-Item $publishRoot, $stageRoot, $sourceStageRoot -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $publishRoot, $stageRoot | Out-Null
$localDotnet = Join-Path $HOME ".dotnet-sdk\dotnet.exe"
$dotnet = if (Test-Path $localDotnet) { $localDotnet } else { (Get-Command dotnet.exe -ErrorAction Stop).Source }
$publishArguments = @("publish", $project, "-c", "Release", "-r", "win-x64", "--self-contained", "true", "--disable-build-servers", "-o", $publishRoot,
"-p:PublishSingleFile=true", "-p:IncludeNativeLibrariesForSelfExtract=true", "-p:DebugType=None", "-p:Version=$Version")
if ((Invoke-Native $dotnet $publishArguments)) { throw "Companion publish failed." }
$bridgeDiagnostic = Join-Path $outputRoot "obs-bridge-package-diagnostic.json"
Remove-Item $bridgeDiagnostic -Force -ErrorAction SilentlyContinue
if ((Invoke-Native (Join-Path $publishRoot "Lumi.Companion.App.exe") @("--diagnose-obs-bridge", $bridgeDiagnostic))) {
$detail = if (Test-Path $bridgeDiagnostic) { Get-Content $bridgeDiagnostic -Raw } else { "No diagnostic result was written." }
throw "Published OBS integration payload failed its executable-level check: $detail"
}
Remove-Item $bridgeDiagnostic -Force -ErrorAction SilentlyContinue
# Copy the release legal bundle beside the application so installed and portable
# builds carry the same terms, privacy notice, and third-party attributions.
New-Item -ItemType Directory -Force -Path $publishLegalRoot | Out-Null
foreach ($name in @(
"LUMI-COMPANION-LICENCE.txt",
"PRIVACY-NOTICE.txt",
"THIRD-PARTY-NOTICES.txt",
"LEGAL-README.txt"
)) {
Copy-Item (Join-Path $legalSourceRoot $name) (Join-Path $publishLegalRoot $name) -Force
}
Copy-Item (Join-Path $legalSourceRoot "third-party") (Join-Path $publishLegalRoot "third-party") -Recurse -Force
& (Join-Path $PSScriptRoot "collect-nuget-notices.ps1") -RepoRoot $repoRoot -OutputRoot (Join-Path $publishLegalRoot "third-party\nuget")
# The bundled OBS module links with GPL-licensed OBS/libobs. Ship the exact Lumi
# bridge source and build materials with every binary distribution.
$sourceCompanionRoot = Join-Path $sourceStageRoot "companion"
$sourceNativeParent = Join-Path $sourceCompanionRoot "native"
$sourceScriptsRoot = Join-Path $sourceCompanionRoot "scripts"
New-Item -ItemType Directory -Force -Path $sourceNativeParent, $sourceScriptsRoot | Out-Null
Copy-Item (Join-Path $repoRoot "companion\native\obs-bridge") (Join-Path $sourceNativeParent "obs-bridge") -Recurse -Force
Copy-Item (Join-Path $repoRoot "companion\scripts\build-obs-bridge.ps1") (Join-Path $sourceScriptsRoot "build-obs-bridge.ps1") -Force
$upstreamSourceRoot = Join-Path $sourceStageRoot "upstream-source"
New-Item -ItemType Directory -Force -Path $upstreamSourceRoot | Out-Null
$bridgeCacheRoot = Join-Path $env:LOCALAPPDATA "LumiCompanionBuild\obs-$ObsVersion"
$obsSourceArchive = Join-Path $bridgeCacheRoot "obs-source.zip"
$jsonSourceRoot = Join-Path $bridgeCacheRoot "bridge-build\_deps\json-src"
if (!(Test-Path $obsSourceArchive)) { throw "The exact OBS source archive used for the bridge build is missing." }
if (!(Test-Path $jsonSourceRoot)) { throw "The exact nlohmann/json source used for the bridge build is missing." }
Copy-Item $obsSourceArchive (Join-Path $upstreamSourceRoot "OBS-Studio-$ObsVersion-source.zip") -Force
Copy-Item $jsonSourceRoot (Join-Path $upstreamSourceRoot "nlohmann-json-3.12.0") -Recurse -Force
@"
Lumi OBS Bridge corresponding source
Release version: $BridgeVersion
This archive contains the Lumi-authored source and build script used for the
GPL-2.0-or-later OBS bridge distributed with Lumi Companion.
The archive includes the Lumi bridge source, its build script, the exact OBS Studio
$ObsVersion source archive used for its interfaces, and the exact nlohmann/json
3.12.0 source used in the binary. Checksums and upstream locations remain recorded
in the build script. OBS Studio binaries are not distributed by Companion.
Licence: companion/native/obs-bridge/COPYING
"@ | Set-Content -Encoding UTF8 (Join-Path $sourceStageRoot "SOURCE-README.txt")
$bridgeSourceArchive = Join-Path $publishLegalRoot "Lumi-OBS-Bridge-Source.zip"
Compress-ArchiveWithRetry -Path (Join-Path $sourceStageRoot "*") -DestinationPath $bridgeSourceArchive
Copy-Item (Join-Path $publishRoot "Lumi.Companion.App.exe") $stageRoot
Copy-Item (Join-Path $publishRoot "components") $stageRoot -Recurse
Copy-Item (Join-Path $publishRoot "legal") $stageRoot -Recurse
Remove-Item $archive -Force -ErrorAction SilentlyContinue
Compress-ArchiveWithRetry -Path (Join-Path $stageRoot "*") -DestinationPath $archive
$isccCandidates = @(
(Join-Path $env:LOCALAPPDATA "Programs\Inno Setup 6\ISCC.exe"),
(Join-Path ${env:ProgramFiles(x86)} "Inno Setup 6\ISCC.exe"),
(Join-Path $env:ProgramFiles "Inno Setup 6\ISCC.exe")
)
$iscc = $isccCandidates | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
if (-not $iscc) { throw "Inno Setup 6 is required to build the durable per-user Companion installer." }
Remove-Item $installer -Force -ErrorAction SilentlyContinue
$compileArguments = @(
"/DAppVersion=$Version",
"/DSourceRoot=$publishRoot",
"/DOutputRoot=$outputRoot",
(Join-Path $repoRoot "companion\installer\Lumi.Companion.iss")
)
if ((Invoke-Native $iscc $compileArguments) -or -not (Test-Path $installer)) { throw "Companion installer compilation failed." }
$file = Get-Item $archive
$sha = (Get-FileHash $archive -Algorithm SHA256).Hash.ToLowerInvariant()
$setupFile = Get-Item $installer
$setupSha = (Get-FileHash $installer -Algorithm SHA256).Hash.ToLowerInvariant()
Write-Host "Published Lumi Companion $Version"
Write-Host "Artifact: $archive"
Write-Host "Bytes: $($file.Length)"
Write-Host "SHA256: $sha"
Write-Host "Installer: $installer"
Write-Host "Installer bytes: $($setupFile.Length)"
Write-Host "Installer SHA256: $setupSha"