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(
54 target: &Example,
55 extra_args: &[String],
56) -> Result<std::process::ExitStatus, Box<dyn Error>> {
57 let current_bin = env!("CARGO_PKG_NAME");
59
60 if target.kind == crate::TargetKind::Binary && target.name == current_bin {
62 return Err(format!(
63 "Skipping automatic run: {} is the same as the running binary",
64 target.name
65 )
66 .into());
67 }
68
69 let mut cmd = Command::new("cargo");
70 let manifest_path: PathBuf;
72
73 match target.kind {
74 crate::TargetKind::Example => {
75 if target.extended {
76 println!(
77 "Running extended example in folder: examples/{}",
78 target.name
79 );
80 manifest_path = PathBuf::from(format!("examples/{}/Cargo.toml", target.name));
82 cmd.arg("run")
83 .current_dir(format!("examples/{}", target.name));
84 } else {
85 manifest_path = PathBuf::from(crate::locate_manifest(false)?);
86 cmd.args(["run", "--release", "--example", &target.name]);
87 }
88 }
89 crate::TargetKind::Binary => {
90 println!("Running binary: {}", target.name);
91 manifest_path = PathBuf::from(crate::locate_manifest(false)?);
92 cmd.args(["run", "--release", "--bin", &target.name]);
93 }
94 }
95
96 if !extra_args.is_empty() {
97 cmd.arg("--").args(extra_args);
98 }
99
100 let full_command = format!(
101 "cargo {}",
102 cmd.get_args()
103 .map(|arg| arg.to_string_lossy())
104 .collect::<Vec<_>>()
105 .join(" ")
106 );
107 println!("Running: {}", full_command);
108
109 let maybe_backup = crate::e_manifest::maybe_patch_manifest_for_run(&manifest_path)?;
112
113 let child = cmd.spawn()?;
115 {
116 let mut global = GLOBAL_CHILD.lock().unwrap();
117 *global = Some(child);
118 }
119 let status = {
120 let mut global = GLOBAL_CHILD.lock().unwrap();
121 if let Some(mut child) = global.take() {
122 child.wait()?
123 } else {
124 return Err("Child process missing".into());
125 }
126 };
127
128 if let Some(original) = maybe_backup {
130 fs::write(&manifest_path, original)?;
131 }
132
133 Ok(status)
135}
136pub fn spawn_cargo_process(args: &[&str]) -> Result<Child, Box<dyn Error>> {
139 #[cfg(windows)]
140 {
141 use std::os::windows::process::CommandExt;
142 const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
143 let child = Command::new("cargo")
144 .args(args)
145 .creation_flags(CREATE_NEW_PROCESS_GROUP)
146 .spawn()?;
147 Ok(child)
148 }
149 #[cfg(not(windows))]
150 {
151 let child = Command::new("cargo").args(args).spawn()?;
152 Ok(child)
153 }
154}