pub struct CuddleX { command: String, args: Vec, } impl CuddleX { pub fn command(command: impl Into) -> Self { Self { command: command.into(), args: Vec::new(), } } pub fn arg(&mut self, arg: impl Into) -> &mut Self { self.args.push(arg.into()); self } pub async fn run(&mut self) -> eyre::Result<(String, String, i32)> { let mut cmd = tokio::process::Command::new("cuddle"); let cmd = cmd.arg("x").arg(&self.command).args(&self.args); let process = cmd.spawn()?; let output = process.wait_with_output().await?; Ok(( std::str::from_utf8(&output.stdout)?.to_string(), std::str::from_utf8(&output.stderr)?.to_string(), output.status.code().unwrap_or(0), )) } } pub mod well_known { use super::CuddleX; pub async fn render(args: impl IntoIterator>) -> eyre::Result<()> { tracing::info!("running render"); let mut cmd = CuddleX::command("render"); for arg in args.into_iter() { let arg = arg.into(); cmd.arg(arg); } let (stdout, stderr, status) = cmd.run().await?; for line in stdout.lines() { tracing::trace!("render: {}", line); } for line in stderr.lines() { tracing::trace!("render: {}", line); } if status != 0 { tracing::warn!("finished render with non-zero exit code: {}", status); } tracing::info!("finished running render"); Ok(()) } }