#!/usr/bin/env python3 import hashlib import json import os import subprocess import sys from pathlib import Path def sha256sum(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: for chunk in iter(lambda: handle.read(1024 * 1024), b""): digest.update(chunk) return digest.hexdigest() def parse_platform(name: str) -> str: lowered = name.lower() if "windows" in lowered: return "windows" if "linux" in lowered: return "linux" if "macos" in lowered: return "macosx" raise ValueError(f"Unable to determine platform from filename: {name}") def parse_arch(name: str) -> str: lowered = name.lower() if lowered.startswith("aarch64-") or lowered.startswith("arm64-"): return "arm64" if lowered.startswith("x64-") or lowered.startswith("x86_64-"): return "x64" raise ValueError(f"Unable to determine arch from filename: {name}") def parse_build_type(name: str) -> str: lowered = name.lower() if "debug" in lowered: return "Debug" return "RelWithDebInfo" def build_metadata_entry(path: Path, version: str) -> dict: filename = path.name return { "version": version, "filename": filename, "sha256": sha256sum(path), "lto": "-lto" in filename.lower(), "asan": "-asan" in filename.lower(), "platform": parse_platform(filename), "arch": parse_arch(filename), "build_type": parse_build_type(filename), } def main() -> None: if len(sys.argv) != 4: print( "Usage: upload-llvm.py ", file=sys.stderr ) sys.exit(1) tag, target_repo, workflow_id = sys.argv[1:] artifacts_dir = Path("artifacts") if not artifacts_dir.is_dir(): print(f"Artifacts directory not found: {artifacts_dir}", file=sys.stderr) sys.exit(1) artifact_files = sorted( p for p in artifacts_dir.rglob("*") if p.is_file() and p.suffix.lower() != ".json" ) if not artifact_files: print("No artifacts found to upload.", file=sys.stderr) sys.exit(1) version_without_prefix = tag.lstrip("vV") metadata = [ build_metadata_entry(path, version_without_prefix) for path in artifact_files ] json_path = artifacts_dir / "llvm-manifest.json" with json_path.open("w", encoding="utf-8") as handle: json.dump(metadata, handle, indent=2) handle.write("\n") assets = [str(path) for path in artifact_files] assets.append(str(json_path)) env = os.environ.copy() print(f"Checking for existing release {tag} in {target_repo}...") view_result = subprocess.run( ["gh", "release", "view", tag, "--repo", target_repo], env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) if view_result.returncode == 0: print(f"Deleting existing release {tag} in {target_repo}...") subprocess.run( ["gh", "release", "delete", tag, "--repo", target_repo, "-y"], env=env, check=True, ) print(f"Creating release {tag} in {target_repo} with {len(assets)} assets...") # fmt: off args = [ "gh", "release", "create", tag, *assets, "--repo", target_repo, "--title", tag, "--notes", f"Artifacts build from workflow run https://github.com/clice-io/clice/actions/runs/{workflow_id}", "--latest", ] # fmt: on subprocess.run(args, env=env, check=True) if __name__ == "__main__": main()