Files
OpenCore-Legacy-Patcher/opencore_legacy_patcher/utilities/updates.py
2024-03-31 21:27:36 -06:00

157 lines
5.3 KiB
Python

"""
updates.py: Check for OpenCore Legacy Patcher binary updates
Call check_binary_updates() to determine if any updates are available
Returns dict with Link and Version of the latest binary update if available
"""
import logging
from typing import Optional, Union
from packaging import version
from .. import constants
from ..utilities import network_handler
REPO_LATEST_RELEASE_URL: str = "https://api.github.com/repos/dortania/OpenCore-Legacy-Patcher/releases/latest"
class CheckBinaryUpdates:
def __init__(self, global_constants: constants.Constants) -> None:
self.constants: constants.Constants = global_constants
try:
self.binary_version = version.parse(self.constants.patcher_version)
except version.InvalidVersion:
assert self.constants.special_build is True, "Invalid version number for binary"
# Special builds will not have a proper version number
self.binary_version = version.parse("0.0.0")
self.latest_details = None
def check_if_newer(self, version: Union[str, version.Version]) -> bool:
"""
Check if the provided version is newer than the local version
Parameters:
version (str): Version to compare against
Returns:
bool: True if the provided version is newer, False if not
"""
if self.constants.special_build is True:
return False
return self._check_if_build_newer(version, self.binary_version)
def _check_if_build_newer(self, first_version: Union[str, version.Version], second_version: Union[str, version.Version]) -> bool:
"""
Check if the first version is newer than the second version
Parameters:
first_version_str (str): First version to compare against (generally local)
second_version_str (str): Second version to compare against (generally remote)
Returns:
bool: True if first version is newer, False if not
"""
if not isinstance(first_version, version.Version):
try:
first_version = version.parse(first_version)
except version.InvalidVersion:
# Special build > release build: assume special build is newer
return True
if not isinstance(second_version, version.Version):
try:
second_version = version.parse(second_version)
except version.InvalidVersion:
# Release build > special build: assume special build is newer
return False
if first_version == second_version:
if not self.constants.commit_info[0].startswith("refs/tags"):
# Check for nightly builds
return True
return first_version > second_version
def _determine_local_build_type(self) -> str:
"""
Check if the local build is a GUI or TUI build
Returns:
str: "GUI" or "TUI"
"""
return "GUI" if self.constants.wxpython_variant else "TUI"
def _determine_remote_type(self, remote_name: str) -> str:
"""
Check if the remote build is a GUI or TUI build
Parameters:
remote_name (str): Name of the remote build
Returns:
str: "GUI" or "TUI"
"""
if "TUI" in remote_name:
return "TUI"
elif "GUI" in remote_name:
return "GUI"
else:
return "Unknown"
def check_binary_updates(self) -> Optional[dict]:
"""
Check if any updates are available for the OpenCore Legacy Patcher binary
Returns:
dict: Dictionary with Link and Version of the latest binary update if available
"""
if self.constants.special_build is True:
# Special builds do not get updates through the updater
return None
if self.latest_details:
# We already checked
return self.latest_details
if not network_handler.NetworkUtilities(REPO_LATEST_RELEASE_URL).verify_network_connection():
return None
response = network_handler.NetworkUtilities().get(REPO_LATEST_RELEASE_URL)
data_set = response.json()
if "tag_name" not in data_set:
return None
# The release marked as latest will always be stable, and thus, have a proper version number
# But if not, let's not crash the program
try:
latest_remote_version = version.parse(data_set["tag_name"])
except version.InvalidVersion:
return None
if not self._check_if_build_newer(latest_remote_version, self.binary_version):
return None
for asset in data_set["assets"]:
logging.info(f"Found asset: {asset['name']}")
if self._determine_remote_type(asset["name"]) == self._determine_local_build_type():
self.latest_details = {
"Name": asset["name"],
"Version": latest_remote_version,
"Link": asset["browser_download_url"],
"Type": self._determine_remote_type(asset["name"]),
"Github Link": f"https://github.com/dortania/OpenCore-Legacy-Patcher/releases/{latest_remote_version}",
}
return self.latest_details
return None