Files
mikusays-c/.github/workflows/package-win.yml
T

306 lines
10 KiB
YAML

name: Windows Installer Packaging
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag_name:
description: 'Release Tag (e.g., v1.0.0). Leave empty to use "latest".'
required: false
default: ''
jobs:
package-windows:
runs-on: windows-latest
permissions:
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install NSIS
run: choco install nsis
- name: Get Version from Cargo.toml
id: get_version
shell: pwsh
run: |
$VersionLine = Get-Content Cargo.toml | Select-String '^version\s*=\s*"(.*)"'
if ($VersionLine.Matches.Success) {
$Version = $VersionLine.Matches.Groups[1].Value
Write-Host "Found version in Cargo.toml: $Version"
"version=$Version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
} else {
Write-Error "Could not find version in Cargo.toml"
exit 1
}
- name: Determine Release Tag
id: get_tag
shell: pwsh
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
$TAG = "${{ inputs.tag_name }}"
if (-not $TAG) { $TAG = "${{ github.event.release.tag_name }}" }
if (-not $TAG) {
Write-Host "No tag provided, fetching latest release..."
$TAG = $(gh release view --json tagName --jq .tagName)
}
if (-not $TAG) {
Write-Error "Could not determine release tag."
exit 1
}
Write-Host "Using Tag: $TAG"
"tag=$TAG" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
- name: Download Release Assets
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
$TAG = "${{ steps.get_tag.outputs.tag }}"
$Version = "${{ steps.get_version.outputs.version }}"
gh release download $TAG -p "mikusays-windows-x86_64-$Version.exe"
gh release download $TAG -p "mikusays-windows-aarch64-$Version.exe"
- name: Generate NSIS Script
shell: pwsh
run: |
$Version = "${{ steps.get_version.outputs.version }}"
$InstallerName = "mikusays-windows-inst-any-$Version.exe"
# Prepend 0. to create a 4-part version string (0.X.Y.Z)
$NsisVersion = "0.$Version"
Write-Host "Installer Name: $InstallerName"
Write-Host "NSIS Internal Version: $NsisVersion"
$nsisContent = @'
!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "x64.nsh"
!include "WinVer.nsh"
; Removed duplicate LogicLib.nsh inclusion
; --- Helper Macros ---
!macro StrContains ResultVar Needle Haystack
Push "${Haystack}"
Push "${Needle}"
Call StrContains
Pop "${ResultVar}"
!macroend
Function StrContains
Exch $R1
Exch
Exch $R0
Push $R2
Push $R3
Push $R4
Push $R5
StrLen $R2 $R0
StrLen $R3 $R1
StrCpy $R5 ""
Loop:
StrCpy $R4 $R0 $R3
StrCmp $R4 $R1 Found
StrCpy $R0 $R0 "" 1
StrLen $R2 $R0
IntCmp $R2 $R3 Loop Loop End
Found:
StrCpy $R5 "1"
End:
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R0
Pop $R1
Exch $R5
FunctionEnd
!macro StrRep ResultVar String SubString RepString
Push "${String}"
Push "${SubString}"
Push "${RepString}"
Call un.StrRep
Pop "${ResultVar}"
!macroend
!macro un.StrRep ResultVar String SubString RepString
Push "${String}"
Push "${SubString}"
Push "${RepString}"
Call un.StrRep
Pop "${ResultVar}"
!macroend
Function un.StrRep
Exch $R2
Exch
Exch $R1
Exch
Exch $R0
Push $R3
Push $R4
Push $R5
Push $R6
Push $R7
StrCpy $R3 0
StrLen $R4 $R1
StrLen $R6 $R0
Start:
StrCpy $R5 $R0 $R4 $R3
StrCmp $R5 $R1 Found
IntOp $R3 $R3 + 1
IntCmp $R3 $R6 End End Start
Found:
StrCpy $R5 $R0 $R3
IntOp $R7 $R3 + $R4
StrCpy $R7 $R0 "" $R7
StrCpy $R0 "$R5$R2$R7"
StrLen $R6 $R0
IntOp $R3 $R3 + $R4
Goto Start
End:
Pop $R7
Pop $R6
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
Exch $R0
FunctionEnd
!define StrContains `!insertmacro StrContains`
!define StrRep `!insertmacro StrRep`
!define un.StrRep `!insertmacro un.StrRep`
; --- Main Script ---
Name "Mikusays"
OutFile "__OUTFILE__"
Unicode True
; --- Metadata & Versioning ---
VIProductVersion "__NSISVERSION__"
VIAddVersionKey "ProductName" "Mikusays"
VIAddVersionKey "CompanyName" "xxanqw"
VIAddVersionKey "LegalCopyright" "© xxanqw"
VIAddVersionKey "FileDescription" "Mikusays Installer"
VIAddVersionKey "FileVersion" "__VERSION__"
VIAddVersionKey "ProductVersion" "__VERSION__"
RequestExecutionLevel user
InstallDir "$LOCALAPPDATA\Programs\mikusays"
!define MUI_ABORTWARNING
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "Install"
SetOutPath "$INSTDIR"
; --- Architecture Detection & Redist Selection ---
; We select both the app binary and the correct VC Redist URL here
ReadEnvStr $0 "PROCESSOR_ARCHITECTURE"
${If} $0 == "ARM64"
File "/oname=mikusays.exe" "__ARMEXE__"
StrCpy $1 "https://aka.ms/vs/17/release/vc_redist.arm64.exe"
${Else}
File "/oname=mikusays.exe" "__X64EXE__"
StrCpy $1 "https://aka.ms/vs/17/release/vc_redist.x64.exe"
${EndIf}
WriteUninstaller "$INSTDIR\uninstall.exe"
; --- Download and Install VC++ Redist (Using PowerShell) ---
DetailPrint "Downloading Visual C++ Redistributable..."
; Define temp path for the installer
StrCpy $2 "$TEMP\vc_redist.exe"
; Use PowerShell to download. We'll ensure the entire command is a single quoted string
; ExecWait expects 1-2 parameters; to avoid tokenization use double-quoted command and escape inner double quotes
ExecWait "powershell -NoProfile -NonInteractive -Command \"Invoke-WebRequest -Uri '$1' -OutFile '$2'\"" $3
${If} $3 != 0
DetailPrint "Download failed (Error code: $3). Skipping Redistributable."
${Else}
DetailPrint "Installing Visual C++ Redistributable..."
; /install /quiet /norestart are standard flags for VC Redist
ExecWait '"$2" /install /quiet /norestart'
Delete "$2" ; Clean up the downloaded file
${EndIf}
; --- Add to PATH ---
ReadRegStr $0 HKCU "Environment" "Path"
${StrContains} $1 "$INSTDIR" "$0"
${If} $1 == ""
WriteRegExpandStr HKCU "Environment" "Path" "$0;$INSTDIR"
SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 "STR:Environment" /TIMEOUT=5000
${EndIf}
SectionEnd
Section "Uninstall"
Delete "$INSTDIR\mikusays.exe"
Delete "$INSTDIR\uninstall.exe"
RMDir "$INSTDIR"
; Remove from PATH
ReadRegStr $0 HKCU "Environment" "Path"
${un.StrRep} $0 "$0" ";$INSTDIR" ""
${un.StrRep} $0 "$0" "$INSTDIR;" ""
${un.StrRep} $0 "$0" "$INSTDIR" ""
WriteRegExpandStr HKCU "Environment" "Path" "$0"
SendMessage ${HWND_BROADCAST} ${WM_SETTINGCHANGE} 0 "STR:Environment" /TIMEOUT=5000
SectionEnd
'@
$exe_x64 = "mikusays-windows-x86_64-$Version.exe"
$exe_arm = "mikusays-windows-aarch64-$Version.exe"
$nsisContent = $nsisContent.Replace("__OUTFILE__", $InstallerName)
$nsisContent = $nsisContent.Replace("__NSISVERSION__", $NsisVersion)
$nsisContent = $nsisContent.Replace("__VERSION__", $Version)
$nsisContent = $nsisContent.Replace("__X64EXE__", $exe_x64)
$nsisContent = $nsisContent.Replace("__ARMEXE__", $exe_arm)
Set-Content -Path installer.nsi -Value $nsisContent
- name: List workspace contents for debug
shell: pwsh
run: |
Write-Host "-- Workspace Contents --"
Get-ChildItem -File | ForEach-Object { Write-Host $_.Name }
- name: Verify downloaded assets
shell: pwsh
run: |
$Version = "${{ steps.get_version.outputs.version }}"
$exe_x64 = "mikusays-windows-x86_64-$Version.exe"
$exe_arm = "mikusays-windows-aarch64-$Version.exe"
if (-not (Test-Path $exe_x64)) { Write-Error "Missing expected asset $exe_x64"; exit 1 }
if (-not (Test-Path $exe_arm)) { Write-Error "Missing expected asset $exe_arm"; exit 1 }
- name: Compile Installer
shell: cmd
run: '"C:\Program Files (x86)\NSIS\makensis.exe" installer.nsi'
- name: Upload Installer to Release
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
$TAG = "${{ steps.get_tag.outputs.tag }}"
$Version = "${{ steps.get_version.outputs.version }}"
$UploadName = "mikusays-windows-inst-any-$Version.exe"
gh release upload $TAG $UploadName --clobber