Skip to content

Commit

Permalink
stdinput now tested and working
Browse files Browse the repository at this point in the history
  • Loading branch information
tiptenbrink committed May 1, 2024
1 parent 640f25f commit 7ae7f9d
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 59 deletions.
10 changes: 6 additions & 4 deletions src/next/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::run::run_command as inner_run_command;
use super::run::run_command_input as inner_run_command;
use crate::state::CliEnvState;
use color_eyre::eyre::Report;
use thiserror::Error as ThisError;
Expand Down Expand Up @@ -45,15 +45,17 @@ impl Default for GlobalArguments {
pub struct RunArguments {
pub executable: Option<String>,
pub variables: Vec<String>,
pub archive: Option<String>
pub archive: Option<String>,
pub input_bytes: Option<Vec<u8>>
}

impl Default for RunArguments {
fn default() -> Self {
RunArguments {
executable: None,
variables: Vec::new(),
archive: None
archive: None,
input_bytes: None
}
}
}
Expand All @@ -79,7 +81,7 @@ pub struct CommandError {
}

pub fn run_command(global_args: GlobalArguments, args: RunArguments) -> Result<EntrypointOut, CommandError> {
inner_run_command(global_args.into(), args.executable, args.variables, args.archive).map_err(|e|
inner_run_command(global_args.into(), args.executable, args.variables, args.archive, args.input_bytes).map_err(|e|
CommandError {
msg: "An error occurred in the inner application layer.".to_owned(),
source: e
Expand Down
74 changes: 21 additions & 53 deletions src/next/process.rs
Original file line number Diff line number Diff line change
@@ -1,53 +1,48 @@
use color_eyre::eyre::{Context, ContextCompat, Report};
use std::io::{stderr, stdout, Read, Write};
use color_eyre::eyre::{Context, Report};
use std::io::{stdout, Read, Write};
use std::process::ExitStatus;
use std::str;
use duct::cmd;
use std::thread::sleep;
use std::time::Duration;
/// This is purely application-level code, hence you would never want to reference it as a library.
/// For this reason we do not really care about the exact errors and need not match on them.
use std::{
collections::HashMap,
io::{BufRead, BufReader},
path::Path,
process::{Command as Cmd, Stdio},
io::BufReader,
path::Path
};
use tracing::{debug, span, Level};

/// Read output bytes into a string and trim any whitespace at the end.
fn process_out(bytes: Vec<u8>) -> Result<String, Report> {
let mut output_string = String::from_utf8(bytes)
.wrap_err("Error occurred decoding process output bytes as UTF-8.")?;
// We use truncate to prevent having to copy the string, which could be quite large as it's
// the output of a whole program
let trim_len = output_string.trim_end().len();
output_string.truncate(trim_len);

Ok(output_string)
}
use tracing::{span, Level};

pub struct EntrypointOut {
pub out: String,
pub exit: ExitStatus
}

/// Runs the entrypoint, sending the entrypoint's stdout and stderr to stdout
/// Runs the entrypoint, sending the entrypoint's stdout and stderr to stdout. It adds the provided envs to
/// the envs of the tidploy process. `input_bytes` is useful mostly for testing, if set to None then the
/// child process will just inherit the stdin of the tidploy process.
pub(crate) fn run_entrypoint<P: AsRef<Path>>(
entrypoint_dir: P,
entrypoint: &str,
envs: HashMap<String, String>,
input_bytes: Option<Vec<u8>>
) -> Result<EntrypointOut, Report> {
println!("Running {}!", &entrypoint);
let program_path = entrypoint_dir.as_ref().join(entrypoint);
// Use parent process env variables as base
let mut combined_envs: HashMap<_, _> = std::env::vars().collect();
combined_envs.extend(envs);

let cmd_expr = cmd(&program_path, Vec::<String>::new())
.dir(entrypoint_dir.as_ref())
.full_env(&combined_envs);
.full_env(&combined_envs)
.stderr_to_stdout();

// This is useful for testing input
let cmd_expr = if let Some(input_bytes) = input_bytes {
cmd_expr.stdin_bytes(input_bytes)
} else {
cmd_expr
};

let reader = cmd_expr.stderr_to_stdout().reader()?;
let reader = cmd_expr.reader()?;

let entry_span = span!(Level::DEBUG, "entrypoint", path = program_path.to_str());
let _enter = entry_span.enter();
Expand Down Expand Up @@ -79,31 +74,4 @@ pub(crate) fn run_entrypoint<P: AsRef<Path>>(
out,
exit
})
}

// #[cfg(test)]
// mod tests {
// use std::env;

// use crate::git::git_root_dir;

// use super::*;

// #[test]
// fn test_run_entrypoint() {
// let current_dir = env::current_dir().unwrap();
// let project_dir = git_root_dir(&current_dir).unwrap();
// let project_path = Path::new(&project_dir).join("examples").join("run");

// run_entrypoint(project_path, "do_echo.sh", HashMap::new()).unwrap();
// }

// #[test]
// fn test_spawn() {
// let current_dir = env::current_dir().unwrap();
// let project_dir = git_root_dir(&current_dir).unwrap();
// let project_path = Path::new(&project_dir).join("examples").join("run");

// run_entrypoint(project_path, "do_echo.sh", HashMap::new()).unwrap();
// }
// }
}
9 changes: 7 additions & 2 deletions src/next/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ use crate::{archives::extract_archive, filesystem::get_dirs, state::{create_stat

use super::{process::{run_entrypoint, EntrypointOut}, state::create_state_run};

#[instrument(name = "run", level = "debug", skip_all)]

pub(crate) fn run_command(cli_state: CliEnvState, executable: Option<String>, variables: Vec<String>, archive: Option<String>) -> Result<EntrypointOut, Report> {
run_command_input(cli_state, executable, variables, archive, None)
}

#[instrument(name = "run", level = "debug", skip_all)]
pub(crate) fn run_command_input(cli_state: CliEnvState, executable: Option<String>, variables: Vec<String>, archive: Option<String>, input_bytes: Option<Vec<u8>>) -> Result<EntrypointOut, Report> {
// Only loads archive if it is given, otherwise path is None
// let state = if let Some(archive) = archive {
// let cache_dir = get_dirs().cache.as_path();
Expand Down Expand Up @@ -47,5 +52,5 @@ pub(crate) fn run_command(cli_state: CliEnvState, executable: Option<String>, va

// let state = extra_envs(state);

run_entrypoint(state.deploy_dir(), &state.exe_name, state.envs)
run_entrypoint(state.deploy_dir(), &state.exe_name, state.envs, input_bytes)
}
16 changes: 16 additions & 0 deletions tests/run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,21 @@ fn test_stdout_stderr() -> Result<(), CommandError> {

assert_eq!("hello1\nhello2\nerr1\nerr2\nhello3\n", output.out);

Ok(())
}

#[test]
fn test_input() -> Result<(), CommandError> {
let mut global_args = GlobalArguments::default();
let mut args = RunArguments::default();
global_args.context = Some(StateContext::None);
args.executable = Some("examples/run/example_input.sh".to_owned());
args.input_bytes = Some("foo".into());

let output = run_command(global_args, args)?;
assert!(output.exit.success());

assert_eq!("You entered: foo\n", output.out);

Ok(())
}

0 comments on commit 7ae7f9d

Please sign in to comment.