diff options
Diffstat (limited to 'meta/run/generate_java.py')
| -rw-r--r-- | meta/run/generate_java.py | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/meta/run/generate_java.py b/meta/run/generate_java.py new file mode 100644 index 0000000000..95803f21f1 --- /dev/null +++ b/meta/run/generate_java.py @@ -0,0 +1,407 @@ +import copy +import datetime +import os +from typing import Optional +from functools import reduce + +from meta.common import ensure_component_dir, launcher_path, upstream_path + +from meta.common.java import ( + JAVA_MINECRAFT_COMPONENT, + JAVA_ADOPTIUM_COMPONENT, + JAVA_AZUL_COMPONENT, + ADOPTIUM_DIR, + ADOPTIUM_VERSIONS_DIR, + AZUL_DIR, + AZUL_VERSIONS_DIR, +) +from meta.model import MetaPackage +from meta.model.java import ( + JavaRuntimeOS, + JavaRuntimeVersion, + JavaRuntimeMeta, + JavaVersionMeta, + JavaPackageType, + JavaChecksumMeta, + JavaChecksumType, + JavaRuntimeDownloadType, + AdoptiumAvailableReleases, + AdoptiumReleases, + AdoptiumRelease, + AdoptiumImageType, + AdoptiumBinary, + ZuluPackageList, + ZuluPackageDetail, + AzulJavaPackageType, + AzulArch, +) + +from meta.common.mojang import ( + JAVA_MANIFEST_FILE, +) + +from meta.model.mojang import ( + JavaIndex, + MojangJavaComponent, + MojangJavaOsName, + MojangJavaRuntime, +) + +LAUNCHER_DIR = launcher_path() +UPSTREAM_DIR = upstream_path() + + +MOJANG_OS_ARCHITECTURES = [ + "x64", + "x86", + "arm64", + "arm32", +] + +MOJANG_OS_ARCHITECTURE_TRANSLATIONS = { + 64: "x64", + 32: "x86", + "x32": "x86", + "i386": "x86", + "aarch64": "arm64", + "x86_64": "x64", + "arm": "arm32", +} + + +def translate_arch(arch: str | int): + if isinstance(arch, str): + arch = arch.lower() + if arch in MOJANG_OS_ARCHITECTURES: + return arch + elif arch in MOJANG_OS_ARCHITECTURE_TRANSLATIONS: + return MOJANG_OS_ARCHITECTURE_TRANSLATIONS[arch] + else: + return None + + +MOJANG_OS_NAMES = [ + "mac-os", + "linux", + "windows", +] + +MOJANG_OS_TRANSLATIONS = { + "osx": "mac-os", + "mac": "mac-os", + "macos": "mac-os", +} + + +def translate_os(os: str): + os = os.lower() + if os in MOJANG_OS_NAMES: + return os + elif os in MOJANG_OS_TRANSLATIONS: + return MOJANG_OS_TRANSLATIONS[os] + else: + return None + + +def mojang_os_to_java_os(mojang_os: MojangJavaOsName) -> JavaRuntimeOS: + match mojang_os: + case MojangJavaOsName.Linux: + return JavaRuntimeOS.LinuxX64 + case MojangJavaOsName.Linuxi386: + return JavaRuntimeOS.LinuxX86 + case MojangJavaOsName.MacOs: + return JavaRuntimeOS.MacOsX64 + case MojangJavaOsName.MacOSArm64: + return JavaRuntimeOS.MacOsArm64 + case MojangJavaOsName.WindowsArm64: + return JavaRuntimeOS.WindowsArm64 + case MojangJavaOsName.WindowsX64: + return JavaRuntimeOS.WindowsX64 + case MojangJavaOsName.WindowsX86: + return JavaRuntimeOS.WindowsX86 + case _: + return JavaRuntimeOS.Unknown + + +def mojang_runtime_to_java_runtime( + mojang_runtime: MojangJavaRuntime, + mojang_component: MojangJavaComponent, + runtime_os: JavaRuntimeOS, +) -> JavaRuntimeMeta: + major, _, security = mojang_runtime.version.name.partition("u") + if major and security: + version_parts = [int(major), 0, int(security)] + else: + version_parts = [int(part) for part in mojang_runtime.version.name.split(".")] + + while len(version_parts) < 3: + version_parts.append(0) + + build = None + if len(version_parts) >= 4: + build = version_parts[3] + + version = JavaVersionMeta( + major=version_parts[0], + minor=version_parts[1], + security=version_parts[2], + build=build, + name=mojang_runtime.version.name, + ) + return JavaRuntimeMeta( + name=mojang_component, + vendor="mojang", + url=mojang_runtime.manifest.url, + releaseTime=mojang_runtime.version.released, + checksum=JavaChecksumMeta( + type=JavaChecksumType.Sha1, hash=mojang_runtime.manifest.sha1 + ), + downloadType=JavaRuntimeDownloadType.Manifest, + packageType=JavaPackageType.Jre, + version=version, + runtime_os=runtime_os, + ) + + +def adoptium_release_binary_to_java_runtime( + rls: AdoptiumRelease, + binary: AdoptiumBinary, + runtime_os: JavaRuntimeOS, +) -> JavaRuntimeMeta: + assert binary.package is not None + + checksum = None + if binary.package.checksum is not None: + checksum = JavaChecksumMeta( + type=JavaChecksumType.Sha256, hash=binary.package.checksum + ) + + pkg_type = JavaPackageType(str(binary.image_type)) + + version = JavaVersionMeta( + major=rls.version_data.major if rls.version_data.major is not None else 0, + minor=rls.version_data.minor if rls.version_data.minor is not None else 0, + security=( + rls.version_data.security if rls.version_data.security is not None else 0 + ), + build=rls.version_data.build, + ) + rls_name = f"{rls.vendor}_temurin_{binary.image_type}{version}" + return JavaRuntimeMeta( + name=rls_name, + vendor=rls.vendor, + url=binary.package.link, + releaseTime=rls.timestamp, + checksum=checksum, + downloadType=JavaRuntimeDownloadType.Archive, + packageType=pkg_type, + version=version, + runtime_os=runtime_os, + ) + + +def azul_package_to_java_runtime( + pkg: ZuluPackageDetail, runtime_os: JavaRuntimeOS +) -> JavaRuntimeMeta: + version_parts = copy.copy(pkg.java_version) + + build = None + while len(version_parts) < 3: + version_parts.append(0) + + if len(version_parts) >= 4: + build = version_parts[3] + + version = JavaVersionMeta( + major=version_parts[0], + minor=version_parts[1], + security=version_parts[2], + build=build, + ) + + pkg_type = JavaPackageType(str(pkg.java_package_type)) + + rls_name = f"azul_{pkg.product}_{pkg.java_package_type}{version}" + + checksum = None + if pkg.sha256_hash is not None: + checksum = JavaChecksumMeta(type=JavaChecksumType.Sha256, hash=pkg.sha256_hash) + + return JavaRuntimeMeta( + name=rls_name, + vendor="azul", + url=pkg.download_url, + releaseTime=pkg.build_date, + checksum=checksum, + downloadType=JavaRuntimeDownloadType.Archive, + packageType=pkg_type, + version=version, + runtime_os=runtime_os, + ) + + +PREFERED_VENDOR_ORDER = ["mojang", "eclipse", "azul"] + +__PREFERED_VENDOR_ORDER = list(reversed(PREFERED_VENDOR_ORDER)) + + +def vendor_priority(vendor: str) -> int: + """Get a numeric priority for a given vendor + + Args: + vendor (str): the vendor to check + + Returns: + int: how preferable the vendor is, the higher the better + """ + if vendor not in PREFERED_VENDOR_ORDER: + return -1 + return __PREFERED_VENDOR_ORDER.index(vendor) + + +def pkg_type_priority(pkg_type: JavaPackageType) -> int: + match pkg_type: + case JavaPackageType.Jre: + return 2 + case JavaPackageType.Jdk: + return 1 + return -1 + + +def writeJavas(javas: dict[int, list[JavaRuntimeMeta]], uid: str): + def oldest_timestamp(a: datetime.datetime | None, b: datetime.datetime): + if a is None or a > b: + return b + return a + + ensure_component_dir(uid) + + # small hack to sort the versions after major + javas = dict(sorted(javas.items(), key=lambda item: item[0])) + timestamps: dict[int, datetime.datetime | None] = {} + prevDate: datetime.datetime | None = None + for major, runtimes in javas.items(): + releaseTime = reduce( + oldest_timestamp, + (runtime.release_time for runtime in runtimes), + None, + ) + if prevDate is not None and releaseTime < prevDate: + releaseTime = prevDate + datetime.timedelta(seconds=1) + prevDate = releaseTime + timestamps[major] = releaseTime + + for major, runtimes in javas.items(): + version_file = os.path.join(LAUNCHER_DIR, uid, f"java{major}.json") + java_version = JavaRuntimeVersion( + name=f"Java {major}", + uid=uid, + version=f"java{major}", + releaseTime=timestamps.get(major), + runtimes=runtimes, + ) + java_version.write(version_file) + + package = MetaPackage(uid=uid, name="Java Runtimes", recommended=[]) + package.write(os.path.join(LAUNCHER_DIR, uid, "package.json")) + + +def main(): + javas: dict[int, list[JavaRuntimeMeta]] = {} + + def add_java_runtime(runtime: JavaRuntimeMeta, major: int): + if major not in javas: + javas[major] = list[JavaRuntimeMeta]() + print(f"Regestering runtime: {runtime.name} for Java {major}") + javas[major].append(runtime) + + print("Processing Mojang Javas") + mojang_java_manifest = JavaIndex.parse_file( + os.path.join(UPSTREAM_DIR, JAVA_MANIFEST_FILE) + ) + for mojang_os_name in mojang_java_manifest: + if mojang_os_name == MojangJavaOsName.Gamecore: + continue # empty + java_os = mojang_os_to_java_os(mojang_os_name) + for comp in mojang_java_manifest[mojang_os_name]: + if comp == MojangJavaComponent.Exe: + continue # doesn't appear to be used and not marked with a full verison so I don't trust it + mojang_runtimes = mojang_java_manifest[mojang_os_name][comp] + for mojang_runtime in mojang_runtimes: + if comp == MojangJavaComponent.JreLegacy: + major = 8 + else: + major = int(mojang_runtime.version.name.partition(".")[0]) + runtime = mojang_runtime_to_java_runtime(mojang_runtime, comp, java_os) + add_java_runtime(runtime, major) + + writeJavas(javas=javas, uid=JAVA_MINECRAFT_COMPONENT) + javas = {} + + print("Processing Adoptium Releases") + adoptium_path = os.path.join(UPSTREAM_DIR, ADOPTIUM_DIR, "available_releases.json") + if os.path.exists(adoptium_path): + adoptium_available_releases = AdoptiumAvailableReleases.parse_file( + adoptium_path + ) + for major in adoptium_available_releases.available_releases: + adoptium_releases = AdoptiumReleases.parse_file( + os.path.join(UPSTREAM_DIR, ADOPTIUM_VERSIONS_DIR, f"java{major}.json") + ) + for _, rls in adoptium_releases: + for binary in rls.binaries: + if ( + binary.package is None + or binary.image_type is not AdoptiumImageType.Jre + ): + continue + binary_arch = translate_arch(str(binary.architecture)) + binary_os = translate_os(str(binary.os)) + if binary_arch is None or binary_os is None: + print(f"Ignoring release for {binary.os} {binary.architecture}") + continue + + java_os = JavaRuntimeOS(f"{binary_os}-{binary_arch}") + runtime = adoptium_release_binary_to_java_runtime( + rls, binary, java_os + ) + add_java_runtime(runtime, major) + + writeJavas(javas=javas, uid=JAVA_ADOPTIUM_COMPONENT) + javas = {} + print("Processing Azul Packages") + azul_path = os.path.join(UPSTREAM_DIR, AZUL_DIR, "packages.json") + if os.path.exists(azul_path): + azul_packages = ZuluPackageList.parse_file(azul_path) + for _, pkg in azul_packages: + pkg_detail = ZuluPackageDetail.parse_file( + os.path.join( + UPSTREAM_DIR, AZUL_VERSIONS_DIR, f"{pkg.package_uuid}.json" + ) + ) + major = pkg_detail.java_version[0] + if major < 8 or pkg_detail.java_package_type is not AzulJavaPackageType.Jre: + continue # we will never need java versions less than 8 + + pkg_os = translate_os(str(pkg_detail.os)) + if pkg_detail.arch == AzulArch.Arm: + pkg_arch = translate_arch(f"{pkg_detail.arch}{pkg_detail.hw_bitness}") + elif pkg_detail.arch == AzulArch.X86: + pkg_arch = translate_arch(int(pkg_detail.hw_bitness)) + else: + pkg_arch = None + if pkg_arch is None or pkg_os is None: + print( + f"Ignoring release for {pkg_detail.os} {pkg_detail.arch}_{pkg_detail.hw_bitness}" + ) + continue + + java_os = JavaRuntimeOS(f"{pkg_os}-{pkg_arch}") + runtime = azul_package_to_java_runtime(pkg_detail, java_os) + add_java_runtime(runtime, major) + writeJavas(javas=javas, uid=JAVA_AZUL_COMPONENT) + javas = {} + + +if __name__ == "__main__": + main() |
