diff --git a/meta/common/__init__.py b/meta/common/__init__.py index 9e623bd..d7ee49a 100644 --- a/meta/common/__init__.py +++ b/meta/common/__init__.py @@ -2,10 +2,11 @@ import os import os.path import datetime from urllib.parse import urlparse +from typing import Any, Optional import requests -from cachecontrol import CacheControl -from cachecontrol.caches import FileCache +from cachecontrol import CacheControl # type: ignore +from cachecontrol.caches import FileCache # type: ignore LAUNCHER_MAVEN = "https://files.prismlauncher.org/maven/%s" @@ -41,7 +42,7 @@ def ensure_upstream_dir(path): os.makedirs(path) -def ensure_component_dir(component_id): +def ensure_component_dir(component_id: str): path = os.path.join(launcher_path(), component_id) if not os.path.exists(path): os.makedirs(path) @@ -51,7 +52,7 @@ def transform_maven_key(maven_key: str): return maven_key.replace(":", ".") -def replace_old_launchermeta_url(url): +def replace_old_launchermeta_url(url: str): o = urlparse(url) if o.netloc == "launchermeta.mojang.com": return o._replace(netloc="piston-meta.mojang.com").geturl() @@ -59,7 +60,7 @@ def replace_old_launchermeta_url(url): return url -def get_all_bases(cls, bases=None): +def get_all_bases(cls: type, bases: Optional[list[type]] = None): bases = bases or [] bases.append(cls) for c in cls.__bases__: @@ -67,10 +68,10 @@ def get_all_bases(cls, bases=None): return tuple(bases) -def merge_dict(base: dict, overlay: dict): +def merge_dict(base: dict[Any, Any], overlay: dict[Any, Any]): for k, v in base.items(): if isinstance(v, dict): - merge_dict(v, overlay.setdefault(k, {})) + merge_dict(v, overlay.setdefault(k, {})) # type: ignore else: if k not in overlay: overlay[k] = v diff --git a/meta/common/java.py b/meta/common/java.py new file mode 100644 index 0000000..ec13b2a --- /dev/null +++ b/meta/common/java.py @@ -0,0 +1,14 @@ +from os.path import join + +BASE_DIR = "java_runtime" + +RELEASE_FILE = join(BASE_DIR, "releases.json") +ADOPTIUM_DIR = join(BASE_DIR, "adoptium") +AZUL_DIR = join(BASE_DIR, "azul") + +ADOPTIUM_VERSIONS_DIR = join(ADOPTIUM_DIR, "versions") +AZUL_VERSIONS_DIR = join(AZUL_DIR, "versions") + +JAVA_MINECRAFT_COMPONENT = "net.minecraft.java" +JAVA_ADOPTIUM_COMPONENT = "net.adoptium.java" +JAVA_AZUL_COMPONENT = "com.azul.java" diff --git a/meta/common/mojang.py b/meta/common/mojang.py index 5fda2e0..fe36c3c 100644 --- a/meta/common/mojang.py +++ b/meta/common/mojang.py @@ -19,3 +19,5 @@ LIBRARY_PATCHES_FILE = join(dirname(__file__), "mojang-library-patches.json") MINECRAFT_COMPONENT = "net.minecraft" LWJGL_COMPONENT = "org.lwjgl" LWJGL3_COMPONENT = "org.lwjgl3" + +JAVA_MANIFEST_FILE = join(BASE_DIR, "java_all.json") diff --git a/meta/model/__init__.py b/meta/model/__init__.py index fb062f5..3d06f99 100644 --- a/meta/model/__init__.py +++ b/meta/model/__init__.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Optional, List, Dict, Any, Iterator import pydantic -from pydantic import Field, validator +from pydantic import Field, validator # type: ignore from ..common import ( LAUNCHER_MAVEN, @@ -87,13 +87,16 @@ class GradleSpecifier: def is_log4j(self): return self.group == "org.apache.logging.log4j" - def __eq__(self, other): - return str(self) == str(other) + def __eq__(self, other: Any): + if isinstance(other, GradleSpecifier): + return str(self) == str(other) + else: + return False - def __lt__(self, other): + def __lt__(self, other: "GradleSpecifier"): return str(self) < str(other) - def __gt__(self, other): + def __gt__(self, other: "GradleSpecifier"): return str(self) > str(other) def __hash__(self): @@ -122,7 +125,7 @@ class GradleSpecifier: return cls(group, artifact, version, classifier, extension) @classmethod - def validate(cls, v): + def validate(cls, v: "str | GradleSpecifier"): if isinstance(v, cls): return v if isinstance(v, str): @@ -131,7 +134,7 @@ class GradleSpecifier: class MetaBase(pydantic.BaseModel): - def dict(self, **kwargs) -> Dict[str, Any]: + def dict(self, **kwargs: Any) -> Dict[str, Any]: for k in ["by_alias"]: if k in kwargs: del kwargs[k] @@ -147,12 +150,12 @@ class MetaBase(pydantic.BaseModel): exclude_none=True, sort_keys=True, by_alias=True, indent=4, **kwargs ) - def write(self, file_path): + def write(self, file_path: str): Path(file_path).parent.mkdir(parents=True, exist_ok=True) with open(file_path, "w") as f: f.write(self.json()) - def merge(self, other): + def merge(self, other: "MetaBase"): """ Merge other object with self. - Concatenates lists @@ -176,14 +179,14 @@ class MetaBase(pydantic.BaseModel): elif isinstance(ours, set): ours |= theirs elif isinstance(ours, dict): - result = merge_dict(ours, copy.deepcopy(theirs)) + result = merge_dict(ours, copy.deepcopy(theirs)) # type: ignore setattr(self, key, result) elif MetaBase in get_all_bases(field.type_): ours.merge(theirs) else: setattr(self, key, theirs) - def __hash__(self): + def __hash__(self): # type: ignore return hash(self.json()) class Config: @@ -194,7 +197,7 @@ class MetaBase(pydantic.BaseModel): class Versioned(MetaBase): @validator("format_version") - def format_version_must_be_supported(cls, v): + def format_version_must_be_supported(cls, v: int): assert v <= META_FORMAT_VERSION return v @@ -209,7 +212,7 @@ class MojangArtifactBase(MetaBase): class MojangAssets(MojangArtifactBase): @validator("url") - def validate_url(cls, v): + def validate_url(cls, v: str): return replace_old_launchermeta_url(v) id: str @@ -245,7 +248,7 @@ class MojangLibraryDownloads(MetaBase): class OSRule(MetaBase): @validator("name") - def name_must_be_os(cls, v): + def name_must_be_os(cls, v: str): assert v in [ "osx", "linux", @@ -263,7 +266,7 @@ class OSRule(MetaBase): class MojangRule(MetaBase): @validator("action") - def action_must_be_allow_disallow(cls, v): + def action_must_be_allow_disallow(cls, v: str): assert v in ["allow", "disallow"] return v @@ -274,10 +277,10 @@ class MojangRule(MetaBase): class MojangRules(MetaBase): __root__: List[MojangRule] - def __iter__(self) -> Iterator[MojangRule]: + def __iter__(self) -> Iterator[MojangRule]: # type: ignore return iter(self.__root__) - def __getitem__(self, item) -> MojangRule: + def __getitem__(self, item: int) -> MojangRule: return self.__root__[item] @@ -316,6 +319,7 @@ class MetaVersion(Versioned): minecraft_arguments: Optional[str] = Field(alias="minecraftArguments") release_time: Optional[datetime] = Field(alias="releaseTime") compatible_java_majors: Optional[List[int]] = Field(alias="compatibleJavaMajors") + compatible_java_name: Optional[str] = Field(alias="compatibleJavaName") additional_traits: Optional[List[str]] = Field(alias="+traits") additional_tweakers: Optional[List[str]] = Field(alias="+tweakers") additional_jvm_args: Optional[List[str]] = Field(alias="+jvmArgs") diff --git a/meta/model/enum.py b/meta/model/enum.py new file mode 100644 index 0000000..08dda4b --- /dev/null +++ b/meta/model/enum.py @@ -0,0 +1,32 @@ +import enum + + +class StrEnum(str, enum.Enum): + """ + StrEnum is a Python ``enum.Enum`` that inherits from ``str``. The default + ``auto()`` behavior uses the member name as its value. + + Example usage:: + + class Example(StrEnum): + UPPER_CASE = auto() + lower_case = auto() + MixedCase = auto() + + assert Example.UPPER_CASE == "UPPER_CASE" + assert Example.lower_case == "lower_case" + assert Example.MixedCase == "MixedCase" + """ + + def __new__(cls, value, *args, **kwargs): + if not isinstance(value, (str, enum.auto)): + raise TypeError( + f"Values of StrEnums must be strings: {value!r} is a {type(value)}" + ) + return super().__new__(cls, value, *args, **kwargs) + + def __str__(self): + return str(self.value) + + def _generate_next_value_(name, *_): + return name diff --git a/meta/model/java.py b/meta/model/java.py new file mode 100644 index 0000000..e24932e --- /dev/null +++ b/meta/model/java.py @@ -0,0 +1,558 @@ +from . import ( + MetaBase, + MetaVersion, + Versioned, +) +from pydantic import Field +from datetime import datetime +from enum import IntEnum, Enum +from .enum import StrEnum +from typing import Optional, Any, NamedTuple, Generator +from urllib.parse import urlencode, urlparse, urlunparse +from functools import total_ordering + +# namedtuple to match the internal signature of urlunparse + + +class JavaRuntimeOS(StrEnum): + MacOsX64 = "mac-os-x64" + MacOsX86 = "mac-os-x86" # rare + MacOsArm64 = "mac-os-arm64" + # MacOsArm32 = "mac-os-arm32" # doesn't exsist + LinuxX64 = "linux-x64" + LinuxX86 = "linux-x86" + LinuxArm64 = "linux-arm64" + LinuxArm32 = "linux-arm32" + WindowsX64 = "windows-x64" + WindowsX86 = "windows-x86" + WindowsArm64 = "windows-arm64" + WindowsArm32 = "windows-arm32" + Unknown = "unknown" + + +class JavaRuntimeDownloadType(StrEnum): + Manifest = "manifest" + Archive = "archive" + + +@total_ordering +class JavaVersionMeta(MetaBase): + major: int + minor: int + security: int + build: Optional[int] = None + name: Optional[str] = None + + def __str__(self): + ver = f"{self.major}.{self.minor}.{self.security}" + if self.build is not None: + ver = f"{ver}+{self.build}" + return ver + + def to_tuple(self): + build = 0 + if self.build is not None: + build = self.build + return (self.major, self.minor, self.security, build) + + def __eq__(self, other: Any): + return self.to_tuple() == other.to_tuple() + + def __lt__(self, other: "JavaVersionMeta"): + return self.to_tuple() < other.to_tuple() + + +class JavaChecksumType(StrEnum): + Sha1 = "sha1" + Sha256 = "sha256" + + +class JavaChecksumMeta(MetaBase): + type: JavaChecksumType + hash: str + + +class JavaPackageType(StrEnum): + Jre = "jre" + Jdk = "jdk" + + +class JavaRuntimeMeta(MetaBase): + name: str + vendor: str + url: str + release_time: datetime = Field(alias="releaseTime") + checksum: Optional[JavaChecksumMeta] + download_type: JavaRuntimeDownloadType = Field(alias="downloadType") + package_type: JavaPackageType = Field(alias="packageType") + version: JavaVersionMeta + runtime_os: JavaRuntimeOS = Field(alias="runtimeOS") + + +class JavaRuntimeVersion(MetaVersion): + runtimes: list[JavaRuntimeMeta] + + +class URLComponents(NamedTuple): + scheme: str + netloc: str + url: str + path: str + query: str + fragment: str + + +class APIQuery(MetaBase): + def to_query(self): + set_parts: dict[str, Any] = {} + for key, value in self.dict().items(): + if value is not None: + if isinstance(value, Enum): + set_parts[key] = value.value + elif isinstance(value, list): + if len(value) > 0: # type: ignore + set_parts[key] = value + elif isinstance(value, datetime): + set_parts[key] = value.isoformat() + else: + set_parts[key] = value + return urlencode(set_parts, doseq=True) + + +class AdoptiumJvmImpl(StrEnum): + Hostspot = "hotspot" + + +class AdoptiumVendor(StrEnum): + Eclipse = "eclipse" + + +class AdoptiumArchitecture(StrEnum): + X64 = "x64" + X86 = "x86" + X32 = "x32" + Ppc64 = "ppc64" + Ppc64le = "ppc64le" + S390x = "s390x" + Aarch64 = "aarch64" + Arm = "arm" + Sparcv9 = "sparcv9" + Riscv64 = "riscv64" + + +class AdoptiumReleaseType(StrEnum): + GenralAccess = "ga" + EarlyAccess = "ea" + + +class AdoptiumSortMethod(StrEnum): + Default = "DEFAULT" + Date = "DATE" + + +class AdoptiumSortOrder(StrEnum): + Asc = "ASC" + Desc = "DESC" + + +class AdoptiumImageType(StrEnum): + Jdk = "jdk" + Jre = "jre" + Testimage = "testimage" + Debugimage = "debugimage" + Staticlibs = "staticlibs" + Sources = "sources" + Sbom = "sbom" + + +class AdoptiumHeapSize(StrEnum): + Normal = "normal" + Large = "large" + + +class AdoptiumProject(StrEnum): + Jdk = "jdk" + Valhalla = "valhalla" + Metropolis = "metropolis" + Jfr = "jfr" + Shenandoah = "shenandoah" + + +class AdoptiumCLib(StrEnum): + Musl = "musl" + Glibc = "glibc" + + +class AdoptiumOs(StrEnum): + Linux = "linux" + Windows = "windows" + Mac = "mac" + Solaris = "solaris" + Aix = "aix" + AlpineLinux = "alpine-linux" + + +ADOPTIUM_API_BASE = " https://api.adoptium.net" +ADOPTIUM_API_FEATURE_RELEASES = f"{ADOPTIUM_API_BASE}/v3/assets/feature_releases/{{feature_version}}/{{release_type}}" +# ?image_type={{image_type}}&heap_size={{heap_size}}&project={{project}}&vendor={{vendor}}&page_size={{page_size}}&page={{page}}&sort_method={{sort_method}}&sort_order={{sort_order}} +ADOPTIUM_API_AVAILABLE_RELEASES = f"{ADOPTIUM_API_BASE}/v3/info/available_releases" + + +class AdoptiumAPIFeatureReleasesQuery(APIQuery): + architecture: Optional[AdoptiumArchitecture] = None + before: Optional[datetime] = None + c_lib: Optional[AdoptiumCLib] = None + heap_size: Optional[AdoptiumHeapSize] = AdoptiumHeapSize.Normal + image_type: Optional[AdoptiumImageType] = None + jvm_impl: Optional[AdoptiumJvmImpl] = None + os: Optional[AdoptiumOs] = None + page_size: int = 10 + page: int = 0 + project: Optional[AdoptiumProject] = AdoptiumProject.Jdk + sort_method: Optional[AdoptiumSortMethod] = AdoptiumSortMethod.Default + sort_order: Optional[AdoptiumSortOrder] = AdoptiumSortOrder.Desc + vendor: Optional[AdoptiumVendor] = AdoptiumVendor.Eclipse + + +def adoptiumAPIFeatureReleasesUrl( + feature: int, + release_type: AdoptiumReleaseType = AdoptiumReleaseType.GenralAccess, + query: AdoptiumAPIFeatureReleasesQuery = AdoptiumAPIFeatureReleasesQuery(), +): + url = urlparse( + ADOPTIUM_API_FEATURE_RELEASES.format( + feature_version=feature, + release_type=release_type.value, + ) + ) + return urlunparse(url._replace(query=query.to_query())) + + +class AdoptiumAvailableReleases(MetaBase): + available_releases: list[int] + available_lts_releases: list[int] + most_recent_lts: Optional[int] + most_recent_feature_release: Optional[int] + most_recent_feature_version: Optional[int] + tip_version: Optional[int] + + +class AdoptiumFile(MetaBase): + name: str + link: str + size: Optional[int] + + +class AdoptiumPackage(AdoptiumFile): + checksum: Optional[str] + checksum_link: Optional[str] + signature_link: Optional[str] + download_count: Optional[int] + metadata_link: Optional[str] + + +class AdoptiumBinary(MetaBase): + os: str + architecture: AdoptiumArchitecture + image_type: AdoptiumImageType + c_lib: Optional[AdoptiumCLib] + jvm_impl: AdoptiumJvmImpl + package: Optional[AdoptiumPackage] + installer: Optional[AdoptiumPackage] + heap_size: AdoptiumHeapSize + download_count: Optional[int] + updated_at: datetime + scm_ref: Optional[str] + project: AdoptiumProject + + +class AdoptiumVersion(MetaBase): + major: Optional[int] + minor: Optional[int] + security: Optional[int] + patch: Optional[int] + pre: Optional[str] + adopt_build_number: Optional[int] + semver: str + openjdk_version: str + build: Optional[int] + optional: Optional[str] + + +class AdoptiumRelease(MetaBase): + release_id: str = Field(alias="id") + release_link: str + release_name: str + timestamp: datetime + updated_at: datetime + binaries: list[AdoptiumBinary] + download_count: Optional[int] + release_type: str + vendor: AdoptiumVendor + version_data: AdoptiumVersion + source: Optional[AdoptiumFile] + release_notes: Optional[AdoptiumFile] + + +class AdoptiumReleases(MetaBase): + __root__: list[AdoptiumRelease] + + def __iter__(self) -> Generator[tuple[str, AdoptiumRelease], None, None]: + yield from ((str(i), val) for i, val in enumerate(self.__root__)) + + def __getitem__(self, item: int) -> AdoptiumRelease: + return self.__root__[item] + + def append(self, rls: AdoptiumRelease): + self.__root__.append(rls) + + +class AzulProduct(StrEnum): + Zulu = "zulu" + + +class AzulAvailabilityType(StrEnum): + SA = "SA" + CA = "CA" + NV = "NV" + _LA = "LA" + + +class AzulJavaPackageType(StrEnum): + Jdk = "jdk" + Jre = "jre" + + +class AzulReleaseType(StrEnum): + CPU = "CPU" + PSU = "PSU" + LU = "LU" + + +class AzulOs(StrEnum): + Linux = "linux" + Macos = "macos" + Qnx = "qnx" + Windows = "windows" + Solaris = "solaris" + + +class AzulLibCType(StrEnum): + Glibc = "glibc" + Uclibc = "uclibc" + Musl = "musl" + + +class AzulCPUGen(StrEnum): + V5 = "v5" + V6kV6kz = "v6k_v6kz" + V6t2 = "v6t2" + V7 = "v7" + V8 = "v8" + + +class AzulArch(StrEnum): + Arm = "arm" + X86 = "x86" + Mips = "mips" + Ppc = "ppc" + Sparcv9 = "sparcv9" + Sparc = "sparc" + + +class AzulHwBitness(IntEnum): + X32 = 32 + X64 = 64 + + +class AzulAbi(StrEnum): + HardFloat = "hard_float" + SoftFloat = "soft_float" + Spe = "spe" + Any = "any" + + +class AzulArchiveType(StrEnum): + Deb = "deb" + Rpm = "rpm" + Dmg = "dmg" + Targz = "tar.gz" + Zip = "zip" + Cab = "cab" + Msi = "msi" + + +class AzulReleaseStatus(StrEnum): + Eval = "eval" + Ea = "ea" + Ga = "ga" + Both = "both" + + +class AzulSupportTerm(StrEnum): + Sts = "sts" + Mts = "mts" + Lts = "lts" + + +class AzulCertifications(StrEnum): + Tck = "tck" + _Aqavit = "aqavit" + none = "none" + + +class AzulSignatureType(StrEnum): + Openpgp = "openpgp" + + +class AzulOsQueryParam(StrEnum): + Macos = "macos" + Windows = "windows" + Linux = "linux" + LinuxMusl = "linux-musl" + LinuxGlibc = "linux-glibc" + Qnx = "qnx" + Solaris = "solaris" + + +class AzulArchQueryParam(StrEnum): + X86 = "x86" + X64 = "x64" + Amd64 = "amd64" + I686 = "i686" + Arm = "arm" + Aarch64 = "aarch64" + Aarch32 = "aarch32" + Aarch32sf = "aarch32sf" + Aarch32hf = "aarch32hf" + Ppc = "ppc" + Ppc64 = "ppc64" + Ppc64hf = "ppc64hf" + Ppc32 = "ppc32" + Ppc32spe = "ppc32spe" + Ppc32hf = "ppc32hf" + Sparc = "sparc" + Sparc32 = "sparc32" + Sparcv9 = "sparcv9" + Sparcv9_64 = "sparcv9-64" + + +AZUL_API_BASE = "https://api.azul.com/metadata/v1" +AZUL_API_PACKAGES = f"{AZUL_API_BASE}/zulu/packages/" +AZUL_API_PACKAGE_DETAIL = f"{AZUL_API_BASE}/zulu/packages/{{package_uuid}}" + + +class AzulApiPackagesQuery(APIQuery): + java_version: Optional[str] = None + os: Optional[AzulOsQueryParam] = None + arch: Optional[AzulArchQueryParam] = None + archive_type: Optional[AzulArchiveType] = None + java_package_type: Optional[AzulJavaPackageType] = None + javafx_bundled: Optional[bool] = None + crac_supported: Optional[bool] = None + support_term: Optional[AzulSupportTerm] = None + release_type: Optional[AzulReleaseType] = None + latest: Optional[bool] = None + distro_version: Optional[str] = None + java_package_features: list[str] = [] + release_status: Optional[AzulReleaseStatus] = None + availability_types: list[AzulAvailabilityType] = [] + certifications: list[AzulCertifications] = [] + include_fields: list[str] = [] + page: int = 0 + page_size: int = 100 + + +def azulApiPackagesUrl(query: AzulApiPackagesQuery = AzulApiPackagesQuery()): + url = urlparse(AZUL_API_PACKAGES) + return urlunparse(url._replace(query=query.to_query())) + + +def azulApiPackageDetailUrl(package_uuid: str): + return AZUL_API_PACKAGE_DETAIL.format(package_uuid=package_uuid) + + +class ZuluSignatureDetail(MetaBase): + type: AzulSignatureType + url: str + details: dict[str, Any] + signature_index: int + signature: str + + +class ZuluPackageDetail(MetaBase): + package_uuid: str + name: Optional[str] + md5_hash: Optional[str] + sha256_hash: Optional[str] + build_date: datetime + last_modified: datetime + download_url: str + product: AzulProduct + availability_type: AzulAvailabilityType + java_version: list[int] + openjdk_build_number: Optional[int] + java_package_type: AzulJavaPackageType + javafx_bundled: bool + release_type: AzulReleaseType + os: AzulOs + lib_c_type: Optional[AzulLibCType] + cpu_gen: Optional[list[AzulCPUGen]] + arch: AzulArch + hw_bitness: AzulHwBitness + abi: AzulAbi + archive_type: AzulArchiveType + release_status: AzulReleaseStatus + support_term: AzulSupportTerm + certifications: Optional[list[AzulCertifications]] + latest: Optional[bool] + size: int + distro_version: list[int] + signatures: list[ZuluSignatureDetail] + + +class ZuluPackage(MetaBase): + package_uuid: str + name: Optional[str] + java_version: list[int] + openjdk_build_number: Optional[int] + latest: Optional[bool] + download_url: str + product: Optional[AzulProduct] + distro_version: list[int] + availability_type: Optional[AzulAvailabilityType] + + +class ZuluPackageList(MetaBase): + __root__: list[ZuluPackage] + + def __iter__(self) -> Generator[tuple[str, ZuluPackage], None, None]: + yield from ((str(i), val) for i, val in enumerate(self.__root__)) + + def __getitem__(self, item: int) -> ZuluPackage: + return self.__root__[item] + + def append(self, pkg: ZuluPackage): + self.__root__.append(pkg) + + +class ZuluPackagesDetail(MetaBase): + __root__: list[ZuluPackageDetail] + + def __iter__(self) -> Generator[tuple[str, ZuluPackageDetail], None, None]: + yield from ((str(i), val) for i, val in enumerate(self.__root__)) + + def __getitem__(self, item: int) -> ZuluPackageDetail: + return self.__root__[item] + + def append(self, pkg: ZuluPackageDetail): + self.__root__.append(pkg) + + +MOJANG_OS_NAMES = ["mac-os", "linux", "windows"] + +MOJANG_OS_ARCHITECTURES = [ + "x64" "x86", + "arm64", + "arm32", +] diff --git a/meta/model/mojang.py b/meta/model/mojang.py index 221f8e0..6fb71e7 100644 --- a/meta/model/mojang.py +++ b/meta/model/mojang.py @@ -1,5 +1,6 @@ from datetime import datetime from typing import Optional, List, Dict, Any, Iterator +from .enum import StrEnum from pydantic import validator, Field @@ -17,6 +18,9 @@ from . import ( SUPPORTED_LAUNCHER_VERSION = 21 SUPPORTED_COMPLIANCE_LEVEL = 1 DEFAULT_JAVA_MAJOR = 8 # By default, we should recommend Java 8 if we don't know better +DEFAULT_JAVA_NAME = ( + "jre-legacy" # By default, we should recommend Java 8 if we don't know better +) COMPATIBLE_JAVA_MAPPINGS = {16: [17]} SUPPORTED_FEATURES = ["is_quick_play_multiplayer"] @@ -193,11 +197,74 @@ class MojangLogging(MetaBase): type: str +class MojangJavaComponent(StrEnum): + JreLegacy = "jre-legacy" + Alpha = "java-runtime-alpha" + Beta = "java-runtime-beta" + Gamma = "java-runtime-gamma" + GammaSnapshot = "java-runtime-gamma-snapshot" + Exe = "minecraft-java-exe" + Delta = "java-runtime-delta" + + class JavaVersion(MetaBase): - component: str = "jre-legacy" + component: MojangJavaComponent = MojangJavaComponent.JreLegacy major_version: int = Field(8, alias="majorVersion") +class MojangJavaIndexAvailability(MetaBase): + group: int + progress: int + + +class MojangJavaIndexManifest(MetaBase): + sha1: str + size: int + url: str + + +class MojangJavaIndexVersion(MetaBase): + name: str + released: datetime + + +class MojangJavaRuntime(MetaBase): + availability: MojangJavaIndexAvailability + manifest: MojangJavaIndexManifest + version: MojangJavaIndexVersion + + +class MojangJavaIndexEntry(MetaBase): + __root__: dict[MojangJavaComponent, list[MojangJavaRuntime]] + + def __iter__(self) -> Iterator[MojangJavaComponent]: + return iter(self.__root__) + + def __getitem__(self, item) -> list[MojangJavaRuntime]: + return self.__root__[item] + + +class MojangJavaOsName(StrEnum): + Gamecore = "gamecore" + Linux = "linux" + Linuxi386 = "linux-i386" + MacOs = "mac-os" + MacOSArm64 = "mac-os-arm64" + WindowsArm64 = "windows-arm64" + WindowsX64 = "windows-x64" + WindowsX86 = "windows-x86" + + +class JavaIndex(MetaBase): + __root__: dict[MojangJavaOsName, MojangJavaIndexEntry] + + def __iter__(self) -> Iterator[MojangJavaOsName]: + return iter(self.__root__) + + def __getitem__(self, item) -> MojangJavaIndexEntry: + return self.__root__[item] + + class MojangVersion(MetaBase): @validator("minimum_launcher_version") def validate_minimum_launcher_version(cls, v): @@ -256,10 +323,12 @@ class MojangVersion(MetaBase): raise Exception(f"Unsupported compliance level {self.compliance_level}") major = DEFAULT_JAVA_MAJOR + javaName = DEFAULT_JAVA_NAME if ( self.javaVersion is not None ): # some versions don't have this. TODO: maybe maintain manual overrides major = self.javaVersion.major_version + javaName = self.javaVersion.component compatible_java_majors = [major] if ( @@ -281,6 +350,7 @@ class MojangVersion(MetaBase): release_time=self.release_time, type=new_type, compatible_java_majors=compatible_java_majors, + compatible_java_name=javaName, additional_traits=addn_traits, main_jar=main_jar, ) diff --git a/meta/run/generate_java.py b/meta/run/generate_java.py new file mode 100644 index 0000000..fd32308 --- /dev/null +++ b/meta/run/generate_java.py @@ -0,0 +1,481 @@ +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_component_to_major(mojang_component: MojangJavaComponent) -> int: + match mojang_component: + case MojangJavaComponent.JreLegacy: + return 8 + case MojangJavaComponent.Alpha: + return 17 + case MojangJavaComponent.Beta: + return 17 + case MojangJavaComponent.Gamma: + return 17 + case MojangJavaComponent.GammaSnapshot: + return 17 + case MojangJavaComponent.Exe: + return 0 + case MojangJavaComponent.Delta: + return 21 + case _: + return 0 + + +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, + ) + + +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]] = {} + extra_mojang_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) + + # only add specific versions to the list + if ( + ( + runtime.runtime_os + in [JavaRuntimeOS.MacOsArm64, JavaRuntimeOS.WindowsArm64] + and major == 8 + ) + or ( + runtime.runtime_os + in [ + JavaRuntimeOS.WindowsArm32, + JavaRuntimeOS.LinuxArm32, + JavaRuntimeOS.LinuxArm64, + ] + and major in [8, 17, 21] + ) + or (runtime.runtime_os == JavaRuntimeOS.LinuxX86 and major in [17, 21]) + ): + if major not in extra_mojang_javas: + extra_mojang_javas[major] = list[JavaRuntimeMeta]() + extra_mojang_javas[major].append(runtime) + + 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 = {} + + # constructs the missing mojang javas based on adoptium or azul + def get_mojang_extra_java( + mojang_component: MojangJavaComponent, java_os: JavaRuntimeOS + ) -> JavaRuntimeMeta | None: + java_major = mojang_component_to_major(mojang_component) + if not java_major in extra_mojang_javas: + return None + posible_javas = list( + filter(lambda x: x.runtime_os == java_os, extra_mojang_javas[java_major]) + ) + if len(posible_javas) == 0: + return None + prefered_vendor = list(filter(lambda x: x.vendor != "azul", posible_javas)) + if len(prefered_vendor) == 0: + prefered_vendor = posible_javas + prefered_vendor.sort(key=lambda x: x.version, reverse=True) + runtime = prefered_vendor[0] + runtime.name = mojang_component + return 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] + if len(mojang_runtimes) == 0: + if mojang_os_name in [ + MojangJavaOsName.WindowsArm64, + MojangJavaOsName.MacOSArm64, + ]: + if comp in [MojangJavaComponent.Alpha, MojangJavaComponent.Beta]: + mojang_runtimes = mojang_java_manifest[mojang_os_name][ + MojangJavaComponent.Gamma + ] + elif ( + comp == MojangJavaComponent.JreLegacy + ): # arm version of win and mac is missing the legacy java + runtime = get_mojang_extra_java(comp, java_os) + if runtime != None: + add_java_runtime(runtime, mojang_component_to_major(comp)) + if ( + mojang_os_name == MojangJavaOsName.Linuxi386 + and comp != MojangJavaComponent.JreLegacy + ): # the linux x86 is missing all but legacy + runtime = get_mojang_extra_java(comp, java_os) + if runtime != None: + add_java_runtime(runtime, mojang_component_to_major(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) + # mojang doesn't provide any versions for the following systems so borrow info from adoptium/azul + for java_os in [ + JavaRuntimeOS.WindowsArm32, + JavaRuntimeOS.LinuxArm32, + JavaRuntimeOS.LinuxArm64, + ]: + for comp in [ + MojangJavaComponent.JreLegacy, + MojangJavaComponent.Alpha, + MojangJavaComponent.Beta, + MojangJavaComponent.Gamma, + MojangJavaComponent.GammaSnapshot, + MojangJavaComponent.Delta, + ]: + runtime = get_mojang_extra_java(comp, java_os) + if runtime != None: + add_java_runtime(runtime, mojang_component_to_major(comp)) + + writeJavas(javas=javas, uid=JAVA_MINECRAFT_COMPONENT) + javas = {} + + +if __name__ == "__main__": + main() diff --git a/meta/run/update_java.py b/meta/run/update_java.py new file mode 100644 index 0000000..326fb5f --- /dev/null +++ b/meta/run/update_java.py @@ -0,0 +1,158 @@ +import os + +from meta.common import upstream_path, ensure_upstream_dir, default_session +from meta.common.java import ( + BASE_DIR, + ADOPTIUM_DIR, + AZUL_DIR, + ADOPTIUM_VERSIONS_DIR, + AZUL_VERSIONS_DIR, +) +from meta.model.java import ( + ADOPTIUM_API_AVAILABLE_RELEASES, + adoptiumAPIFeatureReleasesUrl, + AdoptiumImageType, + AdoptiumAPIFeatureReleasesQuery, + AdoptiumAvailableReleases, + AdoptiumRelease, + AdoptiumReleases, + azulApiPackagesUrl, + AzulApiPackagesQuery, + ZuluPackage, + ZuluPackageList, + AzulArchiveType, + AzulReleaseStatus, + AzulAvailabilityType, + AzulJavaPackageType, + azulApiPackageDetailUrl, + ZuluPackageDetail, + ZuluPackagesDetail, +) + +UPSTREAM_DIR = upstream_path() + +ensure_upstream_dir(BASE_DIR) +ensure_upstream_dir(ADOPTIUM_DIR) +ensure_upstream_dir(AZUL_DIR) +ensure_upstream_dir(ADOPTIUM_VERSIONS_DIR) +ensure_upstream_dir(AZUL_VERSIONS_DIR) + + +sess = default_session() + + +def main(): + print("Getting Adoptium Release Manifests ") + r = sess.get(ADOPTIUM_API_AVAILABLE_RELEASES) + r.raise_for_status() + + available = AdoptiumAvailableReleases(**r.json()) + + available_releases_file = os.path.join( + UPSTREAM_DIR, ADOPTIUM_DIR, "available_releases.json" + ) + available.write(available_releases_file) + + for feature in available.available_releases: + print("Getting Manifests for Adoptium feature release:", feature) + + page_size = 10 + + releases_for_feature: list[AdoptiumRelease] = [] + page = 0 + while True: + query = AdoptiumAPIFeatureReleasesQuery( + image_type=AdoptiumImageType.Jre, page_size=page_size, page=page + ) + api_call = adoptiumAPIFeatureReleasesUrl(feature, query=query) + print("Fetching JRE Page:", page, api_call) + r_rls = sess.get(api_call) + if r_rls.status_code == 404: + break + else: + r_rls.raise_for_status() + + releases = list(AdoptiumRelease(**rls) for rls in r_rls.json()) + releases_for_feature.extend(releases) + + if len(r_rls.json()) < page_size: + break + page += 1 + + print("Total Adoptium releases for feature:", len(releases_for_feature)) + releases = AdoptiumReleases(__root__=releases_for_feature) + feature_file = os.path.join( + UPSTREAM_DIR, ADOPTIUM_VERSIONS_DIR, f"java{feature}.json" + ) + releases.write(feature_file) + + print("Getting Azul Release Manifests") + zulu_packages: list[ZuluPackage] = [] + page = 1 + page_size = 100 + while True: + + query = AzulApiPackagesQuery( + archive_type=AzulArchiveType.Zip, + release_status=AzulReleaseStatus.Ga, + availability_types=[AzulAvailabilityType.CA], + java_package_type=AzulJavaPackageType.Jre, + javafx_bundled=False, + latest=True, + page=page, + page_size=page_size, + ) + api_call = azulApiPackagesUrl(query=query) + + print("Processing Page:", page, api_call) + + r = sess.get(api_call) + if r.status_code == 404: + break + else: + r.raise_for_status() + + packages = list(ZuluPackage(**pkg) for pkg in r.json()) + zulu_packages.extend(packages) + if len(packages) < page_size: + break + page += 1 + + print("Total Azul Packages:", len(zulu_packages)) + packages = ZuluPackageList(__root__=zulu_packages) + azul_manifest_file = os.path.join(UPSTREAM_DIR, AZUL_DIR, "packages.json") + packages.write(azul_manifest_file) + + azul_major_versions: dict[int, ZuluPackagesDetail] = {} + + for _, pkg in packages: + + major_version = pkg.java_version[0] + if major_version not in azul_major_versions: + azul_major_versions[major_version] = ZuluPackagesDetail(__root__=[]) + + pkg_file = os.path.join( + UPSTREAM_DIR, AZUL_VERSIONS_DIR, f"{pkg.package_uuid}.json" + ) + if os.path.exists(pkg_file) and os.path.isfile(pkg_file): + pkg_detail = ZuluPackageDetail.parse_file(pkg_file) + azul_major_versions[major_version].append(pkg_detail) + else: + + api_call = azulApiPackageDetailUrl(pkg.package_uuid) + print("Fetching Azul package manifest:", pkg.package_uuid) + r_pkg = sess.get(api_call) + r_pkg.raise_for_status() + + pkg_detail = ZuluPackageDetail(**r_pkg.json()) + pkg_detail.write(pkg_file) + azul_major_versions[major_version].append(pkg_detail) + + for major in azul_major_versions: + major_file = os.path.join(UPSTREAM_DIR, AZUL_VERSIONS_DIR, f"java{major}.json") + azul_major_versions[major].write(major_file) + + +if __name__ == "__main__": + main() +# diff --git a/meta/run/update_mojang.py b/meta/run/update_mojang.py index defc371..ddadc16 100755 --- a/meta/run/update_mojang.py +++ b/meta/run/update_mojang.py @@ -12,6 +12,7 @@ from meta.common.mojang import ( ASSETS_DIR, STATIC_EXPERIMENTS_FILE, STATIC_OLD_SNAPSHOTS_FILE, + JAVA_MANIFEST_FILE, ) from meta.model.mojang import ( MojangIndexWrap, @@ -20,6 +21,7 @@ from meta.model.mojang import ( ExperimentIndexWrap, OldSnapshotIndexWrap, OldSnapshotIndex, + JavaIndex, ) UPSTREAM_DIR = upstream_path() @@ -81,6 +83,20 @@ def fetch_version(path, url): return version_json +MOJANG_JAVA_URL = "https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json" + + +def update_javas(): + r = sess.get(MOJANG_JAVA_URL) + r.raise_for_status() + + remote_javas = JavaIndex(__root__=r.json()) + + java_manifest_path = os.path.join(UPSTREAM_DIR, JAVA_MANIFEST_FILE) + + remote_javas.write(java_manifest_path) + + def fetch_version_concurrent(remote_versions, x): version = remote_versions.versions[x] print( @@ -165,6 +181,9 @@ def main(): remote_versions.index.write(version_manifest_path) + print("Getting Mojang Java runtime manfest") + update_javas() + if __name__ == "__main__": main() diff --git a/pyproject.toml b/pyproject.toml index ca55558..10cf5dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,12 +16,14 @@ generateLiteloader = "meta.run.generate_liteloader:main" generateMojang = "meta.run.generate_mojang:main" generateNeoForge = "meta.run.generate_neoforge:main" generateQuilt = "meta.run.generate_quilt:main" +generateJava = "meta.run.generate_java:main" updateFabric = "meta.run.update_fabric:main" updateForge = "meta.run.update_forge:main" updateLiteloader = "meta.run.update_liteloader:main" updateMojang = "meta.run.update_mojang:main" updateNeoForge = "meta.run.update_neoforge:main" updateQuilt = "meta.run.update_quilt:main" +updateJava = "meta.run.update_java:main" index = "meta.run.index:main" [tool.poetry.dependencies] diff --git a/update.sh b/update.sh index 40d885b..8e0fe38 100755 --- a/update.sh +++ b/update.sh @@ -10,21 +10,21 @@ export META_CACHE_DIR=${CACHE_DIRECTORY:-./caches} export META_UPSTREAM_DIR=${META_UPSTREAM_DIR:-${STATE_DIRECTORY:-.}/upstream} export META_LAUNCHER_DIR=${META_LAUNCHER_DIR:-${STATE_DIRECTORY:-.}/launcher} -function fail_in { +function fail_in() { upstream_git reset --hard HEAD exit 1 } -function fail_out { +function fail_out() { launcher_git reset --hard HEAD exit 1 } -function upstream_git { +function upstream_git() { git -C "${META_UPSTREAM_DIR}" "$@" } -function launcher_git { +function launcher_git() { git -C "${META_LAUNCHER_DIR}" "$@" } @@ -40,15 +40,17 @@ python -m meta.run.update_neoforge || fail_in python -m meta.run.update_fabric || fail_in python -m meta.run.update_quilt || fail_in python -m meta.run.update_liteloader || fail_in +python -m meta.run.update_java || fail_in -if [ "${DEPLOY_TO_GIT}" = true ] ; then - upstream_git add mojang/version_manifest_v2.json mojang/versions/* || fail_in +if [ "${DEPLOY_TO_GIT}" = true ]; then + upstream_git add mojang/version_manifest_v2.json mojang/java_all.json mojang/versions/* || fail_in upstream_git add forge/*.json forge/version_manifests/*.json forge/installer_manifests/*.json forge/files_manifests/*.json forge/installer_info/*.json || fail_in upstream_git add neoforge/*.json neoforge/version_manifests/*.json neoforge/installer_manifests/*.json neoforge/files_manifests/*.json neoforge/installer_info/*.json || fail_in upstream_git add fabric/loader-installer-json/*.json fabric/meta-v2/*.json fabric/jars/*.json || fail_in upstream_git add quilt/loader-installer-json/*.json quilt/meta-v3/*.json quilt/jars/*.json || fail_in upstream_git add liteloader/*.json || fail_in - if ! upstream_git diff --cached --exit-code ; then + upstream_git add java_runtime/adoptium/available_releases.json java_runtime/adoptium/versions/*.json java_runtime/azul/packages.json java_runtime/azul/versions/*.json || fail_in + if ! upstream_git diff --cached --exit-code; then upstream_git commit -a -m "Update ${currentDate}" || fail_in upstream_git push || exit 1 fi @@ -62,23 +64,25 @@ python -m meta.run.generate_neoforge || fail_out python -m meta.run.generate_fabric || fail_out python -m meta.run.generate_quilt || fail_out python -m meta.run.generate_liteloader || fail_out +python -m meta.run.generate_java || fail_out python -m meta.run.index || fail_out -if [ "${DEPLOY_TO_GIT}" = true ] ; then +if [ "${DEPLOY_TO_GIT}" = true ]; then launcher_git add index.json org.lwjgl/* org.lwjgl3/* net.minecraft/* || fail_out launcher_git add net.minecraftforge/* || fail_out launcher_git add net.neoforged/* || fail_out launcher_git add net.fabricmc.fabric-loader/* net.fabricmc.intermediary/* || fail_out - launcher_git add org.quiltmc.quilt-loader/* || fail_out # TODO: add Quilt hashed, once it is actually used + launcher_git add org.quiltmc.quilt-loader/* || fail_out # TODO: add Quilt hashed, once it is actually used launcher_git add com.mumfrey.liteloader/* || fail_out + launcher_git add net.minecraft.java/* net.adoptium.java/* com.azul.java/* || fail_out - if ! launcher_git diff --cached --exit-code ; then + if ! launcher_git diff --cached --exit-code; then launcher_git commit -a -m "Update ${currentDate}" || fail_out launcher_git push || exit 1 fi fi -if [ "${DEPLOY_TO_FOLDER}" = true ] ; then +if [ "${DEPLOY_TO_FOLDER}" = true ]; then echo "Deploying to ${DEPLOY_FOLDER}" rsync -rvog --chown="${DEPLOY_FOLDER_USER}:${DEPLOY_FOLDER_GROUP}" --exclude=.git "${LAUNCHER_DIR}/" "${DEPLOY_FOLDER}" fi