Enhance version retrieval logic and add fallback mechanisms in _get_installed_version function

This commit is contained in:
Lloyd
2026-03-10 11:33:49 +00:00
parent cd1c88e9c6
commit bf3b4b5b1b
2 changed files with 59 additions and 17 deletions

View File

@@ -85,3 +85,4 @@ line_length = 100
[tool.setuptools_scm]
version_scheme = "guess-next-dev"
local_scheme = "no-local-version"
version_file = "repeater/_version.py"

View File

@@ -45,11 +45,24 @@ CHECK_CACHE_TTL = 600 # 10 minutes
def _get_installed_version() -> str:
"""
Return the highest dist-info version found for pymc_repeater across all
directories the running interpreter actually uses.
Search strategy (union of all three to cover venvs, system, dist-packages):
1. site.getsitepackages() / getusersitepackages()
2. sys.path entries that look like package directories
3. Fallback: importlib.metadata, then the in-process __version__
Sanity check: the running process __version__ is used as a version floor.
If the disk scan returns something older than what is actually running, we
return __version__ instead an older dist-info is definitively stale.
"""
import glob
import site as _site
import sys
# Collect all site-packages directories
# -- 1. Collect candidate directories ---------------------------------- #
dirs: list = []
try:
dirs.extend(_site.getsitepackages())
@@ -59,7 +72,13 @@ def _get_installed_version() -> str:
dirs.append(_site.getusersitepackages())
except AttributeError:
pass
# Also include every sys.path entry that looks like a package directory so
# venvs and Debian dist-packages paths are covered.
for p in sys.path:
if p and ("site-packages" in p or "dist-packages" in p) and p not in dirs:
dirs.append(p)
# -- 2. Scan for dist-info METADATA files ------------------------------ #
pkg_glob = PACKAGE_NAME.replace("-", "_") + "-*.dist-info"
candidates: list = []
for site_dir in dirs:
@@ -75,28 +94,50 @@ def _get_installed_version() -> str:
except OSError:
continue
# -- 3. Pick the highest candidate ------------------------------------- #
disk_version: Optional[str] = None
if candidates:
if len(candidates) == 1:
return candidates[0]
# Multiple dist-info dirs found (stale old version alongside new one).
# Return the highest so an old leftover dir doesn't mask the real version.
try:
from packaging.version import Version
return str(max(candidates, key=lambda v: Version(v)))
except Exception:
return candidates[-1] # last found as a best-effort fallback
disk_version = candidates[0]
else:
try:
from packaging.version import Version
disk_version = str(max(candidates, key=lambda v: Version(v)))
except Exception:
# packaging unavailable sort lexicographically as best-effort
disk_version = sorted(candidates)[-1]
# Fallback: importlib.metadata (may be stale but better than nothing)
# -- 4. Fallbacks when disk scan found nothing ------------------------- #
if disk_version is None:
try:
from importlib.metadata import version as _pkg_ver
disk_version = _pkg_ver(PACKAGE_NAME)
except Exception:
pass
if disk_version is None:
try:
from repeater import __version__
return __version__
except Exception:
return "unknown"
# -- 5. Sanity check: never return a version older than what's running -- #
# If the running process is already on a higher version than anything found
# on disk, the dist-info dirs are stale leftovers and __version__ is truth.
try:
from importlib.metadata import version as _pkg_ver
return _pkg_ver(PACKAGE_NAME)
from repeater import __version__ as _running
from packaging.version import Version
if Version(_running) > Version(disk_version):
logger.debug(
f"[Update] Disk version {disk_version!r} < running {_running!r};"
" using running __version__ as installed version."
)
return _running
except Exception:
pass
try:
from repeater import __version__
return __version__
except Exception:
return "unknown"
return disk_version
# Channels file persisted so the choice survives daemon restarts
_CHANNELS_FILE = "/var/lib/pymc_repeater/.update_channel"