"""Helpers for the temporary psutil-on-Android compatibility installer.""" from __future__ import annotations import shutil import tarfile from pathlib import Path, PurePosixPath # Pin a version we know patches cleanly. Update when a newer psutil # changes the marker line shape and we need to follow upstream. PSUTIL_URL = ( "https://files.pythonhosted.org/packages/aa/c6/" "d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/" "psutil-7.2.2.tar.gz" ) MARKER = 'LINUX = sys.platform.startswith("linux")' REPLACEMENT = 'LINUX = sys.platform.startswith(("linux", "android"))' class PsutilAndroidInstallError(RuntimeError): """Raised when the pinned psutil sdist is missing or unsafe.""" def _normalize_member_parts(member_name: str) -> tuple[str, ...]: path = PurePosixPath(member_name) parts = tuple(part for part in path.parts if part not in ("", ".")) if path.is_absolute() or ".." in parts or not parts: raise PsutilAndroidInstallError( f"Unsafe archive member path: {member_name!r}" ) return parts def _safe_extract_tar_gz(archive: Path, destination: Path) -> None: """Extract a tar.gz without allowing traversal or link members.""" with tarfile.open(archive, "r:gz") as tf: for member in tf.getmembers(): parts = _normalize_member_parts(member.name) target = destination.joinpath(*parts) if member.isdir(): target.mkdir(parents=True, exist_ok=True) continue if not member.isfile(): raise PsutilAndroidInstallError( f"Unsupported archive member type: {member.name}" ) target.parent.mkdir(parents=True, exist_ok=True) extracted = tf.extractfile(member) if extracted is None: raise PsutilAndroidInstallError( f"Cannot read archive member: {member.name}" ) with extracted, open(target, "wb") as dst: shutil.copyfileobj(extracted, dst) try: target.chmod(member.mode & 0o777) except OSError: pass def prepare_patched_psutil_sdist(archive: Path, destination: Path) -> Path: """Safely extract the pinned psutil sdist and patch it for Android.""" _safe_extract_tar_gz(archive, destination) src_roots = sorted( ( path for path in destination.iterdir() if path.is_dir() and path.name.startswith("psutil-") ), key=lambda path: path.name, ) if not src_roots: raise PsutilAndroidInstallError( "psutil sdist did not contain a psutil-* directory" ) src_root = src_roots[0] common_py = src_root / "psutil" / "_common.py" if not common_py.is_file(): raise PsutilAndroidInstallError( f"psutil sdist did not contain {common_py.relative_to(src_root)!s}" ) try: content = common_py.read_text(encoding="utf-8") except OSError as exc: raise PsutilAndroidInstallError( f"Failed to read {common_py.relative_to(src_root)!s}" ) from exc if MARKER not in content: raise PsutilAndroidInstallError( "psutil Android compatibility patch marker not found" ) try: common_py.write_text( content.replace(MARKER, REPLACEMENT), encoding="utf-8", ) except OSError as exc: raise PsutilAndroidInstallError( f"Failed to write {common_py.relative_to(src_root)!s}" ) from exc return src_root