Skip to content

ensure archived before release step. #2

ensure archived before release step.

ensure archived before release step. #2

name: HoloPatcher Release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
OS_RUNNERS_JSON: '["windows-2019", "ubuntu-20.04", "macos-12"]'
PYTHON_VERSIONS_JSON: '["3.8"]'
ARCHITECTURES_JSON: '["x86", "x64"]'
INTERPRETERS_JSON: '["python"]'
UPX_VERSION: '4.2.2'
on:
push:
tags:
- 'v*.**-patcher'
workflow_dispatch:
permissions:
contents: write
jobs:
setup:
runs-on: ubuntu-latest
outputs:
os: ${{ steps.set_env.outputs.os }}
python-version: ${{ steps.set_env.outputs.python-version }}
architecture: ${{ steps.set_env.outputs.architecture }}
python-pypy: ${{ steps.set_env.outputs.python-pypy }}
#qt_version: ${#{ steps.set_env.outputs.qt_version }}
steps:
- name: Set environment variables
id: set_env
run: |
# Use a single line of JSON to avoid issues
$singleLineJson = '${{ env.OS_RUNNERS_JSON }}' -replace "`r", ""
$singleLineJson = $singleLineJson -replace "`n", ""
Write-Host $singleLineJson
echo "os<<EOF" >> $env:GITHUB_OUTPUT
echo $singleLineJson >> $env:GITHUB_OUTPUT
echo "EOF" >> $env:GITHUB_OUTPUT
$singleLineJson = '${{ env.PYTHON_VERSIONS_JSON }}' -replace "`r", ""
$singleLineJson = $singleLineJson -replace "`n", ""
Write-Host $singleLineJson
echo "python-version<<EOF" >> $env:GITHUB_OUTPUT
echo $singleLineJson >> $env:GITHUB_OUTPUT
echo "EOF" >> $env:GITHUB_OUTPUT
$singleLineJson = '${{ env.ARCHITECTURES_JSON }}' -replace "`r", ""
$singleLineJson = $singleLineJson -replace "`n", ""
Write-Host $singleLineJson
echo "architecture<<EOF" >> $env:GITHUB_OUTPUT
echo $singleLineJson >> $env:GITHUB_OUTPUT
echo "EOF" >> $env:GITHUB_OUTPUT
$singleLineJson = '${{ env.INTERPRETERS_JSON }}' -replace "`r", ""
$singleLineJson = $singleLineJson -replace "`n", ""
Write-Host $singleLineJson
echo "python-pypy<<EOF" >> $env:GITHUB_OUTPUT
echo $singleLineJson >> $env:GITHUB_OUTPUT
echo "EOF" >> $env:GITHUB_OUTPUT
shell: pwsh
build:
needs: setup
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # Disable automatic cancellation of other jobs
matrix:
os: ${{ fromJson(needs.setup.outputs.os) }}
python-version: ${{ fromJson(needs.setup.outputs.python-version) }}
architecture: ${{ fromJson(needs.setup.outputs.architecture) }}
python_pypy: ${{ fromJson(needs.setup.outputs.python-pypy) }}
#qt_version: ['pyqt5', 'pyqt6', 'pyside2', 'pyside6']
include:
- arch: x86
vc_redist2015: "https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x86.exe"
vc_redist-latest: "https://aka.ms/vs/17/release/vc_redist.x86.exe"
vc_redist2019: "https://aka.ms/vs/17/release/vc_redist.x86.exe"
- arch: x64
vc_redist2015: "https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe"
vc_redist-latest: "https://aka.ms/vs/17/release/vc_redist.x64.exe"
vc_redist2019: "https://aka.ms/vs/17/release/vc_redist.x64.exe"
exclude:
# unix x86 is definitely not supported.
- os: ubuntu-20.04
architecture: x86
- os: macos-12
architecture: x86
# latest PyPy version as of 17/03/2024 is 3.10.
- python_pypy: 'pypy'
python-version: '3.11'
- python_pypy: 'pypy'
python-version: '3.12'
# PyQt5 doesn't seem to be compatible with PyPy
#- python_pypy: "pypy"
# qt_version: 'pyqt5'
#- python_pypy: "pypy"
# qt_version: 'pyside2'
#- python_pypy: "pypy"
# qt_version: 'pyqt6'
#- python_pypy: "pypy"
# python-version: '3.10'
# os: 'windows-2019'
outputs:
matrix-os: ${{ toJson(matrix.os) }}
matrix-python-version: ${{ toJson(matrix.python-version) }}
steps:
- name: Determine Python version string
id: set-python-version
run: |
if ( "${{ matrix.python_pypy }}" -eq "pypy" ) {
Add-Content -Path $env:GITHUB_ENV -Value "PYTHON_VERSION=pypy-${{ matrix.python-version }}"
} else {
Add-Content -Path $env:GITHUB_ENV -Value "PYTHON_VERSION=${{ matrix.python-version }}"
}
shell: pwsh
- uses: actions/checkout@v4
- name: Test Powershell installer
if: ${{ runner.os != 'Windows' }}
id: setup-powershell
run: |
bash ./install_powershell.sh
shell: bash
- name: Set up ${{ matrix.python_pypy }} ${{ matrix.python-version }}
if: ${{ runner.os != 'macOS' && (runner.os != 'Linux' || matrix.python_pypy == 'pypy') }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: ${{ matrix.architecture }}
- name: Set up python 3.12 mac (stops brew erroring on linking)
if: ${{ runner.os == 'macOS' && matrix.python-version != '3.12' }}
run: |
brew install [email protected] --quiet || true
shell: bash
- name: Set up ${{ matrix.python_pypy }} ${{ matrix.python-version }} macOS
if: ${{ runner.os == 'macOS' }}
run: | # warning: `brew link --overwrite python@ver` is unsafe on any non-virtualized macos.
echo "NONINTERACTIVE DEFAULT: $NONINTERACTIVE"
export NONINTERACTIVE=1
echo "NONINTERACTIVE NEW: $NONINTERACTIVE"
brew analytics on
brew update
brew install ${{ matrix.python_pypy }}@${{ matrix.python-version }} || brew link --overwrite ${{ matrix.python_pypy }}@${{ matrix.python-version }}
- name: Set up ${{ matrix.python_pypy }} ${{ matrix.python-version }} ${{ runner.os }} # macos too?
if: ${{ runner.os == 'Linux' && matrix.python_pypy == 'python' }}
run: |
if ("${{ runner.os }}" -eq "Linux") {
sudo apt-get update
sudo apt-get install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev libbz2-dev tk-dev -y
} elseif ("${{ runner.os }}" -eq "macOS") {
# Ensure Xcode Command Line Tools are installed?
# xcode-select --install 2>$null | Out-Null
}
$pyVersion = switch ("${{ matrix.python-version }}") {
"3.7" { "3.7.17" }
"3.8" { "3.8.18" }
"3.9" { "3.9.18" }
"3.10" { "3.10.13" }
"3.11" { "3.11.8" }
"3.12" { "3.12.2" }
}
Write-Output "Downloading ${{ matrix.python_pypy }} '$pyVersion'..."
Invoke-WebRequest -Uri https://www.python.org/ftp/python/$pyVersion/Python-$pyVersion.tgz -OutFile Python-$pyVersion.tgz
tar -xvf Python-$pyVersion.tgz
$current_working_dir = (Get-Location).Path
Set-Location -LiteralPath "Python-$pyVersion" -ErrorAction Stop
$env:LDFLAGS=""
sudo ./configure --enable-optimizations --with-ensurepip=install --enable-shared --disable-new-dtags
sudo make -j $(nproc)
sudo make altinstall
Set-Location -LiteralPath $current_working_dir
shell: pwsh
- name: Reset APT sources to default
if: ${{ runner.os == 'Linux' }}
run: |
echo "Resetting APT sources to default Ubuntu repositories"
sudo rm /etc/apt/sources.list
echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs)-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs)-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
echo "deb http://security.ubuntu.com/ubuntu $(lsb_release -cs)-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list
sudo apt-get update -y
shell: bash
- name: Setup python venvs
run: | # create the venv early to work around an issue with the matrix runners' concurrency
$pythonExeName = "${{ matrix.python_pypy }}"
if ("${{ runner.os }}" -ne "Windows")
{
$pythonExeName = "${{ matrix.python_pypy }}${{ matrix.python-version }}"
# LD_LIBRARY_PATH must be updated. However this won't be permanent, just long enough to create the venv.
$env:LD_LIBRARY_PATH = "/usr/local/lib:$env:LD_LIBRARY_PATH"
}
& $pythonExeName -m venv .venv_holopatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExeName -m venv .venv_toolset_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExeName -m venv .venv_guiduplicator_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExeName -m venv .venv_kotordiff_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExeName -m venv .venv_batchpatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
shell: pwsh
- name: Set UPX download URL
# upx docs express that crashes are happening on ventura and above with upx, don't use on mac.
if: runner.os != 'macOS'
id: upx_setup
run: |
$build = "no"
$archiveName = ""
if ("${{ runner.os }}" -eq "Windows") {
if ("${{ matrix.architecture }}" -eq "x86") {
$archiveName = "upx-${{ env.UPX_VERSION }}-win32.zip"
} else {
$archiveName = "upx-${{ env.UPX_VERSION }}-win64.zip"
}
} elseif ("${{ runner.os }}" -eq "Linux") {
$archiveName = "upx-${{ env.UPX_VERSION }}-amd64_linux.tar.xz"
} elseif ("${{ runner.os }}" -eq "macOS") {
$build = "yes"
$archiveName = "upx-${{ env.UPX_VERSION }}-src.tar.xz"
}
$url = "https://github.com/upx/upx/releases/download/v${{ env.UPX_VERSION }}/$archiveName"
# Write to the GITHUB_OUTPUT environment file
Add-Content -Path $env:GITHUB_OUTPUT -Value "build=$build"
Add-Content -Path $env:GITHUB_OUTPUT -Value "url=$url"
Add-Content -Path $env:GITHUB_OUTPUT -Value "archiveName=$archiveName"
shell: pwsh
- name: Download and prepare UPX
if: runner.os != 'macOS'
run: |
$ext = "${{ runner.os }}" -eq "Windows" ? "zip" : "tar.xz"
$url = "${{ steps.upx_setup.outputs.url }}"
$archiveName = "${{ steps.upx_setup.outputs.archiveName }}"
$outputPath = "upx-dir"
# Use Invoke-WebRequest or curl depending on the OS
if ("${{ runner.os }}" -eq "Windows") {
Invoke-WebRequest -Uri $url -OutFile $archiveName
} elseif ("${{ runner.os }}" -eq "Linux") {
curl -L $url -o $archiveName
}
New-Item -ItemType Directory -Force -Path "upx-dir" -ErrorAction SilentlyContinue
if ("${{ runner.os }}" -ne "macOS") {
if ($ext -eq "zip") {
$fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($archiveName)
Expand-Archive -Path $archiveName -DestinationPath "temp_folder_upx"
# Ensure upx-dir exists; create it if it doesn't
if (-not (Test-Path -Path "upx-dir")) {
New-Item -ItemType Directory -Path "upx-dir"
}
Get-ChildItem -Path "temp_folder_upx/$fileNameWithoutExtension" -Recurse | Move-Item -Destination "upx-dir"
Remove-Item "temp_folder_upx" -Recurse -Force -ErrorAction SilentlyContinue
} else {
tar -xvf $archiveName --strip-components=1 -C "upx-dir"
}
Remove-Item $archiveName # Clean up downloaded archive
}
shell: pwsh
- name: Set UPX directory path
if: runner.os != 'macOS'
id: upx_dir
run: |
$upx_dir = "./upx-dir"
$upx_dir = $([System.IO.Path]::GetFullPath('./upx-dir'))
Dir -Recurse $upx_dir | Get-Childitem
echo "UPX_DIR=$upx_dir" | Out-File -FilePath $env:GITHUB_ENV -Append
Write-Output "UPX_DIR set to '$upx_dir'"
shell: pwsh
- name: Install Visual Studio 2015 C++ Redistributable
if: runner.os == 'Windows'
run: |
$url = "${{ matrix.vc_redist2015 }}"
$output = "vc_redist.exe"
Invoke-WebRequest -Uri $url -OutFile $output
Start-Process $output -ArgumentList '/install', '/quiet', '/norestart' -Wait
Remove-Item -Path $output
#choco install vcredist2015 -y
shell: pwsh
- name: Install Visual Studio 2019 C++ Redistributable
if: runner.os == 'Windows'
run: |
$url = "${{ matrix.vc_redist2019 }}"
$output = "vc_redist.exe"
Invoke-WebRequest -Uri $url -OutFile $output
Start-Process $output -ArgumentList '/install', '/quiet', '/norestart' -Wait
Remove-Item -Path $output
#choco install vcredist2019 -y
shell: pwsh
- name: Install Visual Studio latest C++ Redistributable
if: runner.os == 'Windows'
run: |
$url = "${{ matrix.vc_redist-latest }}"
$output = "vc_redist.exe"
Invoke-WebRequest -Uri $url -OutFile $output
Start-Process $output -ArgumentList '/install', '/quiet', '/norestart' -Wait
Remove-Item -Path $output
shell: pwsh
- name: Install Holocron Toolset dependencies
if: ${{ success() || failure() }}
id: toolset_deps
run: | # known pyinstaller versions that work with upx compressions, not all are available on all python versions.
try {
. ./install_python_venv.ps1 -noprompt -venv_name .venv_toolset_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
Write-Host "Python executable path: $pythonExePath"
& $pythonExePath -m pip install --upgrade pip
if ("${{ runner.os }}" -eq "Windows") {
if ("${{ matrix.python-version }}" -eq "3.12") {
pip install pyinstaller --prefer-binary -U
} elseif ("${{ matrix.python-version }}" -eq "3.11") {
pip install "pyinstaller==5.13.2" --prefer-binary
} else {
pip install "pyinstaller==5.4" --prefer-binary
}
} else {
pip install pyinstaller -U --prefer-binary
}
#$env:QT_API = if (-not [string]::IsNullOrEmpty($env:QT_API)) { $env:QT_API } else { "{{ matrix.qt_version }}" }
$output = ""
$errorLines = @()
. ./compile/deps_toolset.ps1 -noprompt -venv_name .venv_toolset_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
} catch {
Write-Host -ForegroundColor Red "$($_.InvocationInfo.PositionMessage)`n$($_.Exception.Message)"
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
}
shell: pwsh
- name: HolocronToolset - Adjust RPATH for shared libraries in the virtual environment
if: ${{ (success() || failure()) && runner.os == 'Disabled_Linux' && steps.toolset_deps.outputs.success == 'true' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_toolset_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
# Ensure patchelf is installed
sudo apt-get update && sudo apt-get install -y patchelf
# Find the virtual environment's site-packages directory
$venvPath = $env:VIRTUAL_ENV
Write-Host "Virtual environment path: $venvPath"
# Dynamically find the Python version directory inside the venv
$pythonLibPath = Get-ChildItem -Path "$venvPath/lib" | Where-Object { $_.PSIsContainer } | Select-Object -First 1
$sitePackagesPath = Join-Path -Path $pythonLibPath.FullName -ChildPath "site-packages"
Write-Host "Site-packages path: $sitePackagesPath"
# Use patchelf to adjust RPATH for all shared libraries in the virtual environment
Get-ChildItem -Path $sitePackagesPath -Filter *.so -Recurse | ForEach-Object {
$libPath = $_.FullName
Write-Host "Patching $libPath"
sudo patchelf --set-rpath '$ORIGIN' $libPath
}
shell: pwsh
- name: Compile Holocron Toolset
if: ${{ (success() || failure()) && steps.toolset_deps.outputs.success == 'true' }}
run: |
$upxDir = $env:UPX_DIR
Write-Host "Using UPX directory at '$upxDir'"
$output = ""
. ./compile/compile_toolset.ps1 -noprompt -venv_name .venv_toolset_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} -upx_dir $upxDir 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
$warningCount = 0
$output -split "`n" | ForEach-Object {
if ($_ -match 'WARNING: Library not found: could not resolve' -or
$_ -match 'WARNING: Cannot find ' -or
$_ -match 'WARNING: lib not found:' -or
$_ -match 'WARNING: Tcl modules directory' -or
$_ -match 'WARNING: Failed to upx strip') {
$warningCount++
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} elseif ($warningCount -ge 3) {
Write-Output "Many 'library not found' warnings raised, pyinstaller was probably unsuccessful."
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
shell: pwsh
- name: HolocronToolset - Create Static Binary
if: ${{ (success() || failure()) && runner.os == 'Disabled_Linux' && steps.toolset_deps.outputs.success == 'true' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_toolset_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install staticx
staticx ./dist/HolocronToolset ./dist/HolocronToolset-static
# Rename the static binary for clarity and consistency
Write-Output "./dist/HolocronToolset-static --> ./dist/HolocronToolset"
Move-Item -LiteralPath ./dist/HolocronToolset-static -Destination ./dist/HolocronToolset -Force
shell: pwsh
- name: Install HoloPatcher dependencies
if: ${{ success() || failure() }}
id: holopatcher_deps
run: | # known pyinstaller versions that work with upx compressions, not all are available on all python versions.
try {
. ./install_python_venv.ps1 -noprompt -venv_name .venv_holopatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install --upgrade pip
if ("${{ runner.os }}" -eq "Windows") {
if ("${{ matrix.python-version }}" -eq "3.12") {
pip install "pyinstaller==5.13.2" --prefer-binary
} elseif ("${{ matrix.python-version }}" -eq "3.11") {
pip install "pyinstaller==5.13.2" --prefer-binary
} else {
pip install "pyinstaller==5.4" --prefer-binary
}
} else {
pip install pyinstaller -U --prefer-binary
}
$output = ""
$errorLines = @()
. ./compile/deps_holopatcher.ps1 -noprompt -venv_name .venv_holopatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
} catch {
Write-Host -ForegroundColor Red "$($_.InvocationInfo.PositionMessage)`n$($_.Exception.Message)"
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
}
shell: pwsh
- name: HoloPatcher - Adjust RPATH for shared libraries in the virtual environment
if: ${{ (success() || failure()) && runner.os == 'Disabled_Linux' && steps.holopatcher_deps.outputs.success == 'true' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_holopatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
# Ensure patchelf is installed
sudo apt-get update && sudo apt-get install -y patchelf
# Find the virtual environment's site-packages directory
$venvPath = $env:VIRTUAL_ENV
Write-Host "Virtual environment path: $venvPath"
# Dynamically find the Python version directory inside the venv
$pythonLibPath = Get-ChildItem -Path "$venvPath/lib" | Where-Object { $_.PSIsContainer } | Select-Object -First 1
$sitePackagesPath = Join-Path -Path $pythonLibPath.FullName -ChildPath "site-packages"
Write-Host "Site-packages path: $sitePackagesPath"
# Use patchelf to adjust RPATH for all shared libraries in the virtual environment
Get-ChildItem -Path $sitePackagesPath -Filter *.so -Recurse | ForEach-Object {
$libPath = $_.FullName
Write-Host "Patching $libPath"
sudo patchelf --set-rpath '$ORIGIN' $libPath
}
shell: pwsh
- name: Compile HoloPatcher
if: ${{ (success() || failure()) && steps.holopatcher_deps.outputs.success == 'true' }}
run: |
$upxDir = $env:UPX_DIR
Write-Host "Using UPX directory at '$upxDir'"
$output = ""
. ./compile/compile_holopatcher.ps1 -noprompt -venv_name .venv_holopatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} -upx_dir $upxDir 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
$warningCount = 0
$output -split "`n" | ForEach-Object {
if ($_ -match 'WARNING: Library not found: could not resolve' -or
$_ -match 'WARNING: Cannot find ' -or
$_ -match 'WARNING: lib not found:' -or
$_ -match 'WARNING: Tcl modules directory' -or
$_ -match 'WARNING: Failed to upx strip') {
$warningCount++
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} elseif ($warningCount -ge 3) {
Write-Output "Many 'library not found' warnings raised, pyinstaller was probably unsuccessful."
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
shell: pwsh
- name: HoloPatcher - Create Static Binary
if: ${{ (success() || failure()) && runner.os == 'Disabled_Linux' && steps.holopatcher_deps.outputs.success == 'true' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_holopatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install staticx
staticx ./dist/HoloPatcher ./dist/HoloPatcher-static
# Rename the static binary for clarity and consistency
Write-Output "./dist/HoloPatcher-static --> ./dist/HoloPatcher"
Move-Item -LiteralPath ./dist/HoloPatcher-static -Destination ./dist/HoloPatcher -Force
shell: pwsh
- name: Install BatchPatcher dependencies
if: ${{ success() || failure() }}
id: batchpatcher_deps
run: | # known pyinstaller versions that work with upx compressions, not all are available on all python versions.
try {
. ./install_python_venv.ps1 -noprompt -venv_name .venv_batchpatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install --upgrade pip
if ("${{ runner.os }}" -eq "Windows") {
if ("${{ matrix.python-version }}" -eq "3.12") {
pip install pyinstaller --prefer-binary -U
} elseif ("${{ matrix.python-version }}" -eq "3.11") {
pip install "pyinstaller==5.13.2" --prefer-binary
} else {
pip install "pyinstaller==5.4" --prefer-binary
}
} else {
pip install pyinstaller -U --prefer-binary
}
$output = ""
$errorLines = @()
. ./compile/deps_batchpatcher.ps1 -noprompt -venv_name .venv_batchpatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
} catch {
Write-Host -ForegroundColor Red "$($_.InvocationInfo.PositionMessage)`n$($_.Exception.Message)"
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
}
shell: pwsh
- name: BatchPatcher - Adjust RPATH for shared libraries in the virtual environment
if: ${{ (success() || failure()) && runner.os == 'Disabled_Linux' && steps.batchpatcher_deps.outputs.success == 'true' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_batchpatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
# Ensure patchelf is installed
sudo apt-get update && sudo apt-get install -y patchelf
# Find the virtual environment's site-packages directory
$venvPath = $env:VIRTUAL_ENV
Write-Host "Virtual environment path: $venvPath"
# Dynamically find the Python version directory inside the venv
$pythonLibPath = Get-ChildItem -Path "$venvPath/lib" | Where-Object { $_.PSIsContainer } | Select-Object -First 1
$sitePackagesPath = Join-Path -Path $pythonLibPath.FullName -ChildPath "site-packages"
Write-Host "Site-packages path: $sitePackagesPath"
# Use patchelf to adjust RPATH for all shared libraries in the virtual environment
Get-ChildItem -Path $sitePackagesPath -Filter *.so -Recurse | ForEach-Object {
$libPath = $_.FullName
Write-Host "Patching $libPath"
sudo patchelf --set-rpath '$ORIGIN' $libPath
}
shell: pwsh
- name: Compile BatchPatcher
if: ${{ (success() || failure()) && steps.batchpatcher_deps.outputs.success == 'true' }}
run: |
$upxDir = $env:UPX_DIR
Write-Host "Using UPX directory at '$upxDir'"
$output = ""
. ./compile/compile_batchpatcher.ps1 -noprompt -venv_name .venv_batchpatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} -upx_dir $upxDir 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
$warningCount = 0
$output -split "`n" | ForEach-Object {
if ($_ -match 'WARNING: Library not found: could not resolve' -or
$_ -match 'WARNING: Cannot find ' -or
$_ -match 'WARNING: lib not found:' -or
$_ -match 'WARNING: Tcl modules directory' -or
$_ -match 'WARNING: Failed to upx strip') {
$warningCount++
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} elseif ($warningCount -ge 3) {
Write-Output "Many 'library not found' warnings raised, pyinstaller was probably unsuccessful."
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
shell: pwsh
- name: BatchPatcher - Create Static Binary
if: ${{ (success() || failure()) && runner.os == 'Disabled_Linux' && steps.batchpatcher_deps.outputs.success == 'true' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_batchpatcher_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install staticx
staticx ./dist/K_BatchPatcher ./dist/K_BatchPatcher-static
# Rename the static binary for clarity and consistency
Write-Output "./dist/K_BatchPatcher-static --> ./dist/K_BatchPatcher"
Move-Item -LiteralPath ./dist/K_BatchPatcher-static -Destination ./dist/K_BatchPatcher -Force
shell: pwsh
- name: Compile KotorDiff
if: ${{ success() || failure() }}
run: |
$upxDir = $env:UPX_DIR
Write-Host "Using UPX directory at '$upxDir'"
. ./install_python_venv.ps1 -noprompt -venv_name .venv_kotordiff_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install --upgrade pip
if ("${{ runner.os }}" -eq "Windows") {
if ("${{ matrix.python-version }}" -eq "3.12") {
pip install "pyinstaller==5.13.2" --prefer-binary
} elseif ("${{ matrix.python-version }}" -eq "3.11") {
pip install "pyinstaller==5.13.2" --prefer-binary
} else {
pip install "pyinstaller==5.4" --prefer-binary
}
} else {
pip install pyinstaller -U --prefer-binary
}
pip install -r Tools/KotorDiff/requirements.txt --prefer-binary
$output = ""
. ./compile/compile_kotordiff.ps1 -noprompt -venv_name .venv_kotordiff_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} -upx_dir $upxDir 2>&1 | ForEach-Object {
Write-Output $_.ToString()
$output += $_.ToString() + "`n"
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
$warningCount = 0
$output -split "`n" | ForEach-Object {
if ($_ -match 'WARNING: Library not found: could not resolve' -or
$_ -match 'WARNING: Cannot find ' -or
$_ -match 'WARNING: lib not found:' -or
$_ -match 'WARNING: Tcl modules directory' -or
$_ -match 'WARNING: Failed to upx strip') {
$warningCount++
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} elseif ($warningCount -ge 3) {
Write-Output "Many 'library not found' warnings raised, pyinstaller was probably unsuccessful."
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
shell: pwsh
- name: KotorDiff - Create Static Binary
if: ${{ (success() || failure()) && runner.os == 'Linux' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_kotordiff_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install staticx
staticx ./dist/KotorDiff ./dist/KotorDiff-static
# Rename the static binary for clarity and consistency
Write-Output "./dist/KotorDiff-static --> ./dist/KotorDiff"
Move-Item -LiteralPath ./dist/KotorDiff-static -Destination ./dist/KotorDiff -Force
shell: pwsh
- name: Compile GUIDuplicator
if: ${{ success() || failure() }}
run: |
$upxDir = $env:UPX_DIR
Write-Host "Using UPX directory at '$upxDir'"
. ./install_python_venv.ps1 -noprompt -venv_name .venv_guiduplicator_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install --upgrade pip
if ("${{ runner.os }}" -eq "Windows") {
if ("${{ matrix.python-version }}" -eq "3.12") {
pip install "pyinstaller==5.13.2" --prefer-binary
} elseif ("${{ matrix.python-version }}" -eq "3.11") {
pip install "pyinstaller==5.13.2" --prefer-binary
} else {
pip install "pyinstaller==5.4" --prefer-binary
}
} else {
pip install pyinstaller -U --prefer-binary
}
pip install -r Tools/GuiDuplicator/requirements.txt --prefer-binary
$output = ""
. ./compile/compile_gui_duplicator.ps1 -noprompt -venv_name .venv_guiduplicator_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }} -upx_dir $upxDir 2>&1 | ForEach-Object {
Write-Output $_.ToString()
if($_ -match 'ERROR:') {
$errorLines += $_.ToString()
}
}
$warningCount = 0
$output -split "`n" | ForEach-Object {
if ($_ -match 'WARNING: Library not found: could not resolve' -or
$_ -match 'WARNING: Cannot find ' -or
$_ -match 'WARNING: lib not found:' -or
$_ -match 'WARNING: Tcl modules directory' -or
$_ -match 'WARNING: Failed to upx strip') {
$warningCount++
}
}
if ($errorLines.Count -gt 0) {
$errorLines | ForEach-Object { Write-Error $_ }
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} elseif ($warningCount -ge 3) {
Write-Output "Many 'library not found' warnings raised, pyinstaller was probably unsuccessful."
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=false"
exit 1
} else {
Add-Content -Path $env:GITHUB_OUTPUT -Value "success=true"
}
shell: pwsh
- name: GUIDuplicator - Create Static Binary
if: ${{ (success() || failure()) && runner.os == 'Linux' }}
run: |
. ./install_python_venv.ps1 -noprompt -venv_name .venv_guiduplicator_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
& $pythonExePath -m pip install staticx
staticx ./dist/GuiDuplicator ./dist/GuiDuplicator-static
# Rename the static binary for clarity and consistency
Write-Output "./dist/GuiDuplicator-static --> ./dist/GuiDuplicator"
Move-Item -LiteralPath ./dist/GuiDuplicator-static -Destination ./dist/GuiDuplicator -Force
shell: pwsh
- name: Upload compiled binaries attempt 1
if: ${{ success() || failure() }}
id: upload_attempt_1
uses: actions/upload-artifact@v4
with:
name: publish_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
path: ./dist/**
retention-days: 90
continue-on-error: true
- name: Upload compiled binaries attempt 2
id: upload_attempt_2
if: ${{ (success() || failure()) && steps.upload_attempt_1.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: publish_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
path: ./dist/**
retention-days: 90
continue-on-error: true
- name: Upload compiled binaries attempt 3
id: upload_attempt_3
if: ${{ (success() || failure()) && steps.upload_attempt_2.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: publish_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
path: ./dist/**
retention-days: 90
continue-on-error: true
- name: Upload compiled binaries attempt 4
id: upload_attempt_4
if: ${{ (success() || failure()) && steps.upload_attempt_3.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: publish_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
path: ./dist/**
retention-days: 90
continue-on-error: true
- name: Upload compiled binaries attempt 5
id: upload_attempt_5
if: ${{ (success() || failure()) && steps.upload_attempt_4.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: publish_${{ matrix.os }}_${{ matrix.python_pypy }}_${{ matrix.python-version }}_${{ matrix.architecture }}
path: ./dist/**
retention-days: 90
package:
needs: build # do not start this job until all 'build' jobs complete
if: ${{ success() || failure() }}
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: published_workflow_builds/
pattern: publish_*
- name: Extract tag name
id: get_tag
run: echo "::set-output name=tag::${GITHUB_REF#refs/tags/}"
shell: bash
- name: Compress into archives
run: |
$sourceFolder = Join-Path -Path (Get-Location) -ChildPath "published_workflow_builds"
Set-Location $sourceFolder
Get-ChildItem -Path "." -Directory | ForEach-Object {
$folderName = $_.Name
$archiveName = "$folderName.zip"
zip -r -9 $archiveName $folderName
}
shell: pwsh
- uses: ncipollo/[email protected]
with:
tag: ${{ steps.get_tag.outputs.tag }}
prerelease: true
draft: true
artifacts: "published_workflow_builds/*.zip"
allowUpdates: true
token: ${{ secrets.GITHUB_TOKEN }}