fix: polish transcript rescue and doc drift from review
Guard HOME for set -u in the rescue paths, surface a failed rescue mv instead of silently dropping the transcript, and never delete the party dir after a failed save in either close or clean (close now refuses to delete and exits nonzero on a failed rescue too, matching clean, since a message promising the transcript survived followed by rm -rf was a false assurance). Also stop log --stop from announcing a stop that never started, and sync README's knock/log/write(1) wording with the actual behavior.
This commit is contained in:
parent
8d10e62779
commit
df9c1cb0dc
3 changed files with 38 additions and 6 deletions
|
|
@ -13,7 +13,7 @@ Built for small, mutually trusted groups: a hacklab, a tech team, a circle of fr
|
||||||
- POSIX shell (`/bin/sh`)
|
- POSIX shell (`/bin/sh`)
|
||||||
- `tmux` ≥ 3.3 (for `server-access`) on `$PATH`, or named via `PARTY_TMUX`
|
- `tmux` ≥ 3.3 (for `server-access`) on `$PATH`, or named via `PARTY_TMUX`
|
||||||
- A shared system group. A party is gated on the first of `staff`, `users`, `wheel`, `party` the host belongs to (`--group <name>` or `TMUX_PARTY_GROUP` always win). Boxes where people already share one of those groups need no setup; creating a dedicated `party` group is the fallback recipe. Every host and guest must be a member of whichever group ends up gating the party.
|
- A shared system group. A party is gated on the first of `staff`, `users`, `wheel`, `party` the host belongs to (`--group <name>` or `TMUX_PARTY_GROUP` always win). Boxes where people already share one of those groups need no setup; creating a dedicated `party` group is the fallback recipe. Every host and guest must be a member of whichever group ends up gating the party.
|
||||||
- `write(1)`, optional: used to ping invited guests. Silently skipped when absent.
|
- `write(1)`, optional: used to ping invited guests and knocking guests. `party invite`'s ping is best-effort, silently skipped when absent; `party knock` depends on it and reports a delivery failure to the caller.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|
@ -121,10 +121,10 @@ Three honest caveats, with the full detail in `man party`:
|
||||||
| `party status` | Show the caller's own state: hosting, attached, or idle. |
|
| `party status` | Show the caller's own state: hosting, attached, or idle. |
|
||||||
| `party close` | Tear down the party server and its roster entry. Host-only. |
|
| `party close` | Tear down the party server and its roster entry. Host-only. |
|
||||||
| `party clean` | Remove the caller's own dead party dirs: crash leftovers whose tmux server is gone. Rescues a non-empty transcript first. |
|
| `party clean` | Remove the caller's own dead party dirs: crash leftovers whose tmux server is gone. Rescues a non-empty transcript first. |
|
||||||
| `party log [--stop]` | Record the party into its private dir via `tmux pipe-pane` (host only), group-readable. `--stop` ends it. |
|
| `party log [--stop] [--party <name>]` | Record the party into its private dir via `tmux pipe-pane` (host only), group-readable. `--stop` ends it. |
|
||||||
| `party join [name] [--passive]` | Join a party. Auto-attaches when one is running; picker otherwise. `--passive` attaches read-only to the host's view (watcher mode). Read-only invitees always join passive. |
|
| `party join [name] [--passive]` | Join a party. Auto-attaches when one is running; picker otherwise. `--passive` attaches read-only to the host's view (watcher mode). Read-only invitees always join passive. |
|
||||||
| `party leave` | Detach and clean up the per-guest session. |
|
| `party leave` | Detach and clean up the per-guest session. |
|
||||||
| `party knock <name>` | Ask the host of an invite-only party for an invite (write(1) ping with the exact invite command). |
|
| `party knock [name]` | Ask the host of an invite-only party for an invite (write(1) ping with the exact invite command). |
|
||||||
| `party role [active\|passive\|switch]` | Flip your clients between guest and host session. No arg prints the current role. |
|
| `party role [active\|passive\|switch]` | Flip your clients between guest and host session. No arg prints the current role. |
|
||||||
| `party --help` | Help text. |
|
| `party --help` | Help text. |
|
||||||
|
|
||||||
|
|
|
||||||
32
party
32
party
|
|
@ -16,6 +16,10 @@ PARTY_VERSION=0.1.0
|
||||||
# `env -i` invocations). Every cmd_* path references it, so guarantee it
|
# `env -i` invocations). Every cmd_* path references it, so guarantee it
|
||||||
# now via id -un rather than crashing later under set -eu.
|
# now via id -un rather than crashing later under set -eu.
|
||||||
: "${USER:=$(id -un)}"
|
: "${USER:=$(id -un)}"
|
||||||
|
# $HOME can be unset in the same stripped environments; the close/clean
|
||||||
|
# transcript rescues are the only readers, and they treat an empty
|
||||||
|
# value as "nowhere to put it" rather than crashing under set -u.
|
||||||
|
: "${HOME:=}"
|
||||||
# Group default. Remember whether the caller supplied TMUX_PARTY_GROUP
|
# Group default. Remember whether the caller supplied TMUX_PARTY_GROUP
|
||||||
# explicitly: cmd_host auto-selects a candidate group only when it was
|
# explicitly: cmd_host auto-selects a candidate group only when it was
|
||||||
# not (an empty value counts as unset; an empty group name gates
|
# not (an empty value counts as unset; an empty group name gates
|
||||||
|
|
@ -956,8 +960,17 @@ cmd_close() {
|
||||||
# catching late writes regardless, but $HOME and PARTY_SOCKET_DIR
|
# catching late writes regardless, but $HOME and PARTY_SOCKET_DIR
|
||||||
# are commonly different filesystems (tmpfs /tmp vs a home
|
# are commonly different filesystems (tmpfs /tmp vs a home
|
||||||
# partition), where mv is copy+unlink and tail bytes written after
|
# partition), where mv is copy+unlink and tail bytes written after
|
||||||
# the copy started would be lost from the copy.
|
# the copy started would be lost from the copy. A failed rescue
|
||||||
|
# (HOME unset, mv error) leaves the party dir in place rather than
|
||||||
|
# deleting it out from under a promise the message just made;
|
||||||
|
# kill-server already ran, so the party is dead either way, and
|
||||||
|
# `party close` (or `party clean`) can be re-run once the transcript
|
||||||
|
# is off to safety.
|
||||||
if [ -s "$expected_dir/log" ]; then
|
if [ -s "$expected_dir/log" ]; then
|
||||||
|
if [ -z "$HOME" ]; then
|
||||||
|
echo "party close: HOME is unset; transcript kept, party dir left in place ($expected_dir/log); re-run close after fixing." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
_cl_prev=-1
|
_cl_prev=-1
|
||||||
for _cl_i in 1 2 3; do
|
for _cl_i in 1 2 3; do
|
||||||
_cl_size=$(wc -c < "$expected_dir/log")
|
_cl_size=$(wc -c < "$expected_dir/log")
|
||||||
|
|
@ -968,6 +981,9 @@ cmd_close() {
|
||||||
_cl_dest="$HOME/party-$name-$(date -u '+%Y%m%d-%H%M%S').log"
|
_cl_dest="$HOME/party-$name-$(date -u '+%Y%m%d-%H%M%S').log"
|
||||||
if mv "$expected_dir/log" "$_cl_dest" 2>/dev/null; then
|
if mv "$expected_dir/log" "$_cl_dest" 2>/dev/null; then
|
||||||
echo "party close: transcript saved to $_cl_dest"
|
echo "party close: transcript saved to $_cl_dest"
|
||||||
|
else
|
||||||
|
echo "party close: could not save transcript; party dir left in place ($expected_dir/log); re-run close after fixing." >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -1012,11 +1028,18 @@ EOF
|
||||||
# close there's no pipe-pane `cat` still draining and no
|
# close there's no pipe-pane `cat` still draining and no
|
||||||
# quiescence poll is needed before moving it.
|
# quiescence poll is needed before moving it.
|
||||||
if [ -s "$d/log" ]; then
|
if [ -s "$d/log" ]; then
|
||||||
|
if [ -z "$HOME" ]; then
|
||||||
|
echo "party clean: skipping $d (HOME is unset; leaving transcript)" >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
_cn_name=${d##*"party-$USER:"}
|
_cn_name=${d##*"party-$USER:"}
|
||||||
_cn_name=${_cn_name%.d}
|
_cn_name=${_cn_name%.d}
|
||||||
_cn_dest="$HOME/party-$_cn_name-$(date -u '+%Y%m%d-%H%M%S').log"
|
_cn_dest="$HOME/party-$_cn_name-$(date -u '+%Y%m%d-%H%M%S').log"
|
||||||
if mv "$d/log" "$_cn_dest" 2>/dev/null; then
|
if mv "$d/log" "$_cn_dest" 2>/dev/null; then
|
||||||
echo "party clean: transcript saved to $_cn_dest"
|
echo "party clean: transcript saved to $_cn_dest"
|
||||||
|
else
|
||||||
|
echo "party clean: skipping $d (could not save transcript)" >&2
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -1071,6 +1094,13 @@ EOF
|
||||||
logfile="${RR_SOCKET%/sock}/log"
|
logfile="${RR_SOCKET%/sock}/log"
|
||||||
|
|
||||||
if [ "$stop" = 1 ]; then
|
if [ "$stop" = 1 ]; then
|
||||||
|
# No log file means logging was never started this run; don't
|
||||||
|
# announce a stop that never happened or point at a transcript
|
||||||
|
# that doesn't exist.
|
||||||
|
if [ ! -e "$logfile" ]; then
|
||||||
|
echo "party log: nothing was being logged."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
# pipe-pane with no command closes a pane's pipe; harmless on
|
# pipe-pane with no command closes a pane's pipe; harmless on
|
||||||
# panes that were never piped.
|
# panes that were never piped.
|
||||||
"$PARTY_TMUX" -S "$RR_SOCKET" list-panes -s -t "$RR_PARTY_NAME" -F '#{pane_id}' \
|
"$PARTY_TMUX" -S "$RR_SOCKET" list-panes -s -t "$RR_PARTY_NAME" -F '#{pane_id}' \
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#!/usr/bin/env bats
|
#!/usr/bin/env bats
|
||||||
#
|
#
|
||||||
# party log: pipe-pane transcript into the per-party dir. Needs a real
|
# party log: pipe-pane transcript into the per-party dir. Needs a real
|
||||||
# tmux server (pipe-pane semantics can't be stubbed honestly), so most
|
# tmux server (pipe-pane semantics can't be stubbed honestly), so setup
|
||||||
# tests gate on require_party_group like the other e2e suites.
|
# pins TMUX_PARTY_GROUP to the caller's own primary group rather than
|
||||||
|
# gating on require_party_group like the other e2e suites: no group
|
||||||
|
# membership setup is needed, and no test here ever skips.
|
||||||
|
|
||||||
load 'helpers'
|
load 'helpers'
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue