cirnogodot/CirnoBuild.psm1
2026-02-07 22:31:11 +01:00

397 lines
13 KiB
PowerShell

# CirnoBuild.psm1
# Common functions for building and publishing Cirno No Reason
# Configuration
$script:gitVersionPath = "dotnet-gitversion.exe"
$script:configFile = "export_presets.cfg"
$script:fileName = "Cirno_No_Reason"
# Platform configurations
$script:platforms = @{
"win" = @{
ExportName = "Windows Desktop"
Extension = ".exe"
OutputSubDir = "win"
}
"linux" = @{
ExportName = "Linux"
Extension = ".x86_64"
OutputSubDir = "linux"
}
}
function Test-Prerequisites {
<#
.SYNOPSIS
Validates that required tools are available
.PARAMETER GodotPath
Path to Godot executable
.PARAMETER SkipButler
Skip Butler validation (not needed for build-only operations)
#>
param(
[string]$GodotPath,
[string]$ButlerPath,
[switch]$SkipButler
)
$errors = @()
if ([string]::IsNullOrWhiteSpace($GodotPath)) {
$errors += "GODOT environment variable is not set. Please set it to your Godot executable path."
$errors += "Example: `$env:GODOT = 'C:\Godot\Godot_v4.x.exe'"
} elseif (-not (Test-Path $GodotPath)) {
# Try to resolve from PATH if it's just an executable name
$resolvedPath = Get-Command $GodotPath -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source
if ($resolvedPath) {
Write-Host " Resolved Godot path: $resolvedPath" -ForegroundColor Gray
# Update the caller's variable
return @{
Valid = $true
ResolvedGodotPath = $resolvedPath
}
} else {
$errors += "Godot executable not found at: $GodotPath"
$errors += "Please update the GODOT environment variable or add Godot to PATH."
}
}
if (-not (Test-Path $script:gitVersionPath) -and -not (Get-Command $script:gitVersionPath -ErrorAction SilentlyContinue)) {
$errors += "GitVersion not found. Please install dotnet-gitversion or add it to PATH."
}
if (-not $SkipButler) {
if ([string]::IsNullOrWhiteSpace($ButlerPath)) {
$errors += "Butler path is not configured."
} elseif (-not (Test-Path $ButlerPath)) {
$errors += "Butler executable not found at: $ButlerPath"
}
}
if ($errors.Count -gt 0) {
Write-Host ""
Write-Host "ERROR: Missing Prerequisites" -ForegroundColor Red
Write-Host "=====================================" -ForegroundColor Red
foreach ($error in $errors) {
Write-Host " $error" -ForegroundColor Yellow
}
Write-Host ""
return @{
Valid = $false
}
}
return @{
Valid = $true
ResolvedGodotPath = $GodotPath
}
}
function Get-VersionInfo {
<#
.SYNOPSIS
Gets version information from GitVersion
#>
Write-Host "Getting version information..." -ForegroundColor Cyan
$gitVersionOutput = & $script:gitVersionPath | ConvertFrom-Json
$versionInfo = @{
AssemblySemFileVer = $gitVersionOutput.AssemblySemFileVer
AssemblySemVer = $gitVersionOutput.AssemblySemVer
FullSemVer = $gitVersionOutput.FullSemVer
PreReleaseLabel = $gitVersionOutput.PreReleaseLabelWithDash
}
[System.Environment]::SetEnvironmentVariable("GIT_ASSEMBLY_SEM_FILE_VER", $versionInfo.AssemblySemFileVer, [System.EnvironmentVariableTarget]::Process)
[System.Environment]::SetEnvironmentVariable("GIT_ASSEMBLY_SEM_VER", $versionInfo.AssemblySemVer, [System.EnvironmentVariableTarget]::Process)
Write-Host " Version: $($versionInfo.FullSemVer)" -ForegroundColor Green
Write-Host " File Version: $($versionInfo.AssemblySemFileVer)" -ForegroundColor Green
return $versionInfo
}
function Initialize-BuildDirectories {
<#
.SYNOPSIS
Creates and clears build directories for specified platforms
#>
param(
[string[]]$PlatformsToBuild,
[string]$BuildDir
)
Write-Host "Initializing build directories..." -ForegroundColor Cyan
if (Test-Path $BuildDir) {
Remove-Item "$BuildDir\*" -Recurse -Force -ErrorAction SilentlyContinue
} else {
New-Item -ItemType Directory -Path $BuildDir | Out-Null
}
foreach ($platform in $PlatformsToBuild) {
$platformDir = Join-Path $BuildDir $script:platforms[$platform].OutputSubDir
New-Item -ItemType Directory -Path $platformDir -Force | Out-Null
Write-Host " Created: $platformDir" -ForegroundColor Gray
}
}
function Update-ExportConfig {
<#
.SYNOPSIS
Updates export_presets.cfg with version information
#>
param($VersionInfo)
Write-Host "Updating export configuration..." -ForegroundColor Cyan
if (Test-Path $script:configFile) {
(Get-Content $script:configFile) `
-replace 'application/file_version="[^"]*"', "application/file_version=`"$($VersionInfo.AssemblySemFileVer)`"" `
-replace 'application/product_version="[^"]*"', "application/product_version=`"$($VersionInfo.AssemblySemVer)`"" `
| Set-Content $script:configFile
Write-Host " Export config updated successfully" -ForegroundColor Green
} else {
Write-Host " WARNING: $script:configFile not found!" -ForegroundColor Red
}
}
function Wait-ForExportCompletion {
<#
.SYNOPSIS
Monitors export output file until it's complete
#>
param(
[string]$OutputPath,
[int]$TimeoutSeconds = 300
)
$startTime = Get-Date
$checkInterval = 2
$lastSize = -1
$stableCount = 0
$requiredStableChecks = 3
Write-Host " Waiting for export to complete: $OutputPath" -ForegroundColor Gray
while (((Get-Date) - $startTime).TotalSeconds -lt $TimeoutSeconds) {
Start-Sleep -Seconds $checkInterval
if (Test-Path $OutputPath) {
$currentSize = (Get-Item $OutputPath).Length
if ($currentSize -eq $lastSize -and $currentSize -gt 0) {
$stableCount++
if ($stableCount -ge $requiredStableChecks) {
Write-Host " Export completed: $OutputPath ($currentSize bytes)" -ForegroundColor Green
return $true
}
} else {
$stableCount = 0
}
$lastSize = $currentSize
}
}
Write-Host " WARNING: Export timeout reached for $OutputPath" -ForegroundColor Yellow
return (Test-Path $OutputPath)
}
function Create-PlatformZip {
<#
.SYNOPSIS
Creates a zip archive for a platform build
.PARAMETER Platform
Platform identifier (win, linux)
.PARAMETER BuildDir
Build directory path
.PARAMETER VersionInfo
Optional version information hashtable (if provided, includes version in filename)
.PARAMETER Force
Force recreate zip even if it exists
.RETURNS
Path to the created zip file, or $null if failed
#>
param(
[string]$Platform,
[string]$BuildDir,
[hashtable]$VersionInfo = $null,
[switch]$Force
)
$platformConfig = $script:platforms[$Platform]
$platformDir = Join-Path $BuildDir $platformConfig.OutputSubDir
# Determine zip filename (with or without version)
if ($VersionInfo) {
$zipFileName = "$script:fileName.$($VersionInfo.FullSemVer).$Platform.zip"
} else {
$zipFileName = "$script:fileName.$Platform.zip"
}
$zipFilePath = Join-Path $BuildDir $zipFileName
# Check if zip already exists and force not specified
if ((Test-Path $zipFilePath) -and -not $Force) {
Write-Host " Using existing zip: $zipFilePath" -ForegroundColor Gray
return $zipFilePath
}
# Validate source files exist
$files = Get-ChildItem -Path $platformDir -Recurse -File -ErrorAction SilentlyContinue
if (-not $files) {
Write-Host " ERROR: No files found in $platformDir" -ForegroundColor Red
return $null
}
# Create zip
Write-Host " Creating zip archive: $zipFileName" -ForegroundColor Cyan
try {
if (Test-Path $zipFilePath) { Remove-Item $zipFilePath -Force }
Compress-Archive -Path "$platformDir\*" -DestinationPath $zipFilePath -Force
Write-Host " Zip created: $zipFilePath" -ForegroundColor Green
return $zipFilePath
} catch {
Write-Host " ERROR: Failed to create zip: $($_.Exception.Message)" -ForegroundColor Red
return $null
}
}
function Export-GodotPlatform {
<#
.SYNOPSIS
Exports a single platform build using Godot - simple and direct
#>
param(
[string]$Platform,
[string]$GodotPath,
[string]$BuildDir,
[hashtable]$VersionInfo = $null
)
$platformConfig = $script:platforms[$Platform]
$outputPath = Join-Path $BuildDir "$($platformConfig.OutputSubDir)\$script:fileName$($platformConfig.Extension)"
Write-Host "Exporting $Platform build..." -ForegroundColor Cyan
Write-Host " Export Name: $($platformConfig.ExportName)" -ForegroundColor Gray
Write-Host " Output: $outputPath" -ForegroundColor Gray
Write-Host ""
if (Test-Path $outputPath) { Remove-Item $outputPath -Force }
$timeStamp = (Get-Date).ToString('yyyyMMdd-HHmmss')
# Put log in parent build folder, not in platform subfolder (avoid including in zip)
$logPath = Join-Path $BuildDir "godot-export-$Platform-$timeStamp.log"
$exportName = $platformConfig.ExportName
Write-Host "--- Godot Export Output ---" -ForegroundColor DarkGray
Write-Host "Logging to: $logPath" -ForegroundColor DarkGray
Write-Host ""
# Save current encoding and set to UTF8 to handle Godot's Unicode output
$previousEncoding = [Console]::OutputEncoding
try {
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# Run Godot directly - output streams to console and gets logged
& $GodotPath --headless --export-release $exportName $outputPath 2>&1 | Tee-Object -FilePath $logPath | ForEach-Object { Write-Host $_ }
} catch {
Write-Host " ERROR: Failed to execute Godot: $($_.Exception.Message)" -ForegroundColor Red
return $false
} finally {
# Restore previous encoding
[Console]::OutputEncoding = $previousEncoding
}
Write-Host ""
Write-Host "--- Export command completed ---" -ForegroundColor DarkGray
Write-Host ""
# Wait for the file to be created and stabilize
$success = Wait-ForExportCompletion -OutputPath $outputPath -TimeoutSeconds 30
if ($success) {
Write-Host " $Platform export completed successfully!" -ForegroundColor Green
# Create zip file after successful export (with version if provided)
$zipPath = Create-PlatformZip -Platform $Platform -BuildDir $BuildDir -VersionInfo $VersionInfo -Force
if (-not $zipPath) {
Write-Host " WARNING: Export succeeded but zip creation failed" -ForegroundColor Yellow
}
} else {
Write-Host " ERROR: $Platform export may have failed!" -ForegroundColor Red
Write-Host " Check log: $logPath" -ForegroundColor Yellow
}
return $success
}
function Publish-PlatformBuild {
<#
.SYNOPSIS
Publishes a platform build to itch.io
#>
param(
[string]$Platform,
[hashtable]$VersionInfo,
[string]$BuildDir,
[string]$ReleaseDir,
[string]$ButlerPath
)
$platformConfig = $script:platforms[$Platform]
$butlerTarget = "maddoscientisto/cirno-no-reason:$Platform$($VersionInfo.PreReleaseLabel)"
Write-Host "Publishing $Platform build..." -ForegroundColor Cyan
# Ensure zip exists with version number (create if missing)
$zipFilePath = Create-PlatformZip -Platform $Platform -BuildDir $BuildDir -VersionInfo $VersionInfo
if (-not $zipFilePath) {
Write-Host " ERROR: Failed to get or create zip file" -ForegroundColor Red
return $false
}
# Ensure release directory exists
if (!(Test-Path $ReleaseDir)) {
New-Item -ItemType Directory -Path $ReleaseDir | Out-Null
}
# Copy versioned zip to release directory
$zipFileName = Split-Path $zipFilePath -Leaf
$releaseZipPath = Join-Path $ReleaseDir $zipFileName
Copy-Item -Path $zipFilePath -Destination $releaseZipPath -Force
Write-Host " Copied to release: $zipFileName" -ForegroundColor Gray
# Push to itch.io
Write-Host " Pushing to itch.io: $butlerTarget" -ForegroundColor Gray
& $ButlerPath push $releaseZipPath $butlerTarget --userversion $VersionInfo.FullSemVer
if ($LASTEXITCODE -eq 0) {
Write-Host " $Platform published successfully!" -ForegroundColor Green
return $true
} else {
Write-Host " ERROR: Failed to publish $Platform build" -ForegroundColor Red
return $false
}
}
function Get-PlatformConfigurations {
<#
.SYNOPSIS
Returns platform configuration hashtable
#>
return $script:platforms
}
# Export functions
Export-ModuleMember -Function Test-Prerequisites, Get-VersionInfo, Initialize-BuildDirectories, `
Update-ExportConfig, Wait-ForExportCompletion, Create-PlatformZip, Export-GodotPlatform, `
Publish-PlatformBuild, Get-PlatformConfigurations