link cpython
This commit is contained in:
parent
c93c182953
commit
9f2ac70cc8
|
@ -31,6 +31,7 @@ import logging
|
|||
import os
|
||||
import platform
|
||||
import re
|
||||
import site
|
||||
import shlex
|
||||
import shutil
|
||||
import socket
|
||||
|
@ -168,6 +169,8 @@ OBJ_GRAPHIC = 'SwXTextGraphicObject'
|
|||
OBJ_TEXTS = 'SwXTextRanges'
|
||||
OBJ_TEXT = 'SwXTextRange'
|
||||
IS_FLATPAK = bool(os.getenv("FLATPAK_ID", ""))
|
||||
IS_APP_IMAGE = bool(os.getenv("APPIMAGE", ""))
|
||||
|
||||
|
||||
|
||||
# ~ from com.sun.star.sheet.FilterOperator import EMPTY, NO_EMPTY, EQUAL, NOT_EQUAL
|
||||
|
@ -636,15 +639,60 @@ def sleep(seconds):
|
|||
time.sleep(seconds)
|
||||
return
|
||||
|
||||
def get_flatpak_site_packages_dir() -> str:
|
||||
# should never be all users
|
||||
sand_box = os.getenv("FLATPAK_SANDBOX_DIR", "") or str(
|
||||
Path.home() / ".var/app/org.libreoffice.LibreOffice/sandbox"
|
||||
)
|
||||
|
||||
|
||||
def get_site_packages_dir() -> str:
|
||||
"""Gets the site-packages folder for the current user."""
|
||||
major_minor = f"{sys.version_info.major}.{sys.version_info.minor}"
|
||||
site_packages = Path(sand_box) / f"lib/python{major_minor}/site-packages"
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_windows_site_packages_dir() -> str:
|
||||
nonlocal major_minor
|
||||
if site.USER_SITE:
|
||||
site_packages = Path(site.USER_SITE).resolve()
|
||||
else:
|
||||
site_packages = (
|
||||
Path.home() / f"'/AppData/Roaming/Python/Python{major_minor}/site-packages'"
|
||||
)
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_flatpak_site_packages_dir() -> str:
|
||||
# should never be all users
|
||||
nonlocal major_minor
|
||||
sand_box = os.getenv("FLATPAK_SANDBOX_DIR", "") or str(
|
||||
Path.home() / ".var/app/org.libreoffice.LibreOffice/sandbox"
|
||||
)
|
||||
site_packages = Path(sand_box) / f"lib/python{major_minor}/site-packages"
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_mac_site_packages_dir() -> str:
|
||||
nonlocal major_minor
|
||||
if site.USER_SITE:
|
||||
site_packages = Path(site.USER_SITE).resolve()
|
||||
else:
|
||||
site_packages = (
|
||||
Path.home() / f"Library/LibreOfficePython/{major_minor}/lib/python/site-packages"
|
||||
)
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_default_site_packages_dir() -> str:
|
||||
nonlocal major_minor
|
||||
if site.USER_SITE:
|
||||
site_packages = Path(site.USER_SITE).resolve()
|
||||
else:
|
||||
site_packages = Path.home() / f".local/lib/python{major_minor}/site-packages"
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
if IS_WIN:
|
||||
return get_windows_site_packages_dir()
|
||||
if IS_MAC:
|
||||
return get_mac_site_packages_dir()
|
||||
if IS_FLATPAK:
|
||||
return get_flatpak_site_packages_dir()
|
||||
return get_default_site_packages_dir()
|
||||
|
||||
class TimerThread(threading.Thread):
|
||||
|
||||
|
@ -6206,8 +6254,7 @@ class Paths(object):
|
|||
elif IS_MAC:
|
||||
path = self.join(self.config('Module'), '..', 'Resources', PYTHON)
|
||||
else:
|
||||
is_app_image = bool(os.getenv("APPIMAGE", ""))
|
||||
if is_app_image:
|
||||
if IS_APP_IMAGE:
|
||||
path = self.join(self.config("Module"), PYTHON)
|
||||
else:
|
||||
path = sys.executable
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
"""
|
||||
On some systems such as Mac and AppImage (Linux) the python extension suffix does not match the
|
||||
cpython suffix used by the embedded python interpreter.
|
||||
|
||||
This class creates symlinks for all .so files in dest folder that match the current python embedded suffix.
|
||||
|
||||
For example a file named ``indexers.cpython-38-x86_64-linux-gnu.so`` would be symlinked to ``indexers.cpython-3.8.so``.
|
||||
This renaming allows the python interpreter to find the import.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
from importlib import machinery
|
||||
import easymacro as app
|
||||
|
||||
|
||||
class LinkCPython:
|
||||
def __init__(self, pth: str) -> None:
|
||||
"""
|
||||
Constructor
|
||||
|
||||
Args:
|
||||
pth (str): Path to site-packages folder.
|
||||
"""
|
||||
self._current_suffix = self._get_current_suffix()
|
||||
app.debug("CPythonLink.__init__")
|
||||
self._link_root = Path(pth)
|
||||
if not self._link_root.exists():
|
||||
raise FileNotFoundError(f"Path does not exist {self._link_root}")
|
||||
app.debug("CPythonLink.__init__ done")
|
||||
|
||||
def _get_current_suffix(self) -> str:
|
||||
"""Gets suffix currently used by the embedded python interpreter such as ``cpython-3.8``"""
|
||||
for suffix in machinery.EXTENSION_SUFFIXES:
|
||||
if suffix.startswith(".cpython-") and suffix.endswith(".so"):
|
||||
# remove leading . and trailing .so
|
||||
return suffix[1:][:-3]
|
||||
return ""
|
||||
|
||||
def _get_all_files(self, path: Path) -> List[Path]:
|
||||
return [p for p in path.glob(f"**/*{self.file_suffix}.so") if p.is_file()]
|
||||
|
||||
def _get_all_links(self, path: Path) -> List[Path]:
|
||||
return [p for p in path.glob(f"**/*{self.current_suffix}.so") if p.is_symlink()]
|
||||
|
||||
def _create_symlink(self, src: Path, dst: Path, overwrite: bool) -> None:
|
||||
if dst.is_symlink():
|
||||
if overwrite:
|
||||
app.debug(f"Removing existing symlink {dst}")
|
||||
dst.unlink()
|
||||
else:
|
||||
app.debug(f"Symlink already exists {dst}")
|
||||
return
|
||||
dst.symlink_to(src)
|
||||
app.debug(f"Created symlink {dst} -> {src}")
|
||||
|
||||
def _find_current_installed_suffix(self, path: Path) -> str:
|
||||
"""
|
||||
Finds the current suffix from the current installed python so files such as ``cpython-38-x86_64-linux-gnu``.
|
||||
|
||||
Args:
|
||||
path (Path): Path to search in. Usually site-packages.
|
||||
|
||||
Returns:
|
||||
str: suffix if found, otherwise empty string.
|
||||
"""
|
||||
return next(
|
||||
(str(p).rsplit(".", 2)[1] for p in path.glob("**/*.cpython-*.so") if not p.is_symlink()),
|
||||
"",
|
||||
)
|
||||
|
||||
def link(self, overwrite:bool = False) -> None:
|
||||
"""
|
||||
Creates symlinks for all .so files in site-packages that match the current suffix.
|
||||
|
||||
Args:
|
||||
overwrite (bool, optional): Override any existing sys links. Defaults to False.
|
||||
"""
|
||||
app.debug("CPythonLink.link starting")
|
||||
if not self._link_root:
|
||||
app.debug("No site-packages found")
|
||||
return
|
||||
if not self.file_suffix:
|
||||
app.debug("No current file suffix found")
|
||||
return
|
||||
if not self._link_root.exists():
|
||||
app.debug(f"Site-packages does not exist {self._link_root}")
|
||||
return
|
||||
app.debug(f"Python current suffix: {self._current_suffix}")
|
||||
app.debug(f"Found file suffix: {self.file_suffix}")
|
||||
files = self._get_all_files(self._link_root)
|
||||
if not files:
|
||||
app.debug(f"No files found in {self._link_root}")
|
||||
return
|
||||
cp_old = self.file_suffix
|
||||
cp_new = self._current_suffix
|
||||
if cp_old == cp_new:
|
||||
app.debug(f"Suffixes match, no need to link: {cp_old} == {cp_new}")
|
||||
return
|
||||
|
||||
for file in files:
|
||||
ln_name = file.name.replace(cp_old, cp_new)
|
||||
src = file
|
||||
if not src.is_absolute():
|
||||
src = file.resolve()
|
||||
dst = src.parent / ln_name
|
||||
self._create_symlink(src, dst, overwrite)
|
||||
app.debug("CPythonLink.link done")
|
||||
|
||||
def unlink(self) -> None:
|
||||
"""Unlinks all broken sys links"""
|
||||
links = self._get_all_links(self._link_root)
|
||||
if not links:
|
||||
app.debug(f"No links found in {self._link_root}")
|
||||
return
|
||||
for link in links:
|
||||
if not link.exists():
|
||||
app.debug(f"Removing broken symlink {link}")
|
||||
link.unlink()
|
||||
|
||||
|
||||
# region Properties
|
||||
@property
|
||||
def cpy_name(self) -> str:
|
||||
"""Gets/Sets CPython name, e.g. cpython-3.8"""
|
||||
return self._current_suffix
|
||||
|
||||
@cpy_name.setter
|
||||
def cpy_name(self, value: str) -> None:
|
||||
self._current_suffix = value
|
||||
|
||||
@property
|
||||
def current_suffix(self) -> str:
|
||||
"""Current Suffix such as ``cpython-3.8``"""
|
||||
return self._current_suffix
|
||||
|
||||
@property
|
||||
def file_suffix(self) -> str:
|
||||
"""Current Suffix such as ``cpython-38-x86_64-linux-gnu``"""
|
||||
try:
|
||||
return self._file_suffix
|
||||
except AttributeError:
|
||||
self._file_suffix = self._find_current_installed_suffix(self._link_root)
|
||||
return self._file_suffix
|
||||
|
||||
# endregion Properties
|
|
@ -67,7 +67,6 @@ class Controllers(object):
|
|||
def __init__(self, dialog):
|
||||
self.d = dialog
|
||||
self.path_python = app.paths.python
|
||||
self.is_flatpak = app.IS_FLATPAK
|
||||
|
||||
def _set_state(self, state):
|
||||
self._states = {
|
||||
|
@ -260,8 +259,8 @@ class Controllers(object):
|
|||
self.d.lst_log.visible = True
|
||||
|
||||
line = ''
|
||||
if self.is_flatpak:
|
||||
cmd = f' install --upgrade --target={app.get_flatpak_site_packages_dir()}'
|
||||
if app.IS_FLATPAK:
|
||||
cmd = f' install --upgrade --target={app.get_site_packages_dir()}'
|
||||
else:
|
||||
cmd = ' install --upgrade --user'
|
||||
if value:
|
||||
|
@ -275,6 +274,33 @@ class Controllers(object):
|
|||
self.d.lst_log.insert(line, 'ok.png')
|
||||
else:
|
||||
self.d.lst_log.insert(line)
|
||||
self._link_cpython()
|
||||
return
|
||||
|
||||
def _link_cpython(self):
|
||||
if not app.IS_MAC and not app.IS_APP_IMAGE:
|
||||
app.debug('Not Mac or not AppImage')
|
||||
return
|
||||
try:
|
||||
app.debug("Linking CPython")
|
||||
from link_cpython import LinkCPython
|
||||
cpy_link = LinkCPython(pth=app.get_site_packages_dir())
|
||||
cpy_link.link()
|
||||
except Exception as err:
|
||||
app.error(err)
|
||||
return
|
||||
|
||||
def _unlink_cpython(self):
|
||||
if not app.IS_MAC and not app.IS_APP_IMAGE:
|
||||
app.debug('Not Mac or not AppImage')
|
||||
return
|
||||
try:
|
||||
app.debug("Unlinking CPython")
|
||||
from link_cpython import LinkCPython
|
||||
cpy_link = LinkCPython(pth=app.get_site_packages_dir())
|
||||
cpy_link.unlink()
|
||||
except Exception as err:
|
||||
app.error(err)
|
||||
return
|
||||
|
||||
def lst_package_double_click(self, event):
|
||||
|
@ -305,6 +331,7 @@ class Controllers(object):
|
|||
self.d.lst_log.insert(line, 'ok.png')
|
||||
else:
|
||||
self.d.lst_log.insert(line)
|
||||
self._unlink_cpython()
|
||||
return
|
||||
|
||||
def cmd_uninstall_action(self, event):
|
||||
|
|
Loading…
Reference in New Issue