2022-11-21 16:33:29 +01:00
|
|
|
#!/usr/bin/env python3
|
2022-11-21 17:41:15 +01:00
|
|
|
from argparse import ArgumentParser, BooleanOptionalAction
|
2022-11-21 16:33:29 +01:00
|
|
|
from datetime import datetime
|
|
|
|
from re import search
|
2022-11-22 11:14:24 +01:00
|
|
|
from sys import base_prefix
|
2022-11-21 16:33:29 +01:00
|
|
|
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)
|
|
|
|
|
2022-11-21 17:24:57 +01:00
|
|
|
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)
|
2022-11-21 16:33:29 +01:00
|
|
|
|
2022-11-21 17:24:57 +01:00
|
|
|
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)
|
2022-11-21 16:33:29 +01:00
|
|
|
|
|
|
|
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")
|
2022-11-21 17:24:57 +01:00
|
|
|
parser.add_argument("--version", "-v", type=str, help="Specific Modpack Version ID, otherwise uses the latest release")
|
2022-11-21 17:41:15 +01:00
|
|
|
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")
|
2022-11-21 16:33:29 +01:00
|
|
|
return parser.parse_args()
|
|
|
|
|
2022-11-21 17:24:57 +01:00
|
|
|
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
|
|
|
|
|
2022-11-22 11:14:24 +01:00
|
|
|
def find_suitable_tag(java_repository: str, java_version: str, ver_to_tag: Callable[[str], str] = lambda x: f"{x}-jre"):
|
|
|
|
java_tag_version = java_version
|
|
|
|
while True:
|
|
|
|
# base_image = f"azul/zulu-openjdk:{java_version}-jre"
|
|
|
|
java_tag = ver_to_tag(java_tag_version)
|
|
|
|
try:
|
|
|
|
print(f"Trying for image: {java_repository} tag {java_tag}!")
|
|
|
|
docker.buildx_imagetools_inspect(java_repository, java_tag)
|
|
|
|
return java_tag
|
|
|
|
except Exception:
|
|
|
|
print(f"Potential base image {java_repository} missing tag {java_tag}!")
|
|
|
|
if '_' in java_tag_version:
|
|
|
|
java_tag_version = java_tag_version[:(java_tag_version.rfind('_'))]
|
|
|
|
elif '.' in java_tag_version:
|
|
|
|
java_tag_version = java_tag_version[:(java_tag_version.rfind('.'))]
|
|
|
|
else:
|
|
|
|
raise Exception(f"Cannot find suitable java base image version for Java {java_version}")
|
|
|
|
|
2022-11-21 16:33:29 +01:00
|
|
|
if __name__ == "__main__":
|
|
|
|
args = parse_arguments()
|
|
|
|
modpack = get_modpack_manifest(args.modpack)
|
|
|
|
slug = get_modpack_slug(modpack)
|
|
|
|
print("Slug", slug)
|
2022-11-21 17:24:57 +01:00
|
|
|
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)
|
2022-11-21 16:33:29 +01:00
|
|
|
print(f"{modpack['name']} version {version['name']}: updated {datetime.fromtimestamp(version['updated'])}")
|
2022-11-21 17:24:57 +01:00
|
|
|
|
|
|
|
java_target = next((target for target in version["targets"] if target["type"].lower() == "runtime" and target["name"].lower() == "java"), None)
|
2022-11-21 16:33:29 +01:00
|
|
|
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"])
|
2022-11-21 17:24:57 +01:00
|
|
|
print(f"Required java version is version {java_target['version']}")
|
2022-11-21 16:33:29 +01:00
|
|
|
java_version = java_target["version"].replace('+', '_')
|
2022-11-22 11:14:24 +01:00
|
|
|
java_repository = "eclipse-temurin"
|
|
|
|
java_tag = find_suitable_tag(java_repository, java_version)
|
|
|
|
base_image = f"{java_repository}:{java_tag}"
|
2022-11-21 17:24:57 +01:00
|
|
|
print(f"Using docker base image: {base_image}")
|
2022-11-21 16:33:29 +01:00
|
|
|
|
|
|
|
repo = f"hub.cnml.de/{slug}"
|
|
|
|
semver_version_tags = docker.semver_tags(version["name"])
|
2022-11-21 17:41:15 +01:00
|
|
|
platforms: list[docker.Platforms] = list(filter(None, [
|
|
|
|
"linux/arm64" if args.arm64 else None,
|
|
|
|
"linux/amd64" if args.amd64 else None
|
|
|
|
]))
|
2022-11-22 11:14:24 +01:00
|
|
|
|
2022-11-21 16:33:29 +01:00
|
|
|
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)
|