mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-28 20:00:56 +01:00
A release's folder has no .git, so git describe found nothing and every Hand Recorder session and export from a release said "ft-handrec unknown", and the live tracker's "frametop" was empty. recorder/common.tree_version reads the release's .frametop-release (VERSION, COMMIT) when there's no checkout: "ft-handrec v0.3.0-exp.12 release 789bb44". A checkout keeps its git describe; a checkout's own BOX-only .frametop-release is ignored. The eye recorder uses the same helper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
115 lines
4.2 KiB
Python
115 lines
4.2 KiB
Python
"""What the recorders share that isn't about any one recorder: clocks, the dev container and the
|
|
host, small file and text helpers, and the versions a session records.
|
|
|
|
Standard library only: the recorders run it in the dev container and, standalone, on the host."""
|
|
import glob
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import time
|
|
|
|
|
|
def mono_ns():
|
|
return time.clock_gettime_ns(time.CLOCK_MONOTONIC)
|
|
|
|
|
|
def clock_sample():
|
|
"""[CLOCK_MONOTONIC ns, CLOCK_MONOTONIC_RAW - CLOCK_MONOTONIC ns], as ft-hands' raw_minus_mono_ns().
|
|
sets.bin's capture_ns is on the RAW clock and everything else on MONOTONIC; the two drift
|
|
apart with NTP's corrections (0.8 s apart and ~10 ppm on 2026-10-03), so take.json keeps
|
|
samples to turn capture_ns into MONOTONIC: capture_ns - offset, interpolated by time."""
|
|
a = time.clock_gettime_ns(time.CLOCK_MONOTONIC)
|
|
r = time.clock_gettime_ns(time.CLOCK_MONOTONIC_RAW)
|
|
b = time.clock_gettime_ns(time.CLOCK_MONOTONIC)
|
|
mid = (a + b) // 2
|
|
return [mid, r - mid]
|
|
|
|
|
|
def in_container():
|
|
return os.path.exists("/run/.containerenv") or os.path.exists("/.dockerenv")
|
|
|
|
|
|
def host_command(*cmd):
|
|
"""argv to run a command on the SteamOS host from the dev container (as in
|
|
display-settings: distrobox-host-exec needs the user's real session bus). It runs from the
|
|
home folder: host-spawn starts the command in the caller's folder, and a container-only
|
|
one such as /run/host/tmp doesn't exist on the host (every command then exits 127)."""
|
|
exe = shutil.which("distrobox-host-exec")
|
|
if not in_container() or not exe:
|
|
return list(cmd)
|
|
return ["env", "-C", os.path.expanduser("~"), "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%d/bus" % os.getuid(),
|
|
exe] + list(cmd)
|
|
|
|
|
|
def host_path(path):
|
|
"""A host file, from the container (/run/host) or the host itself."""
|
|
for p in ("/run/host" + path, path):
|
|
if os.path.exists(p):
|
|
return p
|
|
return None
|
|
|
|
|
|
def write_json(path, data):
|
|
tmp = path + ".tmp"
|
|
with open(tmp, "w") as f:
|
|
json.dump(data, f, indent=1)
|
|
f.write("\n")
|
|
os.replace(tmp, path)
|
|
|
|
|
|
def clean_text(s):
|
|
"""Text for a panel command: one line; "|" is the panel's line break, so callers use it."""
|
|
return " ".join(str(s).replace("\r", " ").replace("\n", " ").split())
|
|
|
|
|
|
def os_version():
|
|
path = "/run/host/etc/os-release" if in_container() else "/etc/os-release"
|
|
try:
|
|
with open(path) as f:
|
|
for line in f:
|
|
if line.startswith("VERSION_ID="):
|
|
return line.split("=", 1)[1].strip().strip('"')
|
|
except OSError:
|
|
pass
|
|
return ""
|
|
|
|
|
|
def tree_version(tree):
|
|
"""A Frametop tree's version, for what a session records: a checkout's git describe, else a
|
|
release's version and commit from its .frametop-release (pack/install-release.sh writes it: a
|
|
release's folder has no .git). "" when neither says."""
|
|
if os.path.exists(os.path.join(tree, ".git")):
|
|
try:
|
|
return subprocess.run(["git", "-C", tree, "describe", "--always", "--dirty", "--tags"],
|
|
capture_output=True, text=True, timeout=10).stdout.strip()
|
|
except (OSError, subprocess.SubprocessError):
|
|
return ""
|
|
info = {}
|
|
try:
|
|
with open(os.path.join(tree, ".frametop-release")) as f:
|
|
for line in f:
|
|
key, eq, value = line.strip().partition("=")
|
|
if eq:
|
|
info[key] = value
|
|
except OSError:
|
|
return ""
|
|
if not info.get("VERSION"):
|
|
return "" # a checkout's own .frametop-release names only its container (BOX=)
|
|
return ("v%s release %s" % (info["VERSION"], info.get("COMMIT", "")[:7])).strip()
|
|
|
|
|
|
def steamvr_version():
|
|
for db in ("/usr/lib/holo/pacmandb", "/var/lib/pacman"): # SteamOS keeps it in the image
|
|
found = sorted(glob.glob(("/run/host" if in_container() else "") + db + "/local/deckard-steamvr-rel-*"))
|
|
if found:
|
|
return os.path.basename(found[-1])[len("deckard-steamvr-rel-"):]
|
|
p = host_path("/opt/steamvr/bin/version.txt")
|
|
if p:
|
|
try:
|
|
with open(p) as f:
|
|
return "build " + f.read().strip()
|
|
except OSError:
|
|
pass
|
|
return ""
|