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(target: &Example, extra_args: &[String]) -> Result<(), Box<dyn Error>> {
28    // Retrieve the current package name (or binary name) at compile time.
29    let current_bin = env!("CARGO_PKG_NAME");
30
31    // Avoid running our own binary if the target's name is the same.
32    // this check is for the developer running cargo run --; cargo-e is the only binary and so loops.
33    if target.kind == crate::TargetKind::Binary && target.name == current_bin {
34        return Err(format!(
35            "Skipping automatic run: {} is the same as the running binary",
36            target.name
37        )
38        .into());
39    }
40
41    let mut cmd = Command::new("cargo");
42
43    match target.kind {
44        // For examples:
45        crate::TargetKind::Example => {
46            if target.extended {
47                println!(
48                    "Running extended example in folder: examples/{}",
49                    target.name
50                );
51                cmd.arg("run")
52                    .current_dir(format!("examples/{}", target.name));
53            } else {
54                cmd.args(["run", "--release", "--example", &target.name]);
55            }
56        }
57        // For binaries:
58        crate::TargetKind::Binary => {
59            println!("Running binary: {}", target.name);
60            cmd.args(["run", "--release", "--bin", &target.name]);
61        } // Optionally handle other target kinds.
62          // _ => { unreach able unsupported.
63          //     return Err(format!("Unsupported target kind: {:?}", target.kind).into());
64          // }
65    }
66
67    if !extra_args.is_empty() {
68        cmd.arg("--").args(extra_args);
69    }
70
71    let full_command = format!(
72        "cargo {}",
73        cmd.get_args()
74            .map(|arg| arg.to_string_lossy())
75            .collect::<Vec<_>>()
76            .join(" ")
77    );
78    println!("Running: {}", full_command);
79
80    let child = cmd.spawn()?;
81    use std::sync::{Arc, Mutex};
82    let child_arc = Arc::new(Mutex::new(child));
83    let child_for_handler = Arc::clone(&child_arc);
84
85    ctrlc::set_handler(move || {
86        eprintln!("Ctrl+C pressed, terminating process...");
87        let mut child = child_for_handler.lock().unwrap();
88        let _ = child.kill();
89    })?;
90
91    let status = child_arc.lock().unwrap().wait()?;
92    println!("Process exited with status: {:?}", status.code());
93    Ok(())
94}
95
96/// Helper function to spawn a cargo process.
97/// On Windows, this sets the CREATE_NEW_PROCESS_GROUP flag.
98pub fn spawn_cargo_process(args: &[&str]) -> Result<Child, Box<dyn Error>> {
99    #[cfg(windows)]
100    {
101        use std::os::windows::process::CommandExt;
102        const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
103        let child = Command::new("cargo")
104            .args(args)
105            .creation_flags(CREATE_NEW_PROCESS_GROUP)
106            .spawn()?;
107        Ok(child)
108    }
109    #[cfg(not(windows))]
110    {
111        let child = Command::new("cargo").args(args).spawn()?;
112        Ok(child)
113    }
114}