From bc41781df0483f1865fb7d8011cca99d20c2fd69 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 12 May 2025 00:01:10 -0400 Subject: [PATCH] allow input in `trvmctl run` --- src/cli.rs | 4 ++++ src/main.rs | 24 +++++++++++++++++++++--- src/vm.rs | 3 +++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 2048b81..8e3dc15 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -56,6 +56,10 @@ pub enum Commands { }, /// Run a command in a currently running VM. + /// + /// If standard input is not a terminal, all standard input is collected before invoking the + /// program. All standard output is collected before returning from the function. Interactive + /// programs are not possible at this time.. Run { /// The command to run. command: String, diff --git a/src/main.rs b/src/main.rs index 613fbe1..9f75348 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,14 @@ use clap::Parser; use eyre::WrapErr; -use std::io::Write; +use std::io::{IsTerminal, Read, Write}; mod cli; mod vm; use vm::{SpawnArguments, VirtualMachine}; +#[allow(clippy::too_many_lines)] fn main() -> eyre::Result<()> { color_eyre::install()?; @@ -54,7 +55,7 @@ fn main() -> eyre::Result<()> { .ok_or(eyre::eyre!("no hostname"))? .as_str() .ok_or(eyre::eyre!("hostname is not str"))?; - let uptime = vm.run_command("uptime", [])?; + let uptime = vm.run_command("uptime", [], None)?; eprintln!("hostname: {hostname}"); eprint!("{}", String::from_utf8_lossy(&uptime.0)); } @@ -91,7 +92,24 @@ fn main() -> eyre::Result<()> { cli::Commands::Run { command, args } => { let spawn_arguments = SpawnArguments::default(); let mut vm = VirtualMachine::load(spawn_arguments, None)?; - let (response, exit_code) = vm.run_command(&command, args)?; + + let mut stdin = std::io::stdin(); + let buffered_stdin = if stdin.is_terminal() { + None + } else { + let mut bytes = vec![]; + stdin + .read_to_end(&mut bytes) + .context(eyre::eyre!("could not read input"))?; + if bytes.is_empty() { + None + } else { + Some(bytes) + } + }; + + let (response, exit_code) = + vm.run_command(&command, args, buffered_stdin.as_deref())?; std::io::stdout().write_all(&response)?; std::process::exit( i32::try_from(exit_code).context(eyre::eyre!("bad PID: pid < i32::MAX << 1"))?, diff --git a/src/vm.rs b/src/vm.rs index 70f36d7..7855b58 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -574,13 +574,16 @@ impl VirtualMachine { &mut self, command: &str, args: impl IntoIterator, + stdin: Option<&[u8]>, ) -> Result<(Vec, u64)> { let args = args.into_iter().collect::>(); + let input = stdin.map(|bytes| BASE64_STANDARD.encode(bytes)); let payload = serde_json::json!({ "path": command, "arg": args, "capture-output": true, + "input-data": input, }); let bar = spinner(format!("Running: {command:?} {args:?}"));