Files
OpenCore-Legacy-Patcher/ci_tooling/build_module/application.py
2024-05-21 10:42:11 -06:00

177 lines
5.7 KiB
Python

import sys
import time
import plistlib
import subprocess
from pathlib import Path
from opencore_legacy_patcher import constants
from opencore_legacy_patcher.support import subprocess_wrapper
class GenerateApplication:
"""
Generate OpenCore-Patcher.app
"""
def __init__(self, reset_pyinstaller_cache: bool = False, git_branch: str = None, git_commit_url: str = None, git_commit_date: str = None, analytics_key: str = None, analytics_endpoint: str = None) -> None:
"""
Initialize
"""
self._pyinstaller = [sys.executable, "-m", "PyInstaller"]
self._application_output = Path("./dist/OpenCore-Patcher.app")
self._reset_pyinstaller_cache = reset_pyinstaller_cache
self._git_branch = git_branch
self._git_commit_url = git_commit_url
self._git_commit_date = git_commit_date
self._analytics_key = analytics_key
self._analytics_endpoint = analytics_endpoint
def _generate_application(self) -> None:
"""
Generate PyInstaller Application
"""
if self._application_output.exists():
subprocess_wrapper.run_and_verify(["/bin/rm", "-rf", self._application_output], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print("Generating OpenCore-Patcher.app")
_args = self._pyinstaller + ["./OpenCore-Patcher-GUI.spec", "--noconfirm"]
if self._reset_pyinstaller_cache:
_args.append("--clean")
subprocess_wrapper.run_and_verify(_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def _embed_analytics_key(self) -> None:
"""
Embed analytics key
"""
_file = Path("./opencore_legacy_patcher/support/analytics_handler.py")
if not all([self._analytics_key, self._analytics_endpoint]):
print("Analytics key or endpoint not provided, skipping embedding")
return
print("Embedding analytics data")
if not Path(_file).exists():
raise FileNotFoundError("analytics_handler.py not found")
lines = []
with open(_file, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if line.startswith("SITE_KEY: str = "):
lines[i] = f"SITE_KEY: str = \"{self._analytics_key}\"\n"
elif line.startswith("ANALYTICS_SERVER: str = "):
lines[i] = f"ANALYTICS_SERVER: str = \"{self._analytics_endpoint}\"\n"
with open(_file, "w") as f:
f.writelines(lines)
def _remove_analytics_key(self) -> None:
"""
Remove analytics key
"""
_file = Path("./opencore_legacy_patcher/support/analytics_handler.py")
if not all([self._analytics_key, self._analytics_endpoint]):
return
print("Removing analytics data")
if not _file.exists():
raise FileNotFoundError("analytics_handler.py not found")
lines = []
with open(_file, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if line.startswith("SITE_KEY: str = "):
lines[i] = "SITE_KEY: str = \"\"\n"
elif line.startswith("ANALYTICS_SERVER: str = "):
lines[i] = "ANALYTICS_SERVER: str = \"\"\n"
with open(_file, "w") as f:
f.writelines(lines)
def _patch_load_command(self):
"""
Patch LC_VERSION_MIN_MACOSX in Load Command to report 10.10
By default Pyinstaller will create binaries supporting 10.13+
However this limitation is entirely arbitrary for our libraries
and instead we're able to support 10.10 without issues.
To verify set version:
otool -l ./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher
cmd LC_VERSION_MIN_MACOSX
cmdsize 16
version 10.13
sdk 10.9
"""
_file = self._application_output / "Contents" / "MacOS" / "OpenCore-Patcher"
_find = b'\x00\x0D\x0A\x00' # 10.13 (0xA0D)
_replace = b'\x00\x0A\x0A\x00' # 10.10 (0xA0A)
print("Patching LC_VERSION_MIN_MACOSX")
with open(_file, "rb") as f:
data = f.read()
data = data.replace(_find, _replace, 1)
with open(_file, "wb") as f:
f.write(data)
def _embed_git_data(self) -> None:
"""
Embed git data
"""
_file = self._application_output / "Contents" / "Info.plist"
_git_branch = self._git_branch or "Built from source"
_git_commit = self._git_commit_url or ""
_git_commit_date = self._git_commit_date or time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print("Embedding git data")
_plist = plistlib.load(_file.open("rb"))
_plist["Github"] = {
"Branch": _git_branch,
"Commit URL": _git_commit,
"Commit Date": _git_commit_date
}
plistlib.dump(_plist, _file.open("wb"), sort_keys=True)
def _embed_resources(self) -> None:
"""
Embed resources
"""
print("Embedding resources")
for file in Path("payloads/Icon/AppIcons").glob("*.icns"):
subprocess_wrapper.run_and_verify(
["/bin/cp", str(file), self._application_output / "Contents" / "Resources/"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
def generate(self) -> None:
"""
Generate OpenCore-Patcher.app
"""
self._embed_analytics_key()
self._generate_application()
self._remove_analytics_key()
self._patch_load_command()
self._embed_git_data()
self._embed_resources()