Source code for fractal.util.tmux
"""Functions for tmux session probing."""
from __future__ import annotations
import subprocess
from typing import Optional
__all__ = []
[docs]
def probe(*, socket: Optional[str] = None) -> Optional[frozenset[str]]:
"""Return the set of live tmux session names, or ``None`` when unknown.
The batched form of a per-session existence probe -- a caller checking
many sessions (e.g. reconciling a whole subtree) probes once instead of
per name. Empty only when tmux definitively answered "no sessions": a
zero exit, the ``no server running`` refusal, or a connect against a
socket path that does not exist (no server ever started on this
socket). Any other failure -- the binary absent (``OSError``, raised
before any result) or ``list-sessions`` erroring for another reason
(socket permissions, an unexpected refusal) -- is inconclusive and
returns ``None``, so a caller about to act destructively on "no
sessions" can refuse to act on ignorance.
Every answer is evidence about one server only: the ambient socket's
"no sessions" says nothing about sessions alive on another socket, so
a caller judging a specific session passes the socket it lives on.
Args:
socket: Server socket path to probe (``tmux -S``); ``None`` probes
the ambient socket.
Returns:
The live tmux session names, or ``None`` when tmux gave no answer.
"""
# -S pins the probe to one server; without it tmux resolves the
# ambient socket ($TMUX, else $TMUX_TMPDIR)
server = [] if socket is None else ['-S', socket]
try:
result = subprocess.run(
['tmux', *server, 'list-sessions', '-F', '#{session_name}'],
capture_output=True,
text=True,
)
except OSError:
return None
if result.returncode != 0:
# tmux's two "no server on this socket" answers -- its own verdict,
# and a connect against a socket path that does not exist (a host
# where no server ever started) -- are definitive empties; any other
# error (permissions, an unexpected refusal) leaves liveness unknown
if result.stderr.startswith('no server running'):
return frozenset()
if result.stderr.startswith('error connecting to'):
if 'No such file or directory' in result.stderr:
return frozenset()
return None
return frozenset(result.stdout.splitlines())
[docs]
def sessions() -> frozenset[str]:
"""Return the set of live tmux session names (one ``list-sessions``).
:func:`probe` with the inconclusive answer folded into the empty set --
for display-only callers where "unknown" and "none visible" render the
same and a failed probe must never crash the read.
Returns:
The live tmux session names (empty when the probe failed).
"""
live = probe()
if live is None:
return frozenset()
return live