Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .github/workflows/build-appimage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Build AppImage

on:
push:
branches: [linux-port]
release:
types: [published]
workflow_dispatch:

permissions:
contents: read

jobs:
build:
# Build on the oldest supported distro: the bundled glibc floor comes from
# the build machine, so newer runners would break older distros.
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref }}

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'
cache: pip

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --retries 5 -r requirements.txt

- name: Obtain extracted_data.zip
env:
EXTRACTED_DATA_URL: ${{ vars.EXTRACTED_DATA_URL }}
run: |
if [ -n "$EXTRACTED_DATA_URL" ]; then
curl -fL -o extracted_data.zip "$EXTRACTED_DATA_URL"
else
# Pull the same data file the upstream Windows release bundles inside its exe
pip install pyinstxtractor-ng==2026.7.3
curl -fL -o upstream.exe \
"https://github.com/tommadness/KH2Randomizer/releases/latest/download/KH2.Randomizer.exe"
pyinstxtractor-ng upstream.exe
cp upstream.exe_extracted/extracted_data.zip .
rm -rf upstream.exe upstream.exe_extracted
fi
test -s extracted_data.zip

- name: Build AppImage
env:
# appimagetool runs without FUSE on CI runners
APPIMAGE_EXTRACT_AND_RUN: '1'
PYTHON: python
run: ./packaging/linux/build_appimage.sh

- name: Smoke test
run: |
sudo apt-get update -qq && sudo apt-get install -y -qq libegl1 libgl1 libxkbcommon0
chmod +x KH2.Randomizer-x86_64.AppImage
# Boot headless for a few seconds; exit code 124 means it was still
# running (the GUI event loop) when the timeout killed it.
rc=0
timeout 20 env QT_QPA_PLATFORM=offscreen APPIMAGE_EXTRACT_AND_RUN=1 \
./KH2.Randomizer-x86_64.AppImage || rc=$?
test "$rc" -eq 124

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: KH2.Randomizer-x86_64.AppImage
path: KH2.Randomizer-x86_64.AppImage
compression-level: 0

release:
if: github.event_name == 'release'
needs: build
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: KH2.Randomizer-x86_64.AppImage

- name: Attach to release
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload '${{ github.event.release.tag_name }}' KH2.Randomizer-x86_64.AppImage --clobber
58 changes: 58 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Test

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
tests:
strategy:
matrix:
os: [ubuntu-22.04, windows-2022]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'
cache: pip
- name: Install dependencies
run: python -m pip install --retries 5 -r requirements.txt pytest
- name: Install Linux GUI runtime libraries
if: runner.os == 'Linux'
run: sudo apt-get update -qq && sudo apt-get install -y -qq libegl1 libgl1 libxkbcommon0
- name: Compile
run: python -m compileall -q Class List Module UI linux_main.py localUI.py updater.py
- name: Test
env:
QT_QPA_PLATFORM: offscreen
XDG_DATA_HOME: ${{ runner.temp }}/kh2randomizer-test-data
run: >-
python -m pytest -q
tests/test_platformutils.py
tests/test_releaseInfo.py
tests/test_checkbox_settings.py

windows-package:
runs-on: windows-2022
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.12'
cache: pip
- name: Install dependencies
run: python -m pip install --retries 5 -r requirements.txt
- name: Obtain extracted data
shell: pwsh
run: |
Invoke-WebRequest -Uri "https://github.com/tommadness/KH2Randomizer/releases/latest/download/KH2.Randomizer.exe" -OutFile upstream.exe
python -m pip install pyinstxtractor-ng==2026.7.3
pyinstxtractor-ng upstream.exe
Copy-Item upstream.exe_extracted/extracted_data.zip .
- name: Build Windows package
run: python -m PyInstaller --noconfirm "KH2 Randomizer Debug.spec"
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
*.zip
*.AppImage
__pycache__
venv
.venv
.vs
.vscode
.idea/
Expand All @@ -22,4 +24,5 @@ Gemfile.lock
_site
.generator/
override_enemies.yaml
override_locations.yaml
override_locations.yaml
presets/Boss Rando.json
11 changes: 2 additions & 9 deletions CLIGen.spec
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


import os, glob, shutil, importlib, khbr

for root, dirs, files in os.walk(DISTPATH):
Expand Down Expand Up @@ -38,7 +35,7 @@ def external_data_recursive(paths):
if dest_dirname == "":
dest_dirname = "."
else:
dest_dirname = dest_dirname.split("site-packages\\")[1]
dest_dirname = dest_dirname.split("site-packages" + os.sep)[1]

data_entry = (filename, dest_dirname)
datas.append(data_entry)
Expand All @@ -62,19 +59,15 @@ updater_analysis = Analysis(
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)

pyz = PYZ(updater_analysis.pure, updater_analysis.zipped_data, cipher=block_cipher)
pyz = PYZ(updater_analysis.pure)

updater_exe = EXE(
pyz,
updater_analysis.scripts,
updater_analysis.binaries,
updater_analysis.zipfiles,
updater_analysis.datas,
[],
name='cli_gen',
Expand Down
13 changes: 12 additions & 1 deletion Class/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,15 @@ class BossEnemyException(Exception):
class BackendException(Exception):
pass

RandomizerExceptions = (GeneratorException,HintException,SettingsException,ValidationException)

class ExternalExecutableException(Exception):
pass


RandomizerExceptions = (
GeneratorException,
HintException,
SettingsException,
ValidationException,
ExternalExecutableException,
)
8 changes: 4 additions & 4 deletions Class/openkhmod.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import re
from copy import deepcopy
from enum import Enum
from enum import StrEnum
from pathlib import PurePath, Path
from typing import Any, Optional, Iterator, Union
from zipfile import ZipFile
Expand Down Expand Up @@ -53,7 +53,7 @@ class ModYmlSyntaxException(ModYmlException):
pass


class AssetMethod(str, Enum):
class AssetMethod(StrEnum):
# https://github.com/OpenKH/OpenKh/blob/8f967bd412a9e7104a5124ae2688815307ba2472/OpenKh.Patcher/Metadata.cs#L96-L107
AREADATASCRIPT = "areadatascript"
BDSCRIPT = "bdscript"
Expand All @@ -67,12 +67,12 @@ class AssetMethod(str, Enum):
SYNTHPATCH = "synthpatch"


class AssetPlatform(str, Enum):
class AssetPlatform(StrEnum):
PC = "pc"
PS2 = "ps2"


class BinarcMethod(str, Enum):
class BinarcMethod(StrEnum):
# Taken from OpenKH docs originally, but found others in use in practice.
# It's not entirely clear whether these are even meant to be a separate entity from the AssetMethod.
AREADATASCRIPT = "areadatascript"
Expand Down
6 changes: 4 additions & 2 deletions Class/seedSettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import string
import textwrap
from dataclasses import dataclass
from enum import Enum
from enum import StrEnum
from typing import Callable, Any

from bitstring import BitArray

from Module import compat as _compat # noqa: F401 - must precede kh2fmbr import
from kh2fmbr.randomizer import Randomizer as khbr

from Class import settingkey
Expand Down Expand Up @@ -55,7 +57,7 @@ def _format_list_for_spoiler(values: list[str]) -> str:
return "(none)"


class SettingGroup(str, Enum):
class SettingGroup(StrEnum):
"""
Serves to provide a rough grouping of settings. Not necessarily meant to designate where things should live in the
seed generator UI; rather, meant to give a way for settings to be grouped for things like the spoiler log.
Expand Down
11 changes: 2 additions & 9 deletions KH2 Randomizer Debug.spec
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


import os, glob, khbr
khbrpath = os.path.dirname(khbr.__file__)
def build_datas_recursive(paths):
Expand Down Expand Up @@ -31,7 +28,7 @@ def external_data_recursive(paths):
if dest_dirname == "":
dest_dirname = "."
else:
dest_dirname = dest_dirname.split("site-packages\\")[1]
dest_dirname = dest_dirname.split("site-packages" + os.sep)[1]

data_entry = (filename, dest_dirname)
datas.append(data_entry)
Expand All @@ -56,20 +53,16 @@ a = Analysis(
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
pyz = PYZ(a.pure)



exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='KH2 Randomizer DEBUG VERSION',
Expand Down
79 changes: 79 additions & 0 deletions KH2 Randomizer Linux.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- mode: python ; coding: utf-8 -*-

# Linux build: a single onedir app (see packaging/linux/build_appimage.sh, which wraps
# the output in an AppImage). Unlike the Windows build there is no separate updater
# executable; linux_main.py dispatches --updater to the updater UI.

import glob
import os

from PyInstaller.utils.hooks import collect_data_files


def build_datas_recursive(paths):
datas = []

for path in paths:
for filename in glob.iglob(path, recursive=True):
if os.path.isfile(filename):
dest_dirname = os.path.dirname(filename)
if dest_dirname == "":
dest_dirname = "."

data_entry = (filename, dest_dirname)
datas.append(data_entry)
print(data_entry)

return datas


a = Analysis(
['linux_main.py'],
pathex=[],
binaries=[],
datas=build_datas_recursive([
'UI/**/*.*',
'UI/*.*',
'static/**/*.*',
'static/*.*',
'presets/*.*',
'Module/icon.png',
'extracted_data.zip',
]) + collect_data_files('kh2fmbr', include_py_files=False),
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)

pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='kh2randomizer',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=False,
upx_exclude=[],
name='kh2randomizer',
)
Loading
Loading