bupha_runner/lib.rs
1//! bupha-runner — the runner *port*: a job becomes a spawned child the
2//! watcher can wait on or kill. Implementations live in
3//! `bupha-runner-*` crates; the core knows nothing about dagger, docker
4//! or shells.
5
6use std::io;
7use std::path::Path;
8use std::process::Child;
9
10/// A running job — the local impl wraps `Child`; remote runners
11/// (SSH, hosted agents) impl this over their own handle so the
12/// worker's wait/cancel logic stays unchanged.
13pub trait RunHandle: Send {
14 /// Non-blocking completion check — None if still running.
15 fn try_wait(&mut self) -> io::Result<Option<std::process::ExitStatus>>;
16 /// Block until the run finishes; exit status drives the status
17 /// sink ("success" vs "error").
18 fn wait(&mut self) -> io::Result<std::process::ExitStatus>;
19 /// Best-effort kill (superseded runs).
20 fn kill(&mut self) -> io::Result<()>;
21}
22
23impl RunHandle for Child {
24 fn try_wait(&mut self) -> io::Result<Option<std::process::ExitStatus>> {
25 Child::try_wait(self)
26 }
27 fn wait(&mut self) -> io::Result<std::process::ExitStatus> {
28 Child::wait(self)
29 }
30 fn kill(&mut self) -> io::Result<()> {
31 Child::kill(self)
32 }
33}
34
35/// Everything a runner needs to launch a job.
36pub struct RunCtx<'a> {
37 /// Detached worktree of the sha under test.
38 pub workdir: &'a Path,
39 /// Name of the env var holding the auth token (the runner decides
40 /// how to pass it — e.g. `env://` secret for dagger).
41 pub token_env: &'a str,
42}
43
44/// Job execution — runs a single sha's pipeline.
45pub trait Runner: Send + Sync {
46 /// Human name for logs ("dagger", "script").
47 fn name(&self) -> &'static str;
48 /// Spawn the run. The caller waits/kills via the returned Child —
49 /// keeping the handle outside the queue lock is what makes
50 /// cancel-in-flight safe.
51 fn spawn(&self, ctx: &RunCtx) -> io::Result<Box<dyn RunHandle>>;
52}