1use crate::prelude::*;
2use crate::Example;
5use once_cell::sync::Lazy;
6
7static GLOBAL_CHILD: Lazy<Arc<Mutex<Option<Child>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
9
10pub fn register_ctrlc_handler() -> Result<(), Box<dyn Error>> {
13 ctrlc::set_handler(move || {
14 let mut child_lock = GLOBAL_CHILD.lock().unwrap();
15 if let Some(child) = child_lock.as_mut() {
16 eprintln!("Ctrl+C pressed, terminating running child process...");
17 let _ = child.kill();
18 } else {
19 eprintln!("Ctrl+C pressed, no child process running. Exiting nicely.");
20 exit(0);
21 }
22 })?;
23 Ok(())
24}
25
26#[cfg(feature = "equivalent")]
28pub fn run_example(
29 example: &Example,
30 extra_args: &[String],
31) -> Result<std::process::ExitStatus, Box<dyn Error>> {
32 let mut cmd = Command::new("cargo");
34 cmd.args(["run", "--example", &example.name]);
35 if !extra_args.is_empty() {
36 cmd.arg("--").args(extra_args);
37 }
38 use std::process::Stdio;
40 cmd.stdin(Stdio::inherit())
41 .stdout(Stdio::inherit())
42 .stderr(Stdio::inherit());
43
44 let status = cmd.status()?;
45 std::process::exit(status.code().unwrap_or(1));
46}
47
48#[cfg(not(feature = "equivalent"))]
50pub fn run_example(
51 target: &Example,
52 extra_args: &[String],
53) -> Result<std::process::ExitStatus, Box<dyn Error>> {
54 let current_bin = env!("CARGO_PKG_NAME");
56
57 if target.kind == crate::TargetKind::Binary && target.name == current_bin {
60 return Err(format!(
61 "Skipping automatic run: {} is the same as the running binary",
62 target.name
63 )
64 .into());
65 }
66
67 let mut cmd = Command::new("cargo");
68
69 match target.kind {
70 crate::TargetKind::Example => {
72 if target.extended {
73 println!(
74 "Running extended example in folder: examples/{}",
75 target.name
76 );
77 cmd.arg("run")
78 .current_dir(format!("examples/{}", target.name));
79 } else {
80 cmd.args(["run", "--release", "--example", &target.name]);
81 }
82 }
83 crate::TargetKind::Binary => {
85 println!("Running binary: {}", target.name);
86 cmd.args(["run", "--release", "--bin", &target.name]);
87 } }
92
93 if !extra_args.is_empty() {
94 cmd.arg("--").args(extra_args);
95 }
96
97 let full_command = format!(
98 "cargo {}",
99 cmd.get_args()
100 .map(|arg| arg.to_string_lossy())
101 .collect::<Vec<_>>()
102 .join(" ")
103 );
104 println!("Running: {}", full_command);
105
106 let child = cmd.spawn()?;
108 {
109 let mut global = GLOBAL_CHILD.lock().unwrap();
111 *global = Some(child);
112 }
113 let status = {
115 let mut global = GLOBAL_CHILD.lock().unwrap();
116 if let Some(mut child) = global.take() {
118 child.wait()?
119 } else {
120 return Err("Child process missing".into());
121 }
122 };
123
124 println!("Process exited with status: {:?}", status.code());
137 Ok(status)
138}
139
140pub fn spawn_cargo_process(args: &[&str]) -> Result<Child, Box<dyn Error>> {
143 #[cfg(windows)]
144 {
145 use std::os::windows::process::CommandExt;
146 const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
147 let child = Command::new("cargo")
148 .args(args)
149 .creation_flags(CREATE_NEW_PROCESS_GROUP)
150 .spawn()?;
151 Ok(child)
152 }
153 #[cfg(not(windows))]
154 {
155 let child = Command::new("cargo").args(args).spawn()?;
156 Ok(child)
157 }
158}