#! /usr/bin/env python3 """ Build system is designed to created a build targetting a single platform. This script aims at bundle together multiple builds to generate a final multi-platform release. """ import json from pathlib import Path from urllib.request import urlopen import argparse import tarfile from datetime import datetime import os import shutil from urllib.request import urlretrieve from zipfile import ZipFile from concurrent.futures import ThreadPoolExecutor API_REPO_URL = "https://github.com/Relintai/gdnative_python/releases" PLATFORMS = ("x11-32", "x11-64", "osx-64", "windows-32", "windows-64") MISC_DIR = Path(__file__).parent / "../misc" def get_release_info(version=None): data = json.loads(urlopen(API_REPO_URL).read()) if not version: release_info = data[0] else: tag_name = version if version.startswith("v") else f"v{version}" release_info = next(x for x in data if x["tag_name"] == tag_name) info = { "tag_name": release_info["tag_name"], "version": release_info["tag_name"][1:], "platforms": {}, } for platform in PLATFORMS: asset = next((asset for asset in release_info["assets"] if platform in asset["name"]), None) if asset: info["platforms"][platform] = { "name": asset["name"], "url": asset["browser_download_url"], } else: print(f"Warning: release info for platform {platform} not found") return info def pipeline_executor(dirs, release_info, platform_name): platform_info = release_info["platforms"][platform_name] release_archive = dirs["build"] / platform_info["name"] if not release_archive.exists(): print(f"{platform_name} - Dowloading release") with urlopen(platform_info["url"]) as f: release_archive.write_bytes(f.read()) if not (dirs["pythonscript"] / platform_name).exists(): print(f"{platform_name} - Extracting release") if platform_info["name"].endswith(".zip"): zipobj = ZipFile(release_archive) # Only extract platform-specific stuff members = ( x for x in zipobj.namelist() if x.startswith(f"addons/pythonscript/{platform_name}/") ) zipobj.extractall(path=dirs["dist"], members=members) elif platform_info["name"].endswith(".tar.bz2"): tarobj = tarfile.open(release_archive) # Only extract platform-specific stuff members = ( x for x in tarobj if x.name.startswith(f"./addons/pythonscript/{platform_name}/") ) tarobj.extractall(path=dirs["dist"], members=members) else: raise RuntimeError(f"Unknown archive format for {release_archive}") def orchestrator(dirs, release_info): futures = [] with ThreadPoolExecutor() as executor: for platform_name in release_info["platforms"].keys(): futures.append(executor.submit(pipeline_executor, dirs, release_info, platform_name)) for future in futures: if not future.cancelled(): future.result() # Raise exception if any print("Add bonuses...") (dirs["pythonscript"] / ".gdignore").touch() license_txt = (MISC_DIR / "release_LICENSE.txt").read_text() for entry in ["dist", "pythonscript"]: (dirs[entry] / "LICENSE.txt").write_text(license_txt) (dirs["dist"] / "pythonscript.gdnlib").write_text( (MISC_DIR / "release_pythonscript.gdnlib").read_text() ) (dirs["dist"] / "README.txt").write_text( (MISC_DIR / "release_README.txt") .read_text() .format(version=release_info["version"], date=datetime.utcnow().strftime("%Y-%m-%d")) ) def main(): parser = argparse.ArgumentParser() parser.add_argument("--version", default=None) args = parser.parse_args() release_info = get_release_info(args.version) print(f"Release version: {release_info['version']}") build_dir = Path(f"pythonscript-assetlib-release-{release_info['version']}").resolve() dist_dir = build_dir / f"pythonscript-{release_info['version']}" addons_dir = dist_dir / "addons" pythonscript_dir = addons_dir / "pythonscript" build_dir.mkdir(exist_ok=True) dist_dir.mkdir(exist_ok=True) addons_dir.mkdir(exist_ok=True) pythonscript_dir.mkdir(exist_ok=True) dirs = { "build": build_dir, "dist": dist_dir, "addons": addons_dir, "pythonscript": pythonscript_dir, } orchestrator(dirs, release_info) print(f"{dist_dir} is ready !") if __name__ == "__main__": main()