Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
2.8 kB · 92 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293//! Running a verb's binary: the hand-off, and the version probe `--list`//! makes.
use std::ffi::OsStr;use std::path::Path;use std::process::{Command, Stdio};use std::time::{Duration, Instant};
use didbot_cli::Refusal;
/// How long `--list` waits for one binary to answer `--version`. A verb/// that starts doing work instead of answering is killed, so one stray/// binary on `PATH` cannot hang the listing.const VERSION_PATIENCE: Duration = Duration::from_secs(3);
/// The command as a verb receives it: `binary argv…`, this process's/// environment minus every credential variable, and nothing added.fn command<I, S>(binary: &Path, argv: I) -> Commandwhere I: IntoIterator<Item = S>, S: AsRef<OsStr>,{ let mut command = Command::new(binary); command.args(argv); for variable in didbot_cli::env::CREDENTIALS { command.env_remove(variable); } command}
/// Replaces this process with `binary argv…`.////// Returns only when the binary could not be started. On unix the verb's/// exit status is then the shell's directly; elsewhere this waits and/// exits with the same status.pub fn exec<I, S>(binary: &Path, argv: I) -> Result<(), Refusal>where I: IntoIterator<Item = S>, S: AsRef<OsStr>,{ let mut command = command(binary, argv); let could_not_start = |error: std::io::Error| { Refusal::failed(format!("could not run {}: {error}", binary.display())) }; #[cfg(unix)] { use std::os::unix::process::CommandExt; Err(could_not_start(command.exec())) } #[cfg(not(unix))] { let status = command.status().map_err(could_not_start)?; std::process::exit(status.code().unwrap_or(1)); }}
/// What `binary --version` prints on its first line, if it answers with/// exit 0 inside [`VERSION_PATIENCE`].pub fn version_of(binary: &Path) -> Option<String> { let mut child = command(binary, ["--version"]) .stdin(Stdio::null()) .stdout(Stdio::piped()) .stderr(Stdio::null()) .spawn() .ok()?; let started = Instant::now(); let status = loop { match child.try_wait() { Ok(Some(status)) => break status, Ok(None) if started.elapsed() < VERSION_PATIENCE => { std::thread::sleep(Duration::from_millis(20)); } _ => { let _ = child.kill(); let _ = child.wait(); return None; } } }; if !status.success() { return None; } let mut stdout = child.stdout.take()?; let mut output = String::new(); std::io::Read::read_to_string(&mut stdout, &mut output).ok()?; output .lines() .next() .map(str::trim) .filter(|line| !line.is_empty()) .map(str::to_owned)}