Add jvm search and download support (thanks KiteeLauncher)
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
"""
|
||||
bk_core
|
||||
|
||||
Copyright (c) 2024~2025 Techarerm/TedKai
|
||||
Copyright (c) 2026 Kitee Contributors. All rights reserved.
|
||||
"""
|
||||
import os.path
|
||||
import textwrap
|
||||
import requests
|
||||
|
||||
azul_packages_api = "https://api.azul.com/metadata/v1/zulu/packages"
|
||||
java_manifest_url = 'https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json'
|
||||
|
||||
|
||||
def get_java_build_download_url_from_azul(platform_name: str, full_arch: str, java_major_version: str):
|
||||
full_arch = full_arch.lower()
|
||||
platform_name = platform_name.lower()
|
||||
|
||||
arch_map = {
|
||||
"arm64": "aarch64",
|
||||
"i686": "i686",
|
||||
"amd64": "amd64",
|
||||
"i386": "i686"
|
||||
}
|
||||
|
||||
platform_map = {
|
||||
"macos": "macos",
|
||||
"darwin": "macos",
|
||||
"windows": "windows",
|
||||
"linux": "linux"
|
||||
}
|
||||
|
||||
real_arch = arch_map.get(full_arch, full_arch)
|
||||
platform = platform_map.get(platform_name, platform_name)
|
||||
|
||||
version_type_list = ["jre", "jdk"]
|
||||
|
||||
jre_url = (
|
||||
f"/?java_version={java_major_version}&os={platform}&arch={real_arch}&java_package_type=jre&javafx_bundled=true"
|
||||
f"&release_status=ga&availability_types=CA&certifications=tck&page=1&page_size=100")
|
||||
|
||||
full_jre_url = azul_packages_api + jre_url
|
||||
|
||||
jdk_url = (f"/?java_version={java_major_version}&os={platform}&arch={real_arch}&java_package_type=jdk"
|
||||
f"&javafx_bundled=true"
|
||||
f"&release_status=ga&availability_types=CA&certifications=tck&page=1&page_size=100")
|
||||
|
||||
full_jdk_url = azul_packages_api + jdk_url
|
||||
|
||||
version_url_list = [full_jre_url, full_jdk_url]
|
||||
for url, ver_type in zip(version_url_list, version_type_list):
|
||||
try:
|
||||
response = requests.get(url)
|
||||
data = response.json()
|
||||
java_ver_data = data[0]
|
||||
download_url = java_ver_data.get("download_url", None)
|
||||
|
||||
if download_url is not None:
|
||||
return True, download_url, ver_type
|
||||
|
||||
except Exception as e:
|
||||
print("[ERROR] Getting support jvm download url failed: ", e)
|
||||
return False, None, None
|
||||
|
||||
return False, None, None
|
||||
|
||||
def get_java_version_manifest_data():
|
||||
# Get java manifest
|
||||
try:
|
||||
response = requests.get(java_manifest_url)
|
||||
if response.status_code == 200:
|
||||
manifest_data = response.json()
|
||||
return manifest_data
|
||||
else:
|
||||
return None
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
|
||||
def get_support_java_version(version_data):
|
||||
"""
|
||||
:param version_data: Special minecraft version data
|
||||
:return Status, component, major_version
|
||||
"""
|
||||
try:
|
||||
java_version_info = version_data['javaVersion']
|
||||
component = java_version_info['component']
|
||||
major_version = java_version_info['majorVersion']
|
||||
return True, component, major_version
|
||||
except KeyError:
|
||||
return False, None, None
|
||||
|
||||
|
||||
def get_support_java_version_from_java_version_manifest(platform, full_arch):
|
||||
"""
|
||||
:return SupportList
|
||||
"""
|
||||
|
||||
platform_map = {
|
||||
"darwin": "mac-os",
|
||||
"windows": "windows",
|
||||
"linux": "linux"
|
||||
}
|
||||
|
||||
architecture_map = {
|
||||
"amd64": ["x64"],
|
||||
"i586": ["x86", "i386"],
|
||||
"x86": ["i386", "x86"],
|
||||
"arm64": ["arm64"],
|
||||
"aarch64": ["arm64"]
|
||||
}
|
||||
|
||||
platform_name = platform_map.get(platform.lower(), platform.lower())
|
||||
|
||||
architecture_list = architecture_map.get(full_arch.lower(), full_arch.lower())
|
||||
|
||||
try:
|
||||
response = requests.get(java_manifest_url)
|
||||
except Exception as e:
|
||||
return False, None
|
||||
|
||||
java_manifest_data = response.json()
|
||||
java_manifest_data_cleaned = {}
|
||||
organized_manifest_data_list = []
|
||||
|
||||
# Get all platform data (except item "gamecore")
|
||||
for arch_and_platform, support_java_data in java_manifest_data.items():
|
||||
if arch_and_platform == "gamecore":
|
||||
continue
|
||||
|
||||
java_manifest_data_cleaned.update({arch_and_platform: support_java_data})
|
||||
|
||||
# Separate platform name and arch from arch_and_platform
|
||||
for arch_and_platform, support_java_data in java_manifest_data_cleaned.items():
|
||||
if arch_and_platform == "mac-os":
|
||||
# For mac os (x86-64)
|
||||
java_platform = "mac-os"
|
||||
java_arch = "amd64"
|
||||
elif "-" in arch_and_platform:
|
||||
parts = arch_and_platform.split("-")
|
||||
java_platform = '-'.join(parts[:-1])
|
||||
java_arch = parts[-1]
|
||||
else:
|
||||
java_platform = arch_and_platform
|
||||
java_arch = "amd64"
|
||||
|
||||
for java_runtime_name, runtime_data in support_java_data.items():
|
||||
if not java_runtime_name.startswith("java"):
|
||||
if not java_runtime_name.startswith("jre"):
|
||||
continue
|
||||
|
||||
# Skip some empty data
|
||||
if len(runtime_data) == 0:
|
||||
continue
|
||||
|
||||
# If the platform and architecture are same, append data to list
|
||||
if not java_platform.lower() == platform_name:
|
||||
continue
|
||||
|
||||
if java_arch.lower() not in architecture_list:
|
||||
continue
|
||||
|
||||
# Convert data to dict
|
||||
result = {}
|
||||
for item in runtime_data:
|
||||
result.update(item)
|
||||
organized_manifest_data_list.append(result)
|
||||
|
||||
return organized_manifest_data_list
|
||||
|
||||
|
||||
def get_support_java_runtime_version_data(organized_manifest_data_list, major_version):
|
||||
"""
|
||||
Warning: Require organized_manifest_data_list
|
||||
"""
|
||||
java_version_url = None
|
||||
|
||||
for data in organized_manifest_data_list:
|
||||
name = data.get("version", {}).get("name", None)
|
||||
url = data.get("manifest", {}).get("url", None)
|
||||
if name is None:
|
||||
continue
|
||||
|
||||
if name.startswith(str(major_version)):
|
||||
if url is not None:
|
||||
java_version_url = url
|
||||
|
||||
if java_version_url is not None:
|
||||
try:
|
||||
response = requests.get(java_version_url)
|
||||
data = response.json()
|
||||
|
||||
return True, data
|
||||
except Exception as e:
|
||||
return False, None
|
||||
|
||||
return False, None
|
||||
|
||||
|
||||
def create_java_version_info(java_major_version, java_arch, jvm_runtimes_path):
|
||||
java_info_data = textwrap.dedent(f"""\
|
||||
# Java Runtime Info
|
||||
# This configuration is automatically generated by the BakeLauncher.
|
||||
# Configuration stores Java for the launcher (Example: major_version, architecture).
|
||||
# Do NOT edit this file or delete it!
|
||||
|
||||
JavaMajorVersion = "{java_major_version}"
|
||||
Architecture = "{java_arch}"
|
||||
|
||||
""")
|
||||
|
||||
if not os.path.exists(jvm_runtimes_path):
|
||||
os.makedirs(jvm_runtimes_path)
|
||||
|
||||
java_info_path = os.path.join(jvm_runtimes_path, "java.version.info")
|
||||
|
||||
if not os.path.exists(java_info_path):
|
||||
with open(java_info_path, 'w') as file:
|
||||
file.write(java_info_data)
|
||||
|
||||
|
||||
def read_java_info(info_file_path, item):
|
||||
with open(info_file_path, "r") as file:
|
||||
lines = file.readlines()
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if item in line and '=' in line:
|
||||
data = line.split('=', 1)[1].strip().strip("")
|
||||
return str(data)
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,198 @@
|
||||
"""
|
||||
bk_core
|
||||
|
||||
Copyright (c) 2024~2025 Techarerm/TedKai
|
||||
Copyright (c) 2026 Kitee Contributors. All rights reserved.
|
||||
"""
|
||||
import shutil
|
||||
import os
|
||||
import platform
|
||||
import requests
|
||||
from ..bk_utils.utils import download_file, extract_zip
|
||||
from ..java.java_info import get_java_build_download_url_from_azul
|
||||
from ..bk_utils.crypto import verify_checksum
|
||||
|
||||
|
||||
def download_java_file(file_info, file_path, destination_folder):
|
||||
download_type = "raw"
|
||||
file_url = file_info["downloads"][download_type]["url"]
|
||||
full_file_path = os.path.join(destination_folder, file_path)
|
||||
expected_sha1 = file_info["downloads"][download_type].get("sha1")
|
||||
|
||||
directory = os.path.join(destination_folder, os.path.dirname(file_path))
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
|
||||
if os.path.exists(full_file_path) and expected_sha1 and verify_checksum(full_file_path, expected_sha1):
|
||||
return []
|
||||
|
||||
return download_file(
|
||||
file_url,
|
||||
full_file_path,
|
||||
with_verify=True,
|
||||
sha1=expected_sha1,
|
||||
)
|
||||
|
||||
|
||||
def download_java_runtime_files(manifest, install_path):
|
||||
if not os.path.exists(install_path):
|
||||
return False, "InstallFolderAreNotExist"
|
||||
|
||||
files = manifest.get("files", {})
|
||||
download_tasks = []
|
||||
|
||||
for file_path, file_info in files.items():
|
||||
if file_info.get("type") == "directory":
|
||||
os.makedirs(os.path.join(install_path, file_path), exist_ok=True)
|
||||
continue
|
||||
|
||||
if "downloads" in file_info:
|
||||
download_tasks.extend(download_java_file(file_info, file_path, install_path))
|
||||
|
||||
return True, download_tasks
|
||||
|
||||
|
||||
def install_azul_build_version_jvm(java_major_version, install_dir, full_architecture, platform_name):
|
||||
Status, download_url, version_type = get_java_build_download_url_from_azul(platform_name, full_architecture,
|
||||
java_major_version)
|
||||
|
||||
if not Status:
|
||||
return False, "Get download url failed. Unsupported platform"
|
||||
|
||||
tmp = os.path.join(os.path.dirname(install_dir), ".jvm_installer_tmp")
|
||||
os.makedirs(tmp, exist_ok=True)
|
||||
|
||||
jvm_zip_file_path = os.path.join(tmp, f"jvm-azul-{java_major_version}.zip")
|
||||
|
||||
if os.path.exists(jvm_zip_file_path):
|
||||
try:
|
||||
os.remove(jvm_zip_file_path)
|
||||
except Exception as e:
|
||||
return False, "Cannot delete tmp file. ERR: {}".format(e)
|
||||
|
||||
jvm_unzip_dest = os.path.join(tmp, f"jvm-azul-{java_major_version}-unzipped")
|
||||
if os.path.exists(jvm_unzip_dest):
|
||||
try:
|
||||
shutil.rmtree(jvm_unzip_dest)
|
||||
except Exception as e:
|
||||
return False, "Cannot delete unzip tmp file. ERR: {}".format(e)
|
||||
|
||||
if not os.path.exists(jvm_zip_file_path):
|
||||
try:
|
||||
_download_file_now(download_url, jvm_zip_file_path)
|
||||
except Exception as e:
|
||||
return False, "Download file failed. ERR: {}".format(e)
|
||||
|
||||
extract_zip(jvm_zip_file_path, jvm_unzip_dest)
|
||||
|
||||
if os.path.exists(install_dir):
|
||||
try:
|
||||
shutil.rmtree(install_dir)
|
||||
except Exception as e:
|
||||
return False, f"Cleaning install dir failed. ERR: {e}"
|
||||
|
||||
if platform_name.lower() == "darwin":
|
||||
unzip_list = os.listdir(jvm_unzip_dest)
|
||||
jvm_app_folder_name = unzip_list[0]
|
||||
home_folder_path = os.path.join(jvm_unzip_dest, jvm_app_folder_name, f"zulu-{java_major_version}.jre",
|
||||
"Contents", "Home")
|
||||
if not os.path.isdir(home_folder_path):
|
||||
home_folder_path = _find_java_home(jvm_unzip_dest)
|
||||
if home_folder_path is None:
|
||||
return False, "JAVA_HOME not found in the unzip folder."
|
||||
|
||||
else:
|
||||
unzip_list = os.listdir(jvm_unzip_dest)
|
||||
home_folder_name = unzip_list[0]
|
||||
home_folder_path = os.path.join(jvm_unzip_dest, home_folder_name)
|
||||
if not os.path.isdir(home_folder_path):
|
||||
home_folder_path = _find_java_home(jvm_unzip_dest)
|
||||
if home_folder_path is None:
|
||||
return False, "JAVA_HOME not found in the unzip folder."
|
||||
|
||||
install_root_dir = os.path.dirname(install_dir)
|
||||
home_name = os.path.basename(home_folder_path)
|
||||
dest_path = os.path.join(install_root_dir, home_name)
|
||||
|
||||
try:
|
||||
shutil.move(home_folder_path, install_root_dir)
|
||||
except Exception as e:
|
||||
return False, f"Move home folder to install dir failed. ERR: {e}"
|
||||
|
||||
try:
|
||||
os.rename(dest_path, install_dir)
|
||||
except Exception as e:
|
||||
return False, "Rename dest_path to require name failed. ERR: {}".format(e)
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
def _find_java_home(root):
|
||||
for current_root, _, files in os.walk(root):
|
||||
executable_names = {"java.exe", "javaw.exe"} if os.name == "nt" else {"java"}
|
||||
if os.path.basename(current_root).lower() == "bin" and any(name in executable_names for name in files):
|
||||
return os.path.dirname(current_root)
|
||||
return None
|
||||
|
||||
|
||||
def find_java_home_in_extracted_runtime(unzip_dir):
|
||||
candidates = []
|
||||
for java_name in ("javaw.exe", "java.exe", "java"):
|
||||
candidates.extend(unzip_dir.rglob(java_name))
|
||||
|
||||
for java_path in candidates:
|
||||
parent = java_path.parent
|
||||
if parent.name.lower() == "bin":
|
||||
return parent.parent
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def runtime_java_executable(install_dir):
|
||||
bin_dir = install_dir / "bin"
|
||||
if os.name == "nt":
|
||||
javaw = bin_dir / "javaw.exe"
|
||||
if javaw.exists():
|
||||
return javaw
|
||||
return bin_dir / "java.exe"
|
||||
return bin_dir / "java"
|
||||
|
||||
|
||||
def find_java_runtime_candidates(java_manifest, manifest_platform, java_major_version):
|
||||
platform_data = java_manifest.get(manifest_platform, {})
|
||||
candidates = []
|
||||
for runtime_entries in platform_data.values():
|
||||
for runtime_entry in runtime_entries:
|
||||
version_name = str(runtime_entry.get("version", {}).get("name") or "")
|
||||
if version_name.startswith(str(java_major_version)):
|
||||
candidates.append(runtime_entry)
|
||||
return candidates
|
||||
|
||||
|
||||
def mojang_java_platform_key():
|
||||
system = platform.system().lower()
|
||||
machine = platform.machine().lower()
|
||||
|
||||
if system == "windows":
|
||||
if "arm" in machine or "aarch64" in machine:
|
||||
return "windows-arm64"
|
||||
if "64" in machine or "amd64" in machine:
|
||||
return "windows-x64"
|
||||
return "windows-x86"
|
||||
|
||||
if system == "darwin":
|
||||
return "mac-os-arm64" if "arm" in machine or "aarch64" in machine else "mac-os"
|
||||
|
||||
if system == "linux":
|
||||
return "linux-arm64" if "arm" in machine or "aarch64" in machine else "linux"
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _download_file_now(url, dest_path):
|
||||
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
|
||||
response = requests.get(url, stream=True, timeout=30)
|
||||
response.raise_for_status()
|
||||
with open(dest_path, "wb") as file:
|
||||
for chunk in response.iter_content(chunk_size=1024 * 128):
|
||||
if chunk:
|
||||
file.write(chunk)
|
||||
Reference in New Issue
Block a user