From 883114e2a320b2afb7be960be3a1add430c14328 Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Tue, 2 Jun 2026 11:05:38 +0200 Subject: [PATCH] feat: automatically detach from `p logs -f` on job end --- p/src/commands/logs.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/p/src/commands/logs.rs b/p/src/commands/logs.rs index d38c1c0..a56e886 100644 --- a/p/src/commands/logs.rs +++ b/p/src/commands/logs.rs @@ -20,8 +20,29 @@ pub fn execute(job_id: &str, follow: bool) -> Result<()> { ); print_log(worker, &log)?; } else { - // Stream live output. Ctrl+C kills ssh; the job keeps running. - ssh::run_output(worker, &format!("tail -n +1 -f {}", log))?; + // Stream live output and exit automatically when the job finishes. + // + // The script backgrounds `tail -f` (so its stdout still flows to the + // client through the SSH pipe), then polls for the exitcode file that + // run.sh writes the moment the job exits. A 1-second sleep after + // detecting the exitcode file gives tail time to drain any bytes that + // were written to the log just before exitcode appeared. `kill` + + // `wait` let tail flush its buffer before the SSH connection closes. + // + // Ctrl+C still works: it kills ssh, which sends SIGHUP to the remote + // shell, terminating the whole script including the tail background job. + let exitcode_path = format!("~/.p/jobs/{}/exitcode", job.id); + let follow_cmd = format!( + "tail -n +1 -f {log} & \ + TAIL_PID=$!; \ + while ! [ -f {exitcode} ]; do sleep 1; done; \ + sleep 1; \ + kill \"$TAIL_PID\" 2>/dev/null; \ + wait \"$TAIL_PID\" 2>/dev/null", + log = log, + exitcode = exitcode_path, + ); + ssh::run_output(worker, &follow_cmd)?; } } else { print_log(worker, &log)?;