Inside a Flatpak the host /usr/bin/git is reachable at /run/host/usr/bin/git but linked against host glibc/zlib, which the sandbox cannot load (libz-ng.so.2 missing). gitpython resolves git eagerly on import and crashed the whole validation run. Install a tiny shell wrapper under /tmp at module load (``exec flatpak-spawn --host git "$@"``) and point gitpython at it via GIT_PYTHON_GIT_EXECUTABLE so test_version / test_modifs work in flatpak mode. No-op outside Flatpak. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
183 lines
5.6 KiB
Python
183 lines
5.6 KiB
Python
import atexit
|
|
import os
|
|
import stat
|
|
import sys
|
|
import tempfile
|
|
from importlib import import_module
|
|
|
|
import interpreter.utils.settings as prefs
|
|
import api.testium as tm
|
|
|
|
|
|
# When running inside a Flatpak, the host /usr/bin/git is reachable at
|
|
# /run/host/usr/bin/git but linked against host glibc/zlib, which the
|
|
# sandbox can't load (``libz-ng.so.2`` not found). gitpython resolves git
|
|
# eagerly on import and would crash the whole test run. We install a
|
|
# tiny shell wrapper under /tmp that forwards to ``flatpak-spawn --host
|
|
# git``, and point gitpython at it via ``GIT_PYTHON_GIT_EXECUTABLE``.
|
|
_HOST_GIT_WRAPPER = None
|
|
|
|
|
|
def _setup_flatpak_git():
|
|
global _HOST_GIT_WRAPPER
|
|
if not os.path.isfile("/.flatpak-info"):
|
|
return
|
|
if _HOST_GIT_WRAPPER is not None:
|
|
return
|
|
fd, path = tempfile.mkstemp(prefix="testium-git-host-", suffix=".sh", dir="/tmp")
|
|
with os.fdopen(fd, "w") as f:
|
|
f.write('#!/bin/sh\nexec flatpak-spawn --host git "$@"\n')
|
|
os.chmod(path, stat.S_IRWXU)
|
|
_HOST_GIT_WRAPPER = path
|
|
atexit.register(_cleanup_flatpak_git)
|
|
os.environ["GIT_PYTHON_GIT_EXECUTABLE"] = path
|
|
# Silence gitpython's warning if its refresh probe ever still fails;
|
|
# the wrapper itself should make the probe succeed.
|
|
os.environ.setdefault("GIT_PYTHON_REFRESH", "quiet")
|
|
|
|
|
|
def _cleanup_flatpak_git():
|
|
global _HOST_GIT_WRAPPER
|
|
if _HOST_GIT_WRAPPER and os.path.isfile(_HOST_GIT_WRAPPER):
|
|
try:
|
|
os.unlink(_HOST_GIT_WRAPPER)
|
|
except OSError:
|
|
pass
|
|
_HOST_GIT_WRAPPER = None
|
|
|
|
|
|
_setup_flatpak_git()
|
|
|
|
|
|
_cached_versions = {}
|
|
|
|
def repo_rev(path):
|
|
ret = _cached_versions.get(path, None)
|
|
if ret:
|
|
return ret
|
|
git = import_module("git")
|
|
repo = git.Repo(path, search_parent_directories=True)
|
|
if repo.bare:
|
|
ret ="Warning Bare repo: {}, modifications cannot be tracked !".format(path)
|
|
else:
|
|
ret = getSubmoduleVersion(git, repo)
|
|
_cached_versions.update({path: ret})
|
|
repo.close()
|
|
return ret
|
|
|
|
def get_version(path :str)-> str:
|
|
if prefs.settings.git_supported:
|
|
try:
|
|
return repo_rev(path)
|
|
except:
|
|
return "Warning : {} not versioned".format(path)
|
|
else:
|
|
return "Warning git not supported in your settings, version of {} unknown".format(path)
|
|
|
|
def get_testium_version():
|
|
# Flatpak bundle
|
|
if os.path.isfile('/.flatpak-info'):
|
|
ver = os.environ.get('TESTIUM_VERSION', '').strip()
|
|
return (ver if ver else 'unknown') + " (flatpak release)"
|
|
|
|
# AppImage
|
|
if 'APPIMAGE' in os.environ:
|
|
ver = os.environ.get('TESTIUM_VERSION', '').strip()
|
|
return (ver if ver else 'unknown') + " (binary release)"
|
|
|
|
# PyInstaller frozen exe
|
|
if getattr(sys, 'frozen', False):
|
|
file_path = os.path.join(sys._MEIPASS, "VERSION")
|
|
try:
|
|
with open(file_path, 'r') as f:
|
|
ver = f.read().strip()
|
|
return ver + " (binary release)"
|
|
except OSError:
|
|
return "unknown (binary release)"
|
|
|
|
# Source checkout: prefer git revision when available
|
|
if prefs.settings.git_supported:
|
|
try:
|
|
git = import_module("git")
|
|
return repo_rev(tm.get_main_dir())
|
|
except Exception:
|
|
# Not a git repo (typical pip install): fall through.
|
|
pass
|
|
|
|
# Pip-installed wheel: use the package metadata baked from VERSION
|
|
try:
|
|
from importlib.metadata import version as _pkg_version
|
|
from importlib.metadata import PackageNotFoundError
|
|
try:
|
|
return _pkg_version("testium") + " (wheel release)"
|
|
except PackageNotFoundError:
|
|
pass
|
|
except ImportError:
|
|
pass
|
|
|
|
return "unknown"
|
|
|
|
def get_modifications(path : str)-> str:
|
|
|
|
if prefs.settings.git_supported:
|
|
git = import_module("git")
|
|
modifs = ""
|
|
try:
|
|
repo = git.Repo(path, search_parent_directories=True)
|
|
for item in repo.index.diff(None):
|
|
modifs = modifs + '"' + item.a_path + '"' + ' (modified)\n'
|
|
for item in repo.untracked_files:
|
|
modifs = modifs + '"' + item + '"' + ' (untracked)\n'
|
|
repo.close()
|
|
return modifs
|
|
except git.InvalidGitRepositoryError:
|
|
return "Warning : {} not versioned".format(path)
|
|
else:
|
|
return "Warning git not supported in your settings, version of {} unknown".format(path)
|
|
|
|
def getSubmoduleVersion(git, repo) -> str:
|
|
v = ""
|
|
for subM in repo.iter_submodules(ignore_self=False):
|
|
try:
|
|
v = v + getCommitVsTag(subM.module()) + "\n"
|
|
except git.InvalidGitRepositoryError:
|
|
v = v +"{} not versioned".format(subM.module().git_dir) + "\n"
|
|
return v
|
|
|
|
def getCommitVsTag(repo) -> str:
|
|
sha = repo.head.object.hexsha
|
|
short_sha = repo.git.rev_parse(sha, short=12)
|
|
url = change = ''
|
|
|
|
# check if a tag or no
|
|
t = None
|
|
for tag in repo.tags:
|
|
# Try excepted added after crash encountered because of strange tag
|
|
try:
|
|
if tag.commit == repo.head.commit:
|
|
t = tag
|
|
except:
|
|
pass
|
|
|
|
if repo.is_dirty():
|
|
change = '(M)'
|
|
try:
|
|
url = "".join(repo.remote().urls)
|
|
except:
|
|
pass
|
|
if t:
|
|
ret = "tag {}".format(t.name)
|
|
else:
|
|
branch = ""
|
|
if not repo.head.is_detached:
|
|
branch = repo.active_branch.name
|
|
else:
|
|
for h in repo.heads:
|
|
if h.commit == repo.head.commit:
|
|
branch = "detached from " + h.name
|
|
ret = "{}{}, commit {}".format(branch, change, short_sha)
|
|
if url:
|
|
ret = ret + " from : " + url
|
|
repo.close()
|
|
return ret
|