Michael Chen
5f2c645cb6
Buildkit on arm might not support amd builds Could detect that automatically from buildx inspect
148 lines
6.4 KiB
Python
Executable File
148 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from argparse import ArgumentParser, BooleanOptionalAction
|
|
from datetime import datetime
|
|
from re import search
|
|
from typing import Iterable
|
|
import docker
|
|
from ftbtypes import *
|
|
from jsongetcache import *
|
|
import jsongetcache
|
|
|
|
default_base_url = "https://api.modpacks.ch"
|
|
cache_path = Path("cache")
|
|
|
|
|
|
def get_entity(route: str, base_url: str = default_base_url):
|
|
slashes = '/\\'
|
|
cachefile = cache_path / f"{route.strip(slashes)}.json"
|
|
return jsongetcache.load_cached(base_url + route, cachefile)
|
|
|
|
def get_latest_release(versions: Iterable[ModPackVersion], version_types: list[str] = ["release"]):
|
|
return max((version for version in versions if version["type"].lower() in version_types), key=lambda version: version["updated"], default=None)
|
|
|
|
def get_version_by_id(versions: Iterable[ModPackVersion], version_id: int):
|
|
return next((version for version in versions if version["id"] == version_id), None)
|
|
|
|
def get_version_by_name(versions: Iterable[ModPackVersion], version_name: str):
|
|
return next((version for version in versions if version["name"] == version_name), None)
|
|
|
|
def get_modpack_route(modpack: ModPackManifest | int):
|
|
return f"/public/modpack/{modpack if isinstance(modpack, int) else modpack['id']}"
|
|
|
|
|
|
def get_modpack_manifest(modpack: ModPackManifest | int) -> ModPackManifest:
|
|
return get_entity(get_modpack_route(modpack))
|
|
|
|
|
|
def get_version_route(modpack: ModPackManifest | int, version: ModPackVersion | int):
|
|
return f"{get_modpack_route(modpack)}/{version if isinstance(version, int) else version['id']}"
|
|
|
|
|
|
def get_version_manifest(modpack: ModPackManifest | int, version: ModPackVersion | int) -> ModPackVersionManifest:
|
|
return get_entity(get_version_route(modpack, version))
|
|
|
|
|
|
def version_without_build(version: str):
|
|
print(version)
|
|
match = search(r"^(\d+(.\d+)*)\+(\d+)?$", version)
|
|
if match is None:
|
|
raise Exception(f"Invalid version string: {version}")
|
|
else:
|
|
return match.group(1)
|
|
|
|
|
|
def get_modpack_slug(modpack: ModPackManifest):
|
|
return '-'.join(filter(None, modpack["name"].lower().split(' ')))
|
|
|
|
|
|
def get_installer(modpack: ModPackManifest | int, version: ModPackVersion | int, architecture: docker.Platforms):
|
|
match architecture:
|
|
case "linux/arm64":
|
|
return f"{get_version_route(modpack, version)}/server/arm/linux", "83b9ef3f8b0f525da83c10fd8692c12a6a200c5ce79eba9da97ac29a414232fd"
|
|
case "linux/amd64":
|
|
return f"{get_version_route(modpack, version)}/server/linux", "9c5eed5e160e329bb6c393db549db356b9cc6a9711a5461aba35607b4124485a"
|
|
case _:
|
|
raise Exception(f"Invalid or unsupported architecture {architecture}!")
|
|
|
|
|
|
def parse_arguments():
|
|
parser = ArgumentParser("build.py", description="FTB Docker image build helper.")
|
|
parser.add_argument("modpack", type=int, help="Modpack ID")
|
|
parser.add_argument("--version", "-v", type=str, help="Specific Modpack Version ID, otherwise uses the latest release")
|
|
parser.add_argument("--amd64", action=BooleanOptionalAction, default=True, help="Build releases for AMD64")
|
|
parser.add_argument("--arm64", action=BooleanOptionalAction, default=True, help="Build releases for ARM64")
|
|
return parser.parse_args()
|
|
|
|
def get_version_by_description(modpack: ModPackManifest, version_name: str | None) -> ModPackVersion | None:
|
|
if version_name is None:
|
|
return get_version_by_description(modpack, "release")
|
|
|
|
if version_name.lower() in ["alpha", "beta", "release"]:
|
|
return get_latest_release(modpack["versions"], version_types=[version_name.lower()])
|
|
|
|
match get_version_by_name(modpack["versions"], version_name):
|
|
case None:
|
|
pass
|
|
case idd_version:
|
|
return idd_version
|
|
|
|
try:
|
|
match get_version_by_id(modpack["versions"], int(version_name)):
|
|
case None:
|
|
pass
|
|
case idd_version:
|
|
return idd_version
|
|
except ValueError:
|
|
pass
|
|
|
|
if __name__ == "__main__":
|
|
args = parse_arguments()
|
|
modpack = get_modpack_manifest(args.modpack)
|
|
slug = get_modpack_slug(modpack)
|
|
print("Slug", slug)
|
|
selected_version = get_version_by_description(modpack, args.version)
|
|
if selected_version is None:
|
|
print(f"Available versions for: {modpack['name']}")
|
|
for version in modpack["versions"]:
|
|
print(f"- {version['type']} {version['name']} [{version['id']}]")
|
|
raise Exception(f"No version was found matching \"{args.version}\"")
|
|
version = get_version_manifest(modpack, selected_version)
|
|
print(f"{modpack['name']} version {version['name']}: updated {datetime.fromtimestamp(version['updated'])}")
|
|
|
|
java_target = next((target for target in version["targets"] if target["type"].lower() == "runtime" and target["name"].lower() == "java"), None)
|
|
if java_target is None:
|
|
raise Exception(f"{modpack['name']} version {version['name']} has no java target: {' ,'.join(str(x) for x in version['targets'])}")
|
|
|
|
# java_version = version_without_build(java_target["version"])
|
|
print(f"Required java version is version {java_target['version']}")
|
|
java_version = java_target["version"].replace('+', '_')
|
|
# base_image = f"azul/zulu-openjdk:{java_version}-jre"
|
|
base_image = f"eclipse-temurin:{java_version}-jre"
|
|
print(f"Using docker base image: {base_image}")
|
|
|
|
repo = f"hub.cnml.de/{slug}"
|
|
semver_version_tags = docker.semver_tags(version["name"])
|
|
platforms: list[docker.Platforms] = list(filter(None, [
|
|
"linux/arm64" if args.arm64 else None,
|
|
"linux/amd64" if args.amd64 else None
|
|
]))
|
|
for platform in platforms:
|
|
installer, checksum = get_installer(modpack, version, platform)
|
|
tags = list(f"{ver}-{platform[(platform.rfind('/')+1):]}" for ver in semver_version_tags)
|
|
print(tags)
|
|
print(installer, checksum)
|
|
docker.buildx(repo,
|
|
tags,
|
|
[platform],
|
|
build_args={
|
|
"INSTALLER_URL": default_base_url + installer,
|
|
"INSTALLER_CHECKSUM": checksum,
|
|
"MODPACK_ID": str(modpack["id"]),
|
|
"MODPACK_VERSION": str(version["id"]),
|
|
"BASE_IMAGE": base_image
|
|
},
|
|
write_command=True)
|
|
for version_tag in semver_version_tags:
|
|
tags = list(f"{version_tag}-{platform[(platform.rfind('/')+1):]}" for platform in platforms)
|
|
docker.create_manifest(repo, version_tag, tags, write_command=True)
|