Toolchain: Use docstrings

This commit is contained in:
Mykola Grymalyuk
2023-02-09 18:29:35 -07:00
parent 594f6dcbe5
commit b5b4d84bc9
+135 -72
View File
@@ -1,14 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# This script's main purpose is to handle the following: # Generate stand alone application for OpenCore-Patcher
# - Download PatcherSupportPkg resources # Copyright (C) 2022-2023 - Mykola Grymalyuk
# - Convert payloads directory into DMG (GUI only)
# - Build Binary via Pyinstaller
# - Add Launcher.sh (TUI only)
# - Patch 'LC_VERSION_MIN_MACOSX' to OS X 10.10
# - Add commit data to Info.plist
# Copyright (C) 2022 - Mykola Grymalyuk
from pathlib import Path from pathlib import Path
import time import time
@@ -21,24 +14,48 @@ import sys
from resources import constants from resources import constants
class create_binary: class create_binary:
"""
Library for creating OpenCore-Patcher application
This script's main purpose is to handle the following:
- Download external dependancies (ex. PatcherSupportPkg)
- Convert payloads directory into DMG
- Build Binary via Pyinstaller
- Patch 'LC_VERSION_MIN_MACOSX' to OS X 10.10
- Add commit data to Info.plist
"""
def __init__(self): def __init__(self):
start = time.time() start = time.time()
print("- Starting build script") print("- Starting build script")
self.set_cwd()
self.args = self.parse_arguments()
self.preflight_processes() self.args = self._parse_arguments()
self.build_binary()
self.postflight_processes() self._set_cwd()
self._preflight_processes()
self._build_binary()
self._postflight_processes()
print(f"- Build script completed in {str(round(time.time() - start, 2))} seconds") print(f"- Build script completed in {str(round(time.time() - start, 2))} seconds")
def set_cwd(self):
def _set_cwd(self):
"""
Initialize current working directory to parent of this script
"""
os.chdir(Path(__file__).resolve().parent) os.chdir(Path(__file__).resolve().parent)
print(f"- Current Working Directory: \n\t{os.getcwd()}") print(f"- Current Working Directory: \n\t{os.getcwd()}")
def parse_arguments(self):
def _parse_arguments(self):
"""
Parse arguments passed to script
"""
parser = argparse.ArgumentParser(description='Builds OpenCore-Patcher binary') parser = argparse.ArgumentParser(description='Builds OpenCore-Patcher binary')
parser.add_argument('--branch', type=str, help='Git branch name') parser.add_argument('--branch', type=str, help='Git branch name')
parser.add_argument('--commit', type=str, help='Git commit URL') parser.add_argument('--commit', type=str, help='Git commit URL')
@@ -47,7 +64,12 @@ class create_binary:
args = parser.parse_args() args = parser.parse_args()
return args return args
def setup_pathing(self):
def _setup_pathing(self):
"""
Initialize pathing for pyinstaller
"""
python_path = sys.executable python_path = sys.executable
python_binary = python_path.split("/")[-1] python_binary = python_path.split("/")[-1]
python_bin_dir = python_path.strip(python_binary) python_bin_dir = python_path.strip(python_binary)
@@ -69,21 +91,36 @@ class create_binary:
self.pyinstaller_path = pyinstaller_path self.pyinstaller_path = pyinstaller_path
def preflight_processes(self):
def _preflight_processes(self):
"""
Start preflight processes
"""
print("- Starting preflight processes") print("- Starting preflight processes")
self.setup_pathing() self._setup_pathing()
self.delete_extra_binaries() self._delete_extra_binaries()
self.download_resources() self._download_resources()
self.generate_payloads_dmg() self._generate_payloads_dmg()
def _postflight_processes(self):
"""
Start postflight processes
"""
def postflight_processes(self):
print("- Starting postflight processes") print("- Starting postflight processes")
self.patch_load_command() self._patch_load_command()
self.add_commit_data() self._add_commit_data()
self.post_flight_cleanup() self._post_flight_cleanup()
self.mini_validate() self._mini_validate()
def _build_binary(self):
"""
Build binary via pyinstaller
"""
def build_binary(self):
if Path(f"./dist/OpenCore-Patcher.app").exists(): if Path(f"./dist/OpenCore-Patcher.app").exists():
print("- Found OpenCore-Patcher.app, removing...") print("- Found OpenCore-Patcher.app, removing...")
rm_output = subprocess.run( rm_output = subprocess.run(
@@ -105,7 +142,12 @@ class create_binary:
print(build_result.stderr.decode('utf-8')) print(build_result.stderr.decode('utf-8'))
raise Exception("Build failed") raise Exception("Build failed")
def delete_extra_binaries(self):
def _delete_extra_binaries(self):
"""
Delete extra binaries from payloads directory
"""
delete_files = [ delete_files = [
"AutoPkg-Assets.pkg", "AutoPkg-Assets.pkg",
"AutoPkg-Assets.pkg.zip", "AutoPkg-Assets.pkg.zip",
@@ -113,6 +155,7 @@ class create_binary:
"InstallAssistant.pkg.integrityDataV1", "InstallAssistant.pkg.integrityDataV1",
"KDK.dmg", "KDK.dmg",
] ]
print("- Deleting extra binaries...") print("- Deleting extra binaries...")
for file in Path("payloads").glob(pattern="*"): for file in Path("payloads").glob(pattern="*"):
if file.name in delete_files or file.name.startswith("OpenCore-Legacy-Patcher"): if file.name in delete_files or file.name.startswith("OpenCore-Legacy-Patcher"):
@@ -125,7 +168,12 @@ class create_binary:
print(f" - Deleting {file}") print(f" - Deleting {file}")
subprocess.run(["rm", "-rf", file]) subprocess.run(["rm", "-rf", file])
def download_resources(self):
def _download_resources(self):
"""
Download required dependencies
"""
patcher_support_pkg_version = constants.Constants().patcher_support_pkg_version patcher_support_pkg_version = constants.Constants().patcher_support_pkg_version
required_resources = [ required_resources = [
"Universal-Binaries.zip" "Universal-Binaries.zip"
@@ -172,21 +220,29 @@ class create_binary:
print(mv_output.stderr.decode('utf-8')) print(mv_output.stderr.decode('utf-8'))
raise Exception("Move failed") raise Exception("Move failed")
def generate_payloads_dmg(self):
def _generate_payloads_dmg(self):
"""
Generate disk image containing all payloads
Disk image will be password protected due to issues with
Apple's notarization system and inclusion of kernel extensions
"""
if Path("./payloads.dmg").exists(): if Path("./payloads.dmg").exists():
if self.args.reset_binaries: if not self.args.reset_binaries:
print(" - Removing old payloads.dmg")
rm_output = subprocess.run(
["rm", "-rf", "./payloads.dmg"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
if rm_output.returncode != 0:
print("- Remove failed")
print(rm_output.stderr.decode('utf-8'))
raise Exception("Remove failed")
else:
print(" - payloads.dmg already exists, skipping creation") print(" - payloads.dmg already exists, skipping creation")
return return
print(" - Removing old payloads.dmg")
rm_output = subprocess.run(
["rm", "-rf", "./payloads.dmg"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
if rm_output.returncode != 0:
print("- Remove failed")
print(rm_output.stderr.decode('utf-8'))
raise Exception("Remove failed")
print(" - Generating DMG...") print(" - Generating DMG...")
dmg_output = subprocess.run([ dmg_output = subprocess.run([
'hdiutil', 'create', './payloads.dmg', 'hdiutil', 'create', './payloads.dmg',
@@ -204,7 +260,12 @@ class create_binary:
print(" - DMG generation complete") print(" - DMG generation complete")
def add_commit_data(self):
def _add_commit_data(self):
"""
Add commit data to Info.plist
"""
if not self.args.branch and not self.args.commit and not self.args.commit_date: if not self.args.branch and not self.args.commit and not self.args.commit_date:
print(" - No commit data provided, adding source info") print(" - No commit data provided, adding source info")
branch = "Built from source" branch = "Built from source"
@@ -224,20 +285,25 @@ class create_binary:
} }
plistlib.dump(plist, Path(plist_path).open("wb"), sort_keys=True) plistlib.dump(plist, Path(plist_path).open("wb"), sort_keys=True)
def patch_load_command(self):
# Patches LC_VERSION_MIN_MACOSX in Load Command to report 10.10 def _patch_load_command(self):
# """
# By default Pyinstaller will create binaries supporting 10.13+ Patch LC_VERSION_MIN_MACOSX in Load Command to report 10.10
# However this limitation is entirely arbitrary for our libraries
# and instead we're able to support 10.10 without issues. By default Pyinstaller will create binaries supporting 10.13+
# However this limitation is entirely arbitrary for our libraries
# To verify set version: and instead we're able to support 10.10 without issues.
# otool -l ./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher
# To verify set version:
# cmd LC_VERSION_MIN_MACOSX otool -l ./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher
# cmdsize 16
# version 10.13 cmd LC_VERSION_MIN_MACOSX
# sdk 10.9 cmdsize 16
version 10.13
sdk 10.9
"""
print(" - Patching LC_VERSION_MIN_MACOSX") print(" - Patching LC_VERSION_MIN_MACOSX")
path = './dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher' path = './dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher'
find = b'\x00\x0D\x0A\x00' # 10.13 (0xA0D) find = b'\x00\x0D\x0A\x00' # 10.13 (0xA0D)
@@ -248,19 +314,12 @@ class create_binary:
with open(path, 'wb') as f: with open(path, 'wb') as f:
f.write(data) f.write(data)
def move_launcher(self):
print(" - Adding TUI launcher")
mv_output = subprocess.run(
["cp", "./payloads/launcher.sh", "./dist/OpenCore-Patcher.app/Contents/MacOS/Launcher"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
if mv_output.returncode != 0:
print(" - Move failed")
print(mv_output.stderr.decode('utf-8'))
raise Exception("Move failed")
def post_flight_cleanup(self): def _post_flight_cleanup(self):
# Remove ./dist/OpenCore-Patcher """
Post flight cleanup
"""
path = "./dist/OpenCore-Patcher" path = "./dist/OpenCore-Patcher"
print(f" - Removing {path}") print(f" - Removing {path}")
rm_output = subprocess.run( rm_output = subprocess.run(
@@ -272,9 +331,12 @@ class create_binary:
print(rm_output.stderr.decode('utf-8')) print(rm_output.stderr.decode('utf-8'))
raise Exception(f"Remove failed: {path}") raise Exception(f"Remove failed: {path}")
def mini_validate(self):
# Ensure binary can start def _mini_validate(self):
# Only build a single config, TUI CI will do in-depth validation """
Validate generated binary
"""
print(" - Validating binary") print(" - Validating binary")
validate_output = subprocess.run( validate_output = subprocess.run(
["./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher", "--build", "--model", "MacPro3,1"], ["./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher", "--build", "--model", "MacPro3,1"],
@@ -285,5 +347,6 @@ class create_binary:
print(validate_output.stderr.decode('utf-8')) print(validate_output.stderr.decode('utf-8'))
raise Exception("Validation failed") raise Exception("Validation failed")
if __name__ == "__main__": if __name__ == "__main__":
create_binary() create_binary()