from __future__ import annotations
import os
import platform
import shutil
import stat
import subprocess
import sys
import tempfile
import urllib.request
from pathlib import Path
UDB_VERSION = "0.3.0"
PROTOCOL_VERSION = "1.0.0"
_REPO = "fahara02/udb"
_RELEASE_BASE = f"https://github.com/{_REPO}/releases/download/v{UDB_VERSION}"
def _exe_suffix() -> str:
return ".exe" if os.name == "nt" else ""
def _asset_name() -> str:
system = platform.system().lower()
os_tag = {"linux": "linux", "darwin": "macos", "windows": "windows"}.get(system, system)
machine = platform.machine().lower()
arch = {
"x86_64": "x86_64",
"amd64": "x86_64",
"aarch64": "aarch64",
"arm64": "aarch64",
}.get(machine, machine)
return f"udb-v{UDB_VERSION}-{os_tag}-{arch}{_exe_suffix()}"
def _cache_dir() -> Path:
if os.name == "nt":
base = os.environ.get("LOCALAPPDATA") or str(Path.home() / "AppData" / "Local")
else:
base = os.environ.get("XDG_CACHE_HOME") or str(Path.home() / ".cache")
path = Path(base) / "udb" / "bin" / UDB_VERSION
path.mkdir(parents=True, exist_ok=True)
return path
def _binary_version_matches(binary: str) -> bool:
try:
out = subprocess.run(
[binary, "--version"],
capture_output=True,
text=True,
timeout=10,
)
except (OSError, subprocess.SubprocessError):
return False
return UDB_VERSION in (out.stdout + out.stderr)
def _path_binary() -> str | None:
me = Path(sys.argv[0]).resolve()
found = shutil.which("udb")
if not found:
return None
try:
if Path(found).resolve() == me:
return None
except OSError:
pass
return found if _binary_version_matches(found) else None
def _cached_binary() -> str | None:
candidate = _cache_dir() / f"udb{_exe_suffix()}"
return str(candidate) if candidate.is_file() else None
def _download_binary() -> str:
if os.environ.get("UDB_SKIP_DOWNLOAD"):
raise SystemExit(
f"udb {UDB_VERSION} binary not found and UDB_SKIP_DOWNLOAD is set. "
f"Install it from {_RELEASE_BASE} or set UDB_BIN."
)
url = f"{_RELEASE_BASE}/{_asset_name()}"
dest = _cache_dir() / f"udb{_exe_suffix()}"
tmp_fd, tmp_path = tempfile.mkstemp(dir=str(_cache_dir()))
os.close(tmp_fd)
try:
sys.stderr.write(f"udb: downloading {url}\n")
with urllib.request.urlopen(url) as resp, open(tmp_path, "wb") as out:
shutil.copyfileobj(resp, out)
mode = os.stat(tmp_path).st_mode
os.chmod(tmp_path, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
os.replace(tmp_path, dest)
except Exception as exc: try:
os.unlink(tmp_path)
except OSError:
pass
raise SystemExit(
f"udb: failed to download {url}: {exc}\n"
f"Install the binary manually from {_RELEASE_BASE} or set UDB_BIN."
) from exc
return str(dest)
def _resolve_binary() -> str:
forced = os.environ.get("UDB_BIN")
if forced:
return forced
return _path_binary() or _cached_binary() or _download_binary()
def main(argv: list[str] | None = None) -> int:
args = list(sys.argv[1:] if argv is None else argv)
binary = _resolve_binary()
if os.name == "nt":
return subprocess.run([binary, *args]).returncode
os.execv(binary, [binary, *args])
return 0
if __name__ == "__main__":
raise SystemExit(main())