From 5725395ff8c16fbacf4011d93cc5fb4d10f66ce0 Mon Sep 17 00:00:00 2001 From: v0 Date: Sun, 10 May 2026 17:54:41 +0000 Subject: [PATCH] feat: scaffold portablemc 5.x build and packaging Create build scripts and package structure for portablemc 5.x wheel generation Co-authored-by: PythonChicken123 <101510622+PythonChicken123@users.noreply.github.com> --- scripts/jvm_boot_glue.py | 16 ++++++++---- scripts/local_portablemc.py | 51 ++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/scripts/jvm_boot_glue.py b/scripts/jvm_boot_glue.py index 6921806..21f9212 100644 --- a/scripts/jvm_boot_glue.py +++ b/scripts/jvm_boot_glue.py @@ -2240,12 +2240,18 @@ def resolve( """ # Step 1: Ensure portablemc environment is initialized if not _ensure_portablemc_environment(inmemory=inmemory): + pmc_root = _SCRIPTS_DIR / "portablemc" raise RuntimeError( - "portablemc 5.x environment initialization failed.\n" - "Ensure the vendored portablemc tree exists at:\n" - f" {_SCRIPTS_DIR / 'portablemc' / 'portablemc-py' / 'python'}\n" - "Or ensure the wheel is available at:\n" - f" {_SCRIPTS_DIR / 'portablemc' / 'target' / 'wheels'}" + "portablemc 5.x environment initialization failed.\n\n" + "The native extension (_portablemc.pyd) is required but not found.\n\n" + "To fix this, run the build script:\n" + f" python {pmc_root / 'build_wheel.py'}\n\n" + "Requirements:\n" + " - Rust toolchain (https://rustup.rs/)\n" + " - maturin (pip install maturin)\n\n" + "Expected locations after build:\n" + f" - Wheel: {pmc_root / 'target' / 'wheels' / '*.whl'}\n" + f" - Package: {pmc_root / 'portablemc-py' / 'python' / 'portablemc'}" ) # Step 2: Try the Python API diff --git a/scripts/local_portablemc.py b/scripts/local_portablemc.py index 457ccd6..d542154 100644 --- a/scripts/local_portablemc.py +++ b/scripts/local_portablemc.py @@ -54,8 +54,11 @@ def _find_wheel() -> Path | None: """Return the first portablemc wheel found in the target/wheels dir.""" if not _WHEEL_SEARCH.is_dir(): return None - for whl in sorted(_WHEEL_SEARCH.glob("portablemc-*.whl")): - return whl + # Try different wheel naming patterns (maturin uses portablemc_py-*) + patterns = ["portablemc_py-*.whl", "portablemc-*.whl"] + for pattern in patterns: + for whl in sorted(_WHEEL_SEARCH.glob(pattern), reverse=True): + return whl # Return most recent return None @@ -63,35 +66,69 @@ def _pyd_present() -> bool: """True when the native extension already lives in the vendored tree.""" if not _PMC_PKG_DIR.is_dir(): return False - return any(_PMC_PKG_DIR.glob("_portablemc*.pyd")) + # Check for both naming conventions (.pyd for Windows, .so for Linux/Mac) + patterns = ["_portablemc*.pyd", "_portablemc*.so", "portablemc_py*.pyd", "portablemc_py*.so"] + for pattern in patterns: + if any(_PMC_PKG_DIR.glob(pattern)): + return True + return False def _extract_pyd_from_wheel(wheel: Path) -> bool: """ - Extract every file from the wheel's ``portablemc/`` directory into the + Extract every file from the wheel's package directory into the vendored Python tree. Skips dist-info and __pycache__ entries. + The wheel may contain either: + - portablemc/ (if built with package name portablemc) + - portablemc_py/ (if built with maturin default naming) + + Files are renamed appropriately to create a portablemc/ package. + Returns True on success. """ try: _PMC_PKG_DIR.mkdir(parents=True, exist_ok=True) with zipfile.ZipFile(wheel, "r") as zf: extracted = 0 + # Detect the package prefix in the wheel + prefixes = ["portablemc/", "portablemc_py/"] + found_prefix = None + for name in zf.namelist(): + for prefix in prefixes: + if name.startswith(prefix): + found_prefix = prefix + break + if found_prefix: + break + + if not found_prefix: + log.warning("No portablemc package found in wheel %s", wheel.name) + return False + for name in zf.namelist(): - if not name.startswith("portablemc/"): + if not name.startswith(found_prefix): continue if "__pycache__" in name or name.endswith("/"): continue - # Strip the leading "portablemc/" prefix; write relative to _PMC_PKG_DIR - rel = name[len("portablemc/"):] + if ".dist-info" in name: + continue + + # Strip the leading prefix; write relative to _PMC_PKG_DIR + rel = name[len(found_prefix):] if not rel: continue + + # Rename portablemc_py to _portablemc in filenames + rel = rel.replace("portablemc_py", "_portablemc") + dest = _PMC_PKG_DIR / rel dest.parent.mkdir(parents=True, exist_ok=True) data = zf.read(name) dest.write_bytes(data) extracted += 1 log.debug("Extracted %s → %s", name, dest) + log.info("Extracted %d files from %s into %s", extracted, wheel.name, _PMC_PKG_DIR) return extracted > 0 except Exception as exc: