Skip to content

Commit

Permalink
new: Add tests and handle piping. (#343)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj authored Dec 17, 2023
1 parent 18378e0 commit 6ca316c
Show file tree
Hide file tree
Showing 18 changed files with 324 additions and 44 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,4 @@ winreg = "0.52.0"

[dev-dependencies]
starbase_sandbox = { workspace = true }
signal-child = "1.0.5"
54 changes: 12 additions & 42 deletions crates/cli/src/main_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use rust_json::{json_parse, JsonElem as Json};
use shared_child::SharedChild;
use starbase::tracing::{self, trace, TracingOptions};
use std::collections::HashMap;
use std::io::{IsTerminal, Read, Write};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::Command;
use std::sync::Arc;
use std::{env, fs, io, process};
use std::{env, fs, process};

fn get_proto_home() -> Result<PathBuf> {
if let Ok(root) = env::var("PROTO_HOME") {
Expand Down Expand Up @@ -67,7 +67,7 @@ fn get_proto_binary(proto_home_dir: &Path, shim_exe_path: &Path) -> PathBuf {
PathBuf::from(bin_name)
}

fn create_command(args: Vec<String>, shim_name: &str, shim_exe_path: &Path) -> Result<Command> {
fn create_command(args: Vec<OsString>, shim_name: &str, shim_exe_path: &Path) -> Result<Command> {
let proto_home_dir = get_proto_home()?;
let registry_path = proto_home_dir.join("shims").join("registry.json");
let mut shim = Json::Object(HashMap::default());
Expand All @@ -92,13 +92,13 @@ fn create_command(args: Vec<String>, shim_name: &str, shim_exe_path: &Path) -> R
if let Json::Array(before_args) = &shim["before_args"] {
for arg in before_args {
if let Json::Str(arg) = arg {
passthrough_args.push(arg);
passthrough_args.push(OsString::from(arg));
}
}
}

if args.len() > 1 {
for (i, arg) in args.iter().enumerate() {
for (i, arg) in args.into_iter().enumerate() {
if i == 0 {
continue; // The exe
}
Expand All @@ -110,14 +110,15 @@ fn create_command(args: Vec<String>, shim_name: &str, shim_exe_path: &Path) -> R
if let Json::Array(after_args) = &shim["after_args"] {
for arg in after_args {
if let Json::Str(arg) = arg {
passthrough_args.push(arg);
passthrough_args.push(OsString::from(arg));
}
}
}

// Create a command for local testing
// let mut command = Command::new("node");
// command.arg("./docs/shim-test.mjs");
// command.arg("--version");

// Create the command and handle alternate logic
let mut command = Command::new(get_proto_binary(&proto_home_dir, shim_exe_path));
Expand Down Expand Up @@ -162,7 +163,7 @@ pub fn main() -> Result<()> {
});

// Extract arguments to pass-through
let args = env::args().collect::<Vec<_>>();
let args = env::args_os().collect::<Vec<_>>();
let exe_path = env::current_exe().unwrap_or_else(|_| PathBuf::from(&args[0]));

let shim_name = exe_path
Expand All @@ -179,29 +180,10 @@ pub fn main() -> Result<()> {
));
}

// Capture any piped input
let input = {
let mut stdin = io::stdin();
let mut buffer = String::new();

// Only read piped data when stdin is not a TTY,
// otherwise the process will hang indefinitely waiting for EOF
if !stdin.is_terminal() {
stdin.read_to_string(&mut buffer)?;
}

buffer
};
let has_piped_stdin = !input.is_empty();

// Create the actual command to execute
// Create the command to execute
let mut command = create_command(args, &shim_name, &exe_path)?;
command.env("PROTO_LOG", log_level);

if has_piped_stdin {
command.stdin(Stdio::piped());
}

// Spawn a shareable child process
trace!(
shim = &shim_name,
Expand All @@ -215,25 +197,13 @@ pub fn main() -> Result<()> {

// Handle CTRL+C and kill the child
ctrlc::set_handler(move || {
trace!("Received CTRL+C, killing child process");
trace!("Received ctrl + c, killing child process");
let _ = child_clone.kill();
})?;

// If we have piped data, pass it through
if has_piped_stdin {
if let Some(mut stdin) = child.take_stdin() {
trace!(
shim = &shim_name,
input,
"Received piped input, passing through"
);
stdin.write_all(input.as_bytes())?;
}
}

// Wait for the process to finish or be killed
let status = child.wait()?;
let code = status.code().unwrap_or(0);
let code = status.code().unwrap_or(1);

trace!(shim = &shim_name, code, "Received exit code");

Expand Down
1 change: 1 addition & 0 deletions crates/cli/tests/fixtures/piped-data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this data comes from a file
1 change: 1 addition & 0 deletions crates/cli/tests/fixtures/shim-code-0.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.exitCode = 0;
1 change: 1 addition & 0 deletions crates/cli/tests/fixtures/shim-code-1.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.exit(1);
31 changes: 31 additions & 0 deletions crates/cli/tests/fixtures/shim-piped-stdin.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
console.log("start");

async function getStdinBuffer() {
if (process.stdin.isTTY) {
return Buffer.alloc(0);
}

const result = [];
let length = 0;

for await (const chunk of process.stdin) {
result.push(chunk);
length += chunk.length;
}

return Buffer.concat(result, length);
}

getStdinBuffer().then((buffer) => {
let data = buffer.toString("utf8");

if (data) {
console.log("piped data =", data.trim());
}
});

setTimeout(() => {
console.log("stop");
}, 2500);

console.log("running");
12 changes: 12 additions & 0 deletions crates/cli/tests/fixtures/shim-signal.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
console.log("start");

process.on("SIGINT", () => {
console.log("killed");
process.exit(1);
});

setTimeout(() => {
console.log("stop");
}, 5000);

console.log("running");
2 changes: 2 additions & 0 deletions crates/cli/tests/fixtures/shim-standard.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
console.log("stdout");
console.error("stderr");
7 changes: 7 additions & 0 deletions crates/cli/tests/fixtures/shim-timeout.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
console.log("start");

setTimeout(() => {
console.log("stop");
}, 2500);

console.log("running");
10 changes: 10 additions & 0 deletions crates/cli/tests/fixtures/shim-tla.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
console.log("start");

await new Promise((resolve) => {
setTimeout(() => {
console.log("running");
resolve();
}, 2500);
});

console.log("stop");
Loading

0 comments on commit 6ca316c

Please sign in to comment.