|  | 
|  | 1 | +from __future__ import annotations | 
|  | 2 | + | 
|  | 3 | +from abc import ABC | 
|  | 4 | +from pathlib import Path | 
|  | 5 | + | 
|  | 6 | +from virtualenv.create.describe import PosixSupports, WindowsSupports | 
|  | 7 | +from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest, RefMust, RefWhen | 
|  | 8 | +from virtualenv.create.via_global_ref.builtin.via_global_self_do import ViaGlobalRefVirtualenvBuiltin | 
|  | 9 | + | 
|  | 10 | + | 
|  | 11 | +class GraalPy(ViaGlobalRefVirtualenvBuiltin, ABC): | 
|  | 12 | +    @classmethod | 
|  | 13 | +    def can_describe(cls, interpreter): | 
|  | 14 | +        return interpreter.implementation == "GraalVM" and super().can_describe(interpreter) | 
|  | 15 | + | 
|  | 16 | +    @classmethod | 
|  | 17 | +    def exe_stem(cls): | 
|  | 18 | +        return "graalpy" | 
|  | 19 | + | 
|  | 20 | +    @classmethod | 
|  | 21 | +    def exe_names(cls, interpreter): | 
|  | 22 | +        return { | 
|  | 23 | +            cls.exe_stem(), | 
|  | 24 | +            "python", | 
|  | 25 | +            f"python{interpreter.version_info.major}", | 
|  | 26 | +            f"python{interpreter.version_info.major}.{interpreter.version_info.minor}", | 
|  | 27 | +        } | 
|  | 28 | + | 
|  | 29 | +    @classmethod | 
|  | 30 | +    def _executables(cls, interpreter): | 
|  | 31 | +        host = Path(interpreter.system_executable) | 
|  | 32 | +        targets = sorted(f"{name}{cls.suffix}" for name in cls.exe_names(interpreter)) | 
|  | 33 | +        yield host, targets, RefMust.NA, RefWhen.ANY | 
|  | 34 | + | 
|  | 35 | +    @classmethod | 
|  | 36 | +    def sources(cls, interpreter): | 
|  | 37 | +        yield from super().sources(interpreter) | 
|  | 38 | +        python_dir = Path(interpreter.system_executable).resolve().parent | 
|  | 39 | +        if python_dir.name in {"bin", "Scripts"}: | 
|  | 40 | +            python_dir = python_dir.parent | 
|  | 41 | + | 
|  | 42 | +        native_lib = cls._native_lib(python_dir / "lib", interpreter.platform) | 
|  | 43 | +        if native_lib.exists(): | 
|  | 44 | +            yield PathRefToDest(native_lib, dest=lambda self, s: self.bin_dir.parent / "lib" / s.name) | 
|  | 45 | + | 
|  | 46 | +        for jvm_dir_name in ("jvm", "jvmlibs", "modules"): | 
|  | 47 | +            jvm_dir = python_dir / jvm_dir_name | 
|  | 48 | +            if jvm_dir.exists(): | 
|  | 49 | +                yield PathRefToDest(jvm_dir, dest=lambda self, s: self.bin_dir.parent / s.name) | 
|  | 50 | + | 
|  | 51 | +    @classmethod | 
|  | 52 | +    def _shared_libs(cls, python_dir): | 
|  | 53 | +        raise NotImplementedError | 
|  | 54 | + | 
|  | 55 | +    def set_pyenv_cfg(self): | 
|  | 56 | +        super().set_pyenv_cfg() | 
|  | 57 | +        # GraalPy 24.0 and older had home without the bin | 
|  | 58 | +        version = self.interpreter.version_info | 
|  | 59 | +        if version.major == 3 and version.minor <= 10:  # noqa: PLR2004 | 
|  | 60 | +            home = Path(self.pyenv_cfg["home"]) | 
|  | 61 | +            if home.name == "bin": | 
|  | 62 | +                self.pyenv_cfg["home"] = str(home.parent) | 
|  | 63 | + | 
|  | 64 | + | 
|  | 65 | +class GraalPyPosix(GraalPy, PosixSupports): | 
|  | 66 | +    @classmethod | 
|  | 67 | +    def _native_lib(cls, lib_dir, platform): | 
|  | 68 | +        if platform == "darwin": | 
|  | 69 | +            return lib_dir / "libpythonvm.dylib" | 
|  | 70 | +        return lib_dir / "libpythonvm.so" | 
|  | 71 | + | 
|  | 72 | + | 
|  | 73 | +class GraalPyWindows(GraalPy, WindowsSupports): | 
|  | 74 | +    @classmethod | 
|  | 75 | +    def _native_lib(cls, lib_dir, _platform): | 
|  | 76 | +        return lib_dir / "pythonvm.dll" | 
|  | 77 | + | 
|  | 78 | +    def set_pyenv_cfg(self): | 
|  | 79 | +        # GraalPy needs an additional entry in pyvenv.cfg on Windows | 
|  | 80 | +        super().set_pyenv_cfg() | 
|  | 81 | +        self.pyenv_cfg["venvlauncher_command"] = self.interpreter.system_executable | 
|  | 82 | + | 
|  | 83 | + | 
|  | 84 | +__all__ = [ | 
|  | 85 | +    "GraalPyPosix", | 
|  | 86 | +    "GraalPyWindows", | 
|  | 87 | +] | 
0 commit comments