cargo_e/
e_runner.rs

1use crate::prelude::*;
2// #[cfg(not(feature = "equivalent"))]
3// use ctrlc;
4use crate::Example;
5
6/// In "equivalent" mode, behave exactly like "cargo run --example <name>"
7#[cfg(feature = "equivalent")]
8pub fn run_example(example: &Example, extra_args: &[String]) -> Result<(), Box<dyn Error>> {
9    // In "equivalent" mode, behave exactly like "cargo run --example <name>"
10    let mut cmd = Command::new("cargo");
11    cmd.args(["run", "--example", &example.name]);
12    if !extra_args.is_empty() {
13        cmd.arg("--").args(extra_args);
14    }
15    // Inherit the standard input (as well as stdout/stderr) so that input is passed through.
16    use std::process::Stdio;
17    cmd.stdin(Stdio::inherit())
18        .stdout(Stdio::inherit())
19        .stderr(Stdio::inherit());
20
21    let status = cmd.status()?;
22    std::process::exit(status.code().unwrap_or(1));
23}
24
25/// Runs the given example (or binary) target.
26#[cfg(not(feature = "equivalent"))]
27pub fn run_example(example: &Example, extra_args: &[String]) -> Result<(), Box<dyn Error>> {
28    let mut cmd = Command::new("cargo");
29
30    if example.extended {
31        println!(
32            "Running extended example in folder: examples/{}",
33            example.name
34        );
35        cmd.arg("run")
36            .current_dir(format!("examples/{}", example.name));
37    } else {
38        cmd.args(["run", "--release", "--example", &example.name]);
39    }
40
41    if !extra_args.is_empty() {
42        cmd.arg("--").args(extra_args);
43    }
44
45    let full_command = format!(
46        "cargo {}",
47        cmd.get_args()
48            .map(|arg| arg.to_string_lossy())
49            .collect::<Vec<_>>()
50            .join(" ")
51    );
52    println!("Running: {}", full_command);
53
54    let child = cmd.spawn()?;
55    use std::sync::{Arc, Mutex};
56    let child_arc = Arc::new(Mutex::new(child));
57    let child_for_handler = Arc::clone(&child_arc);
58
59    ctrlc::set_handler(move || {
60        eprintln!("Ctrl+C pressed, terminating process...");
61        let mut child = child_for_handler.lock().unwrap();
62        let _ = child.kill();
63    })?;
64
65    let status = child_arc.lock().unwrap().wait()?;
66    println!("Process exited with status: {:?}", status.code());
67    Ok(())
68}
69
70/// Helper function to spawn a cargo process.
71/// On Windows, this sets the CREATE_NEW_PROCESS_GROUP flag.
72pub fn spawn_cargo_process(args: &[&str]) -> Result<Child, Box<dyn Error>> {
73    #[cfg(windows)]
74    {
75        use std::os::windows::process::CommandExt;
76        const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
77        let child = Command::new("cargo")
78            .args(args)
79            .creation_flags(CREATE_NEW_PROCESS_GROUP)
80            .spawn()?;
81        Ok(child)
82    }
83    #[cfg(not(windows))]
84    {
85        let child = Command::new("cargo").args(args).spawn()?;
86        Ok(child)
87    }
88}