cargo_e/
e_runner.rs

1use crate::e_processmanager::ProcessManager;
2use crate::{e_target::TargetOrigin, prelude::*};
3// #[cfg(not(feature = "equivalent"))]
4// use ctrlc;
5use crate::e_cargocommand_ext::CargoProcessHandle;
6use crate::e_target::CargoTarget;
7#[cfg(feature = "uses_plugins")]
8use crate::plugins::plugin_api::Target as PluginTarget;
9use anyhow::Result;
10use once_cell::sync::Lazy;
11use regex::Regex;
12use std::collections::HashMap;
13use std::fs::File;
14use std::io::{self, BufRead};
15use std::path::Path;
16use std::process::Command;
17use std::sync::atomic::{AtomicUsize, Ordering};
18use std::thread;
19use which::which; // Adjust the import based on your project structure
20
21// lazy_static! {
22//     pub static ref GLOBAL_CHILDREN: Arc<Mutex<Vec<Arc<CargoProcessHandle>>>> = Arc::new(Mutex::new(Vec::new()));
23//     static CTRL_C_COUNT: Lazy<Mutex<u32>> = Lazy::new(|| Mutex::new(0));
24// }
25
26// pub static GLOBAL_CHILDREN:     Lazy<Arc<Mutex<Vec<Arc<Mutex<CargoProcessHandle>>>>>> = Lazy::new(|| Arc::new(Mutex::new(Vec::new())));
27pub static GLOBAL_CHILDREN: Lazy<Arc<Mutex<HashMap<u32, Arc<Mutex<CargoProcessHandle>>>>>> =
28    Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));
29
30static CTRL_C_COUNT: AtomicUsize = AtomicUsize::new(0);
31
32// Global shared container for the currently running child process.
33// pub static GLOBAL_CHILD: Lazy<Arc<Mutex<Option<Child>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
34// static CTRL_C_COUNT: Lazy<Mutex<u32>> = Lazy::new(|| Mutex::new(0));
35
36// pub static GLOBAL_CHILDREN: Lazy<Arc<Mutex<VecDeque<CargoProcessHandle>>>> = Lazy::new(|| Arc::new(Mutex::new(VecDeque::new())));
37/// Resets the Ctrl+C counter.
38/// This can be called to reset the count when starting a new program or at any other point.
39pub fn reset_ctrl_c_count() {
40    CTRL_C_COUNT.store(0, std::sync::atomic::Ordering::SeqCst);
41}
42
43// pub fn kill_last_process() -> Result<()> {
44//     let mut global = GLOBAL_CHILDREN.lock().unwrap();
45
46//     if let Some(mut child_handle) = global.pop_back() {
47//         // Kill the most recent process
48//         eprintln!("Killing the most recent child process...");
49//         let _ = child_handle.kill();
50//         Ok(())
51//     } else {
52//         eprintln!("No child processes to kill.");
53//         Err(anyhow::anyhow!("No child processes to kill").into())
54//     }
55// }
56
57pub fn take_process_results(pid: u32) -> Option<CargoProcessHandle> {
58    let mut global = GLOBAL_CHILDREN.lock().ok()?;
59    // Take ownership
60    // let handle = global.remove(&pid)?;
61    // let mut handle = handle.lock().ok()?;
62    let handle = global.remove(&pid)?;
63    // global.remove(&pid)
64    // This will succeed only if no other Arc exists
65    Arc::try_unwrap(handle)
66        .ok()? // fails if other Arc exists
67        .into_inner()
68        .ok() // fails if poisoned
69}
70
71pub fn get_process_results_in_place(
72    pid: u32,
73) -> Option<crate::e_cargocommand_ext::CargoProcessResult> {
74    let global = GLOBAL_CHILDREN.lock().ok()?; // MutexGuard<HashMap>
75    let handle = global.get(&pid)?.clone(); // Arc<Mutex<CargoProcessHandle>>
76    let handle = handle.lock().ok()?; // MutexGuard<CargoProcessHandle>
77    Some(handle.result.clone()) // ✅ return the result field
78}
79
80// /// Registers a global Ctrl+C handler that interacts with the `GLOBAL_CHILDREN` process container.
81// pub fn register_ctrlc_handler() -> Result<(), Box<dyn Error>> {
82//     println!("Registering Ctrl+C handler...");
83//     ctrlc::set_handler(move || {
84//          let count = CTRL_C_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1;
85//         {
86//             eprintln!("Ctrl+C pressed");
87
88//     // lock only ONE mutex safely
89//     if let Ok(mut global) = GLOBAL_CHILDREN.try_lock() {
90//             // let mut global = GLOBAL_CHILDREN.lock().unwrap();
91//             eprintln!("Ctrl+C got lock on global container");
92
93//             // If there are processes in the global container, terminate the most recent one
94//             if let Some((pid, child_handle)) = global.iter_mut().next() {
95//                 eprintln!("Ctrl+C pressed, terminating the child process with PID: {}", pid);
96
97//                 // Lock the child process and kill it
98//                 let mut child_handle = child_handle.lock().unwrap();
99//                 if child_handle.requested_exit {
100//                     eprintln!("Child process is already requested kill...");
101//                 } else {
102//                     eprintln!("Child process is not running, no need to kill.");
103//                     child_handle.requested_exit=true;
104//                     println!("Killing child process with PID: {}", pid);
105//                     let _ = child_handle.kill();  // Attempt to kill the process
106//                     println!("Killed child process with PID: {}", pid);
107
108//                     reset_ctrl_c_count();
109//                     return;  // Exit after successfully terminating the process
110//                 }
111
112//                 // Now remove the process from the global container
113//                 // let pid_to_remove = *pid;
114
115//                 // // Reacquire the lock after killing and remove the process from global
116//                 // drop(global);  // Drop the first borrow
117
118//                 // // Re-lock global and safely remove the entry using the pid
119//                 // let mut global = GLOBAL_CHILDREN.lock().unwrap();
120//                 // global.remove(&pid_to_remove); // Remove the process entry by PID
121//                 // println!("Removed process with PID: {}", pid_to_remove);
122//             }
123
124//     } else {
125//         eprintln!("Couldn't acquire GLOBAL_CHILDREN lock safely");
126//     }
127
128/// Registers a global Ctrl+C handler that uses the process manager.
129pub fn register_ctrlc_handler(process_manager: Arc<ProcessManager>) -> Result<(), Box<dyn Error>> {
130    println!("Registering Ctrl+C handler...");
131    ctrlc::set_handler(move || {
132        let count = CTRL_C_COUNT.fetch_add(1, Ordering::SeqCst) + 1;
133        eprintln!("Ctrl+C pressed");
134
135        // Use the process manager's API to handle killing
136        match process_manager.kill_one() {
137            Ok(true) => {
138                eprintln!("Process was successfully terminated.");
139                reset_ctrl_c_count();
140                return; // Exit handler early after a successful kill.
141            }
142            Ok(false) => {
143                eprintln!("No process was killed this time.");
144            }
145            Err(e) => {
146                eprintln!("Error killing process: {:?}", e);
147            }
148        }
149
150        // Handle Ctrl+C count logic for exiting the program.
151        if count == 3 {
152            eprintln!("Ctrl+C pressed 3 times with no child process running. Exiting.");
153            std::process::exit(0);
154        } else if count == 2 {
155            eprintln!("Ctrl+C pressed 2 times, press one more to exit.");
156        } else {
157            eprintln!("Ctrl+C pressed {} times, no child process running.", count);
158        }
159    })?;
160    Ok(())
161}
162
163//         }
164
165//         // Now handle the Ctrl+C count and display messages
166//         // If Ctrl+C is pressed 3 times without any child process, exit the program.
167//         if count == 3 {
168//             eprintln!("Ctrl+C pressed 3 times with no child process running. Exiting.");
169//             std::process::exit(0);
170//         } else if count == 2 {
171//             // Notify that one more Ctrl+C will exit the program.
172//             eprintln!("Ctrl+C pressed 2 times, press one more to exit.");
173//         } else {
174//             eprintln!("Ctrl+C pressed {} times, no child process running.", count);
175//         }
176//     })?;
177//     Ok(())
178// }
179
180// /// Registers a global Ctrl+C handler once.
181// /// The handler checks GLOBAL_CHILD and kills the child process if present.
182// pub fn register_ctrlc_handler() -> Result<(), Box<dyn Error>> {
183//     ctrlc::set_handler(move || {
184//         let mut count_lock = CTRL_C_COUNT.lock().unwrap();
185//         *count_lock += 1;
186
187//         let count = *count_lock;
188
189//         // If there is no child process and Ctrl+C is pressed 3 times, exit the program
190//         if count == 3 {
191//             eprintln!("Ctrl+C pressed 3 times with no child process running. Exiting.");
192//             exit(0);
193//         } else {
194//             let mut child_lock = GLOBAL_CHILD.lock().unwrap();
195//             if let Some(child) = child_lock.as_mut() {
196//                 eprintln!(
197//                     "Ctrl+C pressed {} times, terminating running child process...",
198//                     count
199//                 );
200//                 let _ = child.kill();
201//             } else {
202//                 eprintln!("Ctrl+C pressed {} times, no child process running.", count);
203//             }
204//         }
205//     })?;
206//     Ok(())
207// }
208
209/// Asynchronously launches the GenAI summarization example for the given target.
210/// It builds the command using the target's manifest path as the "origin" argument.
211pub async fn open_ai_summarize_for_target(target: &CargoTarget) {
212    // Extract the origin path from the target (e.g. the manifest path).
213    let origin_path = match &target.origin {
214        Some(TargetOrigin::SingleFile(path)) | Some(TargetOrigin::DefaultBinary(path)) => path,
215        _ => return,
216    };
217
218    let exe_path = match which("cargoe_ai_summarize") {
219        Ok(path) => path,
220        Err(err) => {
221            eprintln!("Error: 'cargoe_ai_summarize' not found in PATH: {}", err);
222            return;
223        }
224    };
225    // Build the command based on the platform.
226    // let mut cmd = if cfg!(target_os = "windows") {
227    //     let command_str = format!(
228    //         "e_ai_summarize --streaming --stdin {}",
229    //         origin_path.as_os_str().to_string_lossy()
230    //     );
231    //     println!("Running command: {}", command_str);
232    //     let mut command = Command::new("cmd");
233    //     command.args(["/C", &command_str]);
234    //     command
235    // } else {
236    let mut cmd = Command::new(exe_path);
237    cmd.arg("--streaming");
238    cmd.arg("--stdin");
239    // cmd.arg(".");
240    cmd.arg(origin_path);
241    // command
242    // };
243
244    cmd.stdin(Stdio::inherit())
245        .stdout(Stdio::inherit())
246        .stderr(Stdio::inherit());
247
248    // Spawn the command and wait for it to finish.
249    let child = cmd.spawn();
250    let status = child
251        .expect("Failed to spawn command")
252        .wait()
253        .expect("Failed to wait for command");
254
255    if !status.success() {
256        eprintln!("Command exited with status: {}", status);
257    }
258
259    // // Build the command to run the example.
260    // let output = if cfg!(target_os = "windows") {
261    //     let command_str = format!("e_ai_summarize --stdin {}", origin_path.as_os_str().to_string_lossy());
262    //     println!("Running command: {}", command_str);
263    //     Command::new("cmd")
264    //         .args([
265    //             "/C",
266    //             command_str.as_str(),
267    //         ])
268    //         .output()
269    // } else {
270    //     Command::new("e_ai_summarize")
271    //         .args([origin_path])
272    //         .output()
273    // };
274
275    // // Handle the output from the command.
276    // match output {
277    //     Ok(output) if output.status.success() => {
278    //         // The summarization example ran successfully.
279    //         println!("----
280    //         {}", String::from_utf8_lossy(&output.stdout));
281    //     }
282    //     Ok(output) => {
283    //         let msg = format!(
284    //             "Error running summarization example:\nstdout: {}\nstderr: {}",
285    //             String::from_utf8_lossy(&output.stdout),
286    //             String::from_utf8_lossy(&output.stderr)
287    //         );
288    //         error!("{}", msg);
289    //     }
290    //     Err(e) => {
291    //         let msg = format!("Failed to execute summarization command: {}", e);
292    //         error!("{}", msg);
293    //     }
294    // }
295}
296
297fn library_hint(lib: &str) -> &str {
298    match lib {
299        "javascriptcoregtk-4.1" => "libjavascriptcoregtk-4.1-dev",
300        "libsoup-3.0" => "libsoup-3.0-dev",
301        "webkit2gtk-4.1" => "libwebkit2gtk-4.1-dev",
302        "openssl" => "libssl-dev",
303        _ => lib, // Fallback, assume same name
304    }
305}
306
307/// In "equivalent" mode, behave exactly like "cargo run --example <name>"
308#[cfg(feature = "equivalent")]
309pub fn run_equivalent_example(
310    cli: &crate::Cli,
311) -> Result<std::process::ExitStatus, Box<dyn Error>> {
312    // In "equivalent" mode, behave exactly like "cargo run --example <name>"
313    let mut cmd = Command::new("cargo");
314    cmd.args([
315        "run",
316        "--example",
317        cli.explicit_example.as_deref().unwrap_or(""),
318    ]);
319    if !cli.extra.is_empty() {
320        cmd.arg("--").args(cli.extra.clone());
321    }
322    // Inherit the standard input (as well as stdout/stderr) so that input is passed through.
323    use std::process::Stdio;
324    cmd.stdin(Stdio::inherit())
325        .stdout(Stdio::inherit())
326        .stderr(Stdio::inherit());
327
328    let status = cmd.status()?;
329    std::process::exit(status.code().unwrap_or(1));
330}
331
332/// Runs the given example (or binary) target.
333pub fn run_example(
334    manager: Arc<ProcessManager>,
335    cli: &crate::Cli,
336    target: &crate::e_target::CargoTarget,
337) -> anyhow::Result<Option<std::process::ExitStatus>> {
338    crate::e_runall::set_rustflags_if_quiet(cli.quiet);
339    // Retrieve the current package name at compile time.
340    let current_bin = env!("CARGO_PKG_NAME");
341
342    // Avoid running our own binary.
343    if target.kind == crate::e_target::TargetKind::Binary && target.name == current_bin {
344        println!(
345            "Skipping automatic run: {} is the same as the running binary",
346            target.name
347        );
348        return Ok(None);
349    }
350
351    // If this is a plugin-provided target, execute it via the plugin's in-process run
352    #[cfg(feature = "uses_plugins")]
353    if target.kind == crate::e_target::TargetKind::Plugin {
354        if let Some(crate::e_target::TargetOrigin::Plugin { plugin_path, .. }) = &target.origin {
355            // Current working directory
356            let cwd = std::env::current_dir()?;
357            // Load the plugin directly based on its file extension
358            let ext = plugin_path
359                .extension()
360                .and_then(|s| s.to_str())
361                .unwrap_or("");
362            let plugin: Box<dyn crate::plugins::plugin_api::Plugin> = match ext {
363                "lua" => {
364                    #[cfg(feature = "uses_lua")]
365                    {
366                        Box::new(crate::plugins::lua_plugin::LuaPlugin::load(
367                            plugin_path,
368                            cli,
369                            manager.clone(),
370                        )?)
371                    }
372                    #[cfg(not(feature = "uses_lua"))]
373                    {
374                        return Err(anyhow::anyhow!("Lua plugin support is not enabled"));
375                    }
376                }
377                "rhai" => {
378                    #[cfg(feature = "uses_rhai")]
379                    {
380                        Box::new(crate::plugins::rhai_plugin::RhaiPlugin::load(
381                            plugin_path,
382                            cli,
383                            manager.clone(),
384                        )?)
385                    }
386                    #[cfg(not(feature = "uses_rhai"))]
387                    {
388                        return Err(anyhow::anyhow!("Rhai plugin support is not enabled"));
389                    }
390                }
391                "wasm" => {
392                    #[cfg(feature = "uses_wasm")]
393                    {
394                        if let Some(wp) =
395                            crate::plugins::wasm_plugin::WasmPlugin::load(plugin_path)?
396                        {
397                            Box::new(wp)
398                        } else {
399                            // Fallback to generic export plugin
400                            Box::new(
401                                crate::plugins::wasm_export_plugin::WasmExportPlugin::load(
402                                    plugin_path,
403                                )?
404                                .expect("Failed to load export plugin"),
405                            )
406                        }
407                    }
408                    #[cfg(not(feature = "uses_wasm"))]
409                    {
410                        return Err(anyhow::anyhow!("WASM plugin support is not enabled"));
411                    }
412                }
413                "dll" => {
414                    #[cfg(feature = "uses_wasm")]
415                    {
416                        Box::new(
417                            crate::plugins::wasm_export_plugin::WasmExportPlugin::load(
418                                plugin_path,
419                            )?
420                            .expect("Failed to load export plugin"),
421                        )
422                    }
423                    #[cfg(not(feature = "uses_wasm"))]
424                    {
425                        return Err(anyhow::anyhow!("WASM export plugin support is not enabled"));
426                    }
427                }
428                other => {
429                    return Err(anyhow::anyhow!("Unknown plugin extension: {}", other));
430                }
431            };
432            // Run the plugin and capture output
433            let plugin_target = PluginTarget::from(target.clone());
434            let output = plugin.run(&cwd, &plugin_target)?;
435            // Print exit code and subsequent output lines
436            if !output.is_empty() {
437                if let Ok(code) = output[0].parse::<i32>() {
438                    eprintln!("Plugin exited with code: {}", code);
439                }
440                for line in &output[1..] {
441                    println!("{}", line);
442                }
443            }
444            return Ok(None);
445        }
446    }
447    // Not a plugin, continue with standard cargo invocation
448    let manifest_path = PathBuf::from(target.manifest_path.clone());
449    // Build the command using the CargoCommandBuilder.
450    let mut builder = crate::e_command_builder::CargoCommandBuilder::new(
451        &target.name,
452        &manifest_path,
453        &cli.subcommand,
454        cli.filter,
455        cli.cached,
456        cli.default_binary_is_runner,
457        cli.quiet || cli.json_all_targets,
458        cli.detached,
459        cli.cwd_wsr,
460    )
461    .with_target(target)
462    .with_required_features(&target.manifest_path, target)
463    .with_cli(cli);
464
465    // Build the command.
466    let mut cmd = builder.clone().build_command();
467
468    // Before spawning, determine the directory to run from.
469    // By default, run from the current working directory (cwd).
470    // If --cwd-wsr is specified, run from the workspace root (manifest's parent directory).
471    let mut exec_dir: Option<std::path::PathBuf> = None;
472    if let Some(ref dir) = builder.execution_dir {
473        cmd.current_dir(dir);
474        exec_dir = Some(dir.as_path().to_path_buf());
475    } else if cli.cwd_wsr {
476        // Assume cli has a field `cwd_wsr: bool` set by --cwd-wsr
477        if let Some(dir) = target.manifest_path.parent() {
478            cmd.current_dir(dir);
479            exec_dir = Some(dir.to_path_buf());
480        }
481    } // else: do not set current_dir, so it runs from process cwd
482
483    // Print the full command for debugging.
484    let full_command = format!(
485        "{} {}",
486        cmd.get_program().to_string_lossy(),
487        cmd.get_args()
488            .map(|arg| arg.to_string_lossy())
489            .collect::<Vec<_>>()
490            .join(" ")
491    );
492    println!("Running: {}  [from {:?}]", full_command, exec_dir);
493
494    // Check if the manifest triggers the workspace error.
495    let maybe_backup = crate::e_manifest::maybe_patch_manifest_for_run(&target.manifest_path)?;
496    let a_blder = Arc::new(builder.clone());
497    let pid = a_blder.run(|pid, handle| {
498        manager.register(pid, handle);
499    })?;
500    let result = manager.wait(pid, None)?;
501    // println!("HERE IS THE RESULT!{} {:?}",pid,manager.get(pid));
502    // println!("\n\nHERE IS THE RESULT!{} {:?}",pid,result);
503    if result
504        .exit_status
505        .map_or(false, |status| status.code() == Some(101))
506    {
507        println!(
508            "ProcessManager senses pid {} cargo error, running again to capture and analyze",
509            pid,
510        );
511        match builder.clone().capture_output() {
512            Ok(output) => {
513                let system_lib_regex = Regex::new(
514                    r"\s*The system library `([^`]+)` required by crate `([^`]+)` was not found\.",
515                )
516                .unwrap();
517
518                if let Some(captures) = system_lib_regex.captures(&output) {
519                    let library = &captures[1];
520                    let crate_name = &captures[2];
521                    println!(
522                        "cargo-e detected missing system library '{}' required by crate '{}'.",
523                        library, crate_name
524                    );
525
526                    // Suggest installation based on common package managers
527                    println!(
528                        "You might need to install '{}' via your system package manager.",
529                        library
530                    );
531                    println!("For example:");
532
533                    println!(
534                        "  • Debian/Ubuntu: sudo apt install {}",
535                        library_hint(library)
536                    );
537                    println!("  • Fedora: sudo dnf install {}", library_hint(library));
538                    println!("  • Arch: sudo pacman -S {}", library_hint(library));
539                    println!(
540                        "  • macOS (Homebrew): brew install {}",
541                        library_hint(library)
542                    );
543                    std::process::exit(0);
544                } else if output.contains("error: failed to load manifest for workspace member") {
545                    println!("cargo-e error: failed to load manifest for workspace member, please check your workspace configuration.");
546                    println!("cargo-e autorecovery: removing manfifest path from argument and changing to parent of Cargo.toml.");
547                    let cwd = target
548                        .manifest_path
549                        .parent()
550                        .unwrap_or_else(|| Path::new("."));
551                    // Rebuild the command with the new cwd
552                    builder.execution_dir = Some(cwd.to_path_buf());
553                    // Remove --manifest-path and its associated value from the args array
554                    if let Some(pos) = builder.args.iter().position(|arg| arg == "--manifest-path")
555                    {
556                        // Remove --manifest-path and the next argument (the manifest path value)
557                        builder.args.remove(pos); // Remove --manifest-path
558                        if pos < builder.args.len() {
559                            builder.args.remove(pos); // Remove the manifest path value
560                        }
561                    }
562                    let mut cmd = builder.clone().build_command();
563                    cmd.current_dir(cwd);
564
565                    // Retry the command execution
566                    let mut child = cmd.spawn()?;
567                    let status = child.wait()?;
568                    return Ok(Some(status)); // Return the exit status after retrying
569                                             // return run_example(manager, cli, target);  // Recursively call run_example
570                }
571                if output.contains("no such command: `tauri`") {
572                    println!("cargo tauri is not installed, please install it with cargo install tauri-cli");
573                    // Use the yesno function to prompt the user
574                    match crate::e_prompts::yesno(
575                        "Do you want to install tauri-cli?",
576                        Some(true), // Default to yes
577                    ) {
578                        Ok(Some(true)) => {
579                            println!("Installing tauri-cli...");
580                            match spawn_cargo_process(&["install", "tauri-cli"]) {
581                                Ok(mut child) => {
582                                    child.wait().ok(); // Wait for the installation to finish
583                                } // Installation successful
584                                Err(e) => {
585                                    eprintln!("Error installing tauri-cli: {}", e);
586                                }
587                            }
588                        }
589                        Ok(Some(false)) => {}
590                        Ok(None) => {
591                            println!("Installation cancelled (timeout or invalid input).");
592                        }
593                        Err(e) => {
594                            eprintln!("Error during prompt: {}", e);
595                        }
596                    }
597                } else if output.contains("error: no such command: `leptos`") {
598                    println!("cargo-leptos is not installed, please install it with cargo install cargo-leptos");
599                    // Use the yesno function to prompt the user
600                    match crate::e_prompts::yesno(
601                        "Do you want to install cargo-leptos?",
602                        Some(true), // Default to yes
603                    ) {
604                        Ok(Some(true)) => {
605                            println!("Installing cargo-leptos...");
606                            match spawn_cargo_process(&["install", "cargo-leptos"]) {
607                                Ok(mut child) => {
608                                    child.wait().ok(); // Wait for the installation to finish
609                                } // Installation successful
610                                Err(e) => {
611                                    eprintln!("Error installing cargo-leptos: {}", e);
612                                }
613                            }
614                        }
615                        Ok(Some(false)) => {}
616                        Ok(None) => {
617                            println!("Installation cancelled (timeout or invalid input).");
618                        }
619                        Err(e) => {
620                            eprintln!("Error during prompt: {}", e);
621                        }
622                    }
623                    // needed for cargo-leptos but as part of tool installer
624                    //   } else if output.contains("Command 'perl' not found. Is perl installed?") {
625                    //     println!("cargo e sees a perl issue; maybe a prompt in the future or auto-resolution.");
626                    //     crate::e_autosense::auto_sense_perl();
627                  }  else if output.contains("Unable to find libclang")
628      || output.contains("couldn't find any valid shared libraries matching: ['clang.dll', 'libclang.dll']") 
629{
630    crate::e_autosense::auto_sense_llvm();
631
632                } else if output.contains("no such command: `dx`") {
633                    println!("cargo dx is not installed, please install it with cargo install dioxus-cli");
634                } else if output.contains("no such command: `scriptisto`") {
635                    println!("cargo scriptisto is not installed, please install it with cargo install scriptisto");
636                } else if output.contains("no such command: `rust-script`") {
637                    println!("cargo rust-script is not installed, please install it with cargo install rust-script");
638                } else if output.contains(
639                    "No platform feature enabled. Please enable one of the following features:",
640                ) {
641                    println!("cargo e sees a dioxus issue; maybe a prompt in the future or auto-resolution.");
642                } else {
643                    //println!("cargo error: {}", output);
644                }
645            }
646            Err(e) => {
647                eprintln!("Error running cargo: {}", e);
648            }
649        }
650    }
651    // let is_run_command = matches!(cli.subcommand.as_str(), "run" | "r");
652    // if !is_run_command && result.is_filter || ( result.is_filter && !result.is_could_not_compile ) {
653    result.print_exact();
654    result.print_compact();
655    result.print_short();
656    manager.print_prefixed_summary();
657    let errors: Vec<_> = result
658        .diagnostics
659        .iter()
660        .filter(|d| d.level.eq("error"))
661        .collect();
662    let error_width = errors.len().to_string().len().max(1);
663    let line: Vec<String> = errors
664        .iter()
665        .enumerate()
666        .map(|(i, diag)| {
667            let index = format!("{:0width$}", i + 1, width = error_width);
668            let lineref = if diag.lineref.is_empty() {
669                ""
670            } else {
671                &diag.lineref
672            };
673            // Resolve filename to full path
674            let (filename, goto) = if let Some((file, line, col)) = diag
675                .lineref
676                .split_once(':')
677                .and_then(|(f, rest)| rest.split_once(':').and_then(|(l, c)| Some((f, l, c))))
678            {
679                let full_path = std::fs::canonicalize(file).unwrap_or_else(|_| {
680                    let manifest_dir = std::path::Path::new(&manifest_path)
681                        .parent()
682                        .unwrap_or_else(|| {
683                            eprintln!(
684                                "Failed to determine parent directory for manifest: {:?}",
685                                manifest_path
686                            );
687                            std::path::Path::new(".")
688                        });
689                    let fallback_path = manifest_dir.join(file);
690                    std::fs::canonicalize(&fallback_path).unwrap_or_else(|_| {
691                        let parent_fallback_path = manifest_dir.join("../").join(file);
692                        std::fs::canonicalize(&parent_fallback_path).unwrap_or_else(|_| {
693                            eprintln!("Failed to resolve full path for: {} using ../", file);
694                            file.into()
695                        })
696                    })
697                });
698                let stripped_file = full_path.to_string_lossy().replace("\\\\?\\", "");
699
700                (stripped_file.to_string(), format!("{}:{}", line, col))
701            } else {
702                ("".to_string(), "".to_string())
703            };
704            let code_path = which("code").unwrap_or_else(|_| "code".to_string().into());
705            format!(
706                "{}: {}\nanchor:{}: {}\\n {}|\"{}\" --goto \"{}:{}\"\n",
707                index,
708                diag.message.trim(),
709                index,
710                diag.message.trim(),
711                lineref,
712                code_path.display(),
713                filename,
714                goto,
715            )
716        })
717        .collect();
718    if !errors.is_empty() {
719        if let Ok(e_window_path) = which("e_window") {
720            // Compose a nice message for e_window's stdin
721            let stats = result.stats;
722            // Compose a table with cargo-e and its version, plus panic info
723            let cargo_e_version = env!("CARGO_PKG_VERSION");
724            let card = format!(
725                "--title \"failed build: {target}\" --width 400 --height 300 --decode-debug\n\
726                target | {target} | string\n\
727                cargo-e | {version} | string\n\
728                \n\
729                failed build: {target}\n{errors} errors.\n\n{additional_errors}",
730                target = stats.target_name,
731                version = cargo_e_version,
732                errors = errors.len(),
733                additional_errors = line
734                    .iter()
735                    .map(|l| l.as_str())
736                    .collect::<Vec<_>>()
737                    .join("\n"),
738            );
739            // Set the working directory to the manifest's parent directory
740            let manifest_dir = std::path::Path::new(&manifest_path)
741                .parent()
742                .unwrap_or_else(|| {
743                    eprintln!(
744                        "Failed to determine parent directory for manifest: {:?}",
745                        target.manifest_path
746                    );
747                    std::path::Path::new(".")
748                });
749
750            let child = std::process::Command::new(e_window_path)
751                .current_dir(manifest_dir) // Set working directory
752                .stdin(std::process::Stdio::piped())
753                .spawn();
754            if let Ok(mut child) = child {
755                if let Some(stdin) = child.stdin.as_mut() {
756                    use std::io::Write;
757                    let _ = stdin.write_all(card.as_bytes());
758                    if let Some(global) = crate::GLOBAL_EWINDOW_PIDS.get() {
759                        global.insert(child.id(), child.id());
760                        println!("[DEBUG] Added pid {} to GLOBAL_EWINDOW_PIDS", pid);
761                    } else {
762                        eprintln!("[DEBUG] GLOBAL_EWINDOW_PIDS is not initialized");
763                        // If GLOBAL_EWINDOW_PIDS is not initialized, you may want to initialize it or handle the error accordingly.
764                        // For now, just print a debug message.
765                    }
766                }
767            }
768        }
769    }
770
771    // }
772
773    // let handle=    Arc::new(builder).run_wait()?;
774    // Spawn the process.
775    // let child = cmd.spawn()?;
776    // {
777    //     let mut global = GLOBAL_CHILD.lock().unwrap();
778    //     *global = Some(child);
779    // }
780    // let status = {
781    //     let mut global = GLOBAL_CHILD.lock().unwrap();
782    //     if let Some(mut child) = global.take() {
783    //         child.wait()?
784    //     } else {
785    //         return Err(anyhow::anyhow!("Child process missing"));
786    //     }
787    // };
788
789    // Restore the manifest if we patched it.
790    if let Some(original) = maybe_backup {
791        fs::write(&target.manifest_path, original)?;
792    }
793    #[cfg(feature = "uses_tts")]
794    wait_for_tts_to_finish(15000);
795
796    Ok(result.exit_status)
797}
798
799#[cfg(feature = "uses_tts")]
800pub fn wait_for_tts_to_finish(max_wait_ms: u64) {
801    let tts_mutex = crate::GLOBAL_TTS.get();
802    if tts_mutex.is_none() {
803        return;
804    } else {
805        println!("Waiting for TTS to finish speaking...");
806    }
807    let start = std::time::Instant::now();
808    let mut tts_guard = None;
809    for _ in 0..3 {
810        if let Ok(guard) = tts_mutex.unwrap().lock() {
811            tts_guard = Some(guard);
812            break;
813        } else {
814            std::thread::sleep(std::time::Duration::from_millis(100));
815        }
816        if start.elapsed().as_millis() as u64 >= max_wait_ms {
817            eprintln!("Timeout while trying to lock TTS mutex.");
818            return;
819        }
820    }
821    if let Some(tts) = tts_guard {
822        while tts.is_speaking().unwrap_or(false) {
823            if start.elapsed().as_millis() as u64 >= max_wait_ms {
824                eprintln!("Timeout while waiting for TTS to finish speaking.");
825                break;
826            }
827            std::thread::sleep(std::time::Duration::from_millis(100));
828        }
829    } else {
830        eprintln!("Failed to lock TTS mutex after 3 attempts, skipping wait.");
831    }
832}
833
834// /// Runs an example or binary target, applying a temporary manifest patch if a workspace error is detected.
835// /// This function uses the same idea as in the collection helpers: if the workspace error is found,
836// /// we patch the manifest, run the command, and then restore the manifest.
837// pub fn run_example(
838//     target: &crate::e_target::CargoTarget,
839//     extra_args: &[String],
840// ) -> Result<std::process::ExitStatus, Box<dyn Error>> {
841//     // Retrieve the current package name (or binary name) at compile time.
842
843//     use crate::e_target::TargetKind;
844
845//     let current_bin = env!("CARGO_PKG_NAME");
846
847//     // Avoid running our own binary if the target's name is the same.
848//     if target.kind == TargetKind::Binary && target.name == current_bin {
849//         return Err(format!(
850//             "Skipping automatic run: {} is the same as the running binary",
851//             target.name
852//         )
853//         .into());
854//     }
855
856//     let mut cmd = Command::new("cargo");
857//     // Determine which manifest file is used.
858//     let manifest_path: PathBuf;
859
860//     match target.kind {
861//         TargetKind::Bench => {
862//             manifest_path = PathBuf::from(target.manifest_path.clone());
863//             cmd.args([
864//                 "bench",
865//                 "--bench",
866//                 &target.name,
867//                 "--manifest-path",
868//                 &target.manifest_path.to_str().unwrap_or_default().to_owned(),
869//             ]);
870//         }
871//         TargetKind::Test => {
872//             manifest_path = PathBuf::from(target.manifest_path.clone());
873//             cmd.args([
874//                 "test",
875//                 "--test",
876//                 &target.name,
877//                 "--manifest-path",
878//                 &target.manifest_path.to_str().unwrap_or_default().to_owned(),
879//             ]);
880//         }
881//         TargetKind::Manifest => {
882//             manifest_path = PathBuf::from(target.manifest_path.clone());
883//             cmd.args([
884//                 "run",
885//                 "--release",
886//                 "--manifest-path",
887//                 &target.manifest_path.to_str().unwrap_or_default().to_owned(),
888//                 "-p",
889//                 &target.name,
890//             ]);
891//         }
892//         TargetKind::Example => {
893//             if target.extended {
894//                 println!(
895//                     "Running extended example in folder: examples/{}",
896//                     target.name
897//                 );
898//                 // For extended examples, assume the manifest is inside the example folder.
899//                 manifest_path = PathBuf::from(format!("examples/{}/Cargo.toml", target.name));
900//                 cmd.arg("run")
901//                     .current_dir(format!("examples/{}", target.name));
902//             } else {
903//                 manifest_path = PathBuf::from(crate::locate_manifest(false)?);
904//                 cmd.args([
905//                     "run",
906//                     "--release",
907//                     "--example",
908//                     &target.name,
909//                     "--manifest-path",
910//                     &target.manifest_path.to_str().unwrap_or_default().to_owned(),
911//                 ]);
912//             }
913//         }
914//         TargetKind::Binary => {
915//             println!("Running binary: {}", target.name);
916//             manifest_path = PathBuf::from(crate::locate_manifest(false)?);
917//             cmd.args([
918//                 "run",
919//                 "--release",
920//                 "--bin",
921//                 &target.name,
922//                 "--manifest-path",
923//                 &target.manifest_path.to_str().unwrap_or_default().to_owned(),
924//             ]);
925//         }
926//         TargetKind::ExtendedBinary => {
927//             println!("Running extended binary: {}", target.name);
928//             manifest_path = PathBuf::from(crate::locate_manifest(false)?);
929//             cmd.args([
930//                 "run",
931//                 "--release",
932//                 "--manifest-path",
933//                 &target.manifest_path.to_str().unwrap_or_default().to_owned(),
934//                 "--bin",
935//                 &target.name,
936//             ]);
937//         }
938//         TargetKind::ExtendedExample => {
939//             println!("Running extended example: {}", target.name);
940//             manifest_path = PathBuf::from(crate::locate_manifest(false)?);
941//             cmd.args([
942//                 "run",
943//                 "--release",
944//                 "--manifest-path",
945//                 &target.manifest_path.to_str().unwrap_or_default().to_owned(),
946//                 "--example",
947//                 &target.name,
948//             ]);
949//         }
950//         TargetKind::ManifestTauri => {
951//             println!("Running tauri: {}", target.name);
952//             // For a Tauri example, run `cargo tauri dev`
953//             manifest_path = PathBuf::from(target.manifest_path.clone());
954//             let manifest_dir = PathBuf::from(manifest_path.parent().expect("expected a parent"));
955//             // Start a new command for tauri dev
956//             cmd.arg("tauri").arg("dev").current_dir(manifest_dir); // run from the folder where Cargo.toml is located
957//         }
958//         TargetKind::ManifestDioxus => {
959//             println!("Running dioxus: {}", target.name);
960//             cmd = Command::new("dx");
961//             // For a Tauri example, run `cargo tauri dev`
962//             manifest_path = PathBuf::from(target.manifest_path.clone());
963//             let manifest_dir = PathBuf::from(manifest_path.parent().expect("expected a parent"));
964//             // Start a new command for tauri dev
965//             cmd.arg("serve").current_dir(manifest_dir); // run from the folder where Cargo.toml is located
966//         }
967//         TargetKind::ManifestDioxusExample => {
968//             println!("Running dioxus: {}", target.name);
969//             cmd = Command::new("dx");
970//             // For a Tauri example, run `cargo tauri dev`
971//             manifest_path = PathBuf::from(target.manifest_path.clone());
972//             let manifest_dir = PathBuf::from(manifest_path.parent().expect("expected a parent"));
973//             // Start a new command for tauri dev
974//             cmd.arg("serve")
975//                 .arg("--example")
976//                 .arg(&target.name)
977//                 .current_dir(manifest_dir); // run from the folder where Cargo.toml is located
978//         }
979//     }
980
981//     // --- Add required-features support ---
982//     // This call will search the provided manifest, and if it's a workspace,
983//     // it will search workspace members for the target.
984//     if let Some(features) = crate::e_manifest::get_required_features_from_manifest(
985//         manifest_path.as_path(),
986//         &target.kind,
987//         &target.name,
988//     ) {
989//         cmd.args(&["--features", &features]);
990//     }
991//     // --- End required-features support ---
992
993//     if !extra_args.is_empty() {
994//         cmd.arg("--").args(extra_args);
995//     }
996
997//     let full_command = format!(
998//         "{} {}",
999//         cmd.get_program().to_string_lossy(),
1000//         cmd.get_args()
1001//             .map(|arg| arg.to_string_lossy())
1002//             .collect::<Vec<_>>()
1003//             .join(" ")
1004//     );
1005//     println!("Running: {}", full_command);
1006
1007//     // Before spawning, check if the manifest triggers the workspace error.
1008//     // If so, patch it temporarily.
1009//     let maybe_backup = crate::e_manifest::maybe_patch_manifest_for_run(&manifest_path)?;
1010
1011//     // Spawn the process.
1012//     let child = cmd.spawn()?;
1013//     {
1014//         let mut global = GLOBAL_CHILD.lock().unwrap();
1015//         *global = Some(child);
1016//     }
1017//     let status = {
1018//         let mut global = GLOBAL_CHILD.lock().unwrap();
1019//         if let Some(mut child) = global.take() {
1020//             child.wait()?
1021//         } else {
1022//             return Err("Child process missing".into());
1023//         }
1024//     };
1025
1026//     // Restore the manifest if we patched it.
1027//     if let Some(original) = maybe_backup {
1028//         fs::write(&manifest_path, original)?;
1029//     }
1030
1031//     //    println!("Process exited with status: {:?}", status.code());
1032//     Ok(status)
1033// }
1034/// Helper function to spawn a cargo process.
1035/// On Windows, this sets the CREATE_NEW_PROCESS_GROUP flag.
1036pub fn spawn_cargo_process(args: &[&str]) -> Result<Child, Box<dyn Error>> {
1037    // #[cfg(windows)]
1038    // {
1039    //     use std::os::windows::process::CommandExt;
1040    //     const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
1041    //     let child = Command::new("cargo")
1042    //         .args(args)
1043    //         .creation_flags(CREATE_NEW_PROCESS_GROUP)
1044    //         .spawn()?;
1045    //     Ok(child)
1046    // }
1047    // #[cfg(not(windows))]
1048    // {
1049    let child = Command::new("cargo").args(args).spawn()?;
1050    Ok(child)
1051    // }
1052}
1053
1054/// Returns true if the file's a "scriptisto"
1055pub fn is_active_scriptisto<P: AsRef<Path>>(path: P) -> io::Result<bool> {
1056    let file = File::open(path)?;
1057    let mut reader = std::io::BufReader::new(file);
1058    let mut first_line = String::new();
1059    reader.read_line(&mut first_line)?;
1060    if !first_line.contains("scriptisto") || !first_line.starts_with("#") {
1061        return Ok(false);
1062    }
1063    Ok(true)
1064}
1065
1066/// Returns true if the file's a "rust-script"
1067pub fn is_active_rust_script<P: AsRef<Path>>(path: P) -> io::Result<bool> {
1068    let file = File::open(path)?;
1069    let mut reader = std::io::BufReader::new(file);
1070    let mut first_line = String::new();
1071    reader.read_line(&mut first_line)?;
1072    if !first_line.contains("rust-script") || !first_line.starts_with("#") {
1073        return Ok(false);
1074    }
1075    Ok(true)
1076}
1077
1078/// Checks if `scriptisto` is installed and suggests installation if it's not.
1079pub fn check_scriptisto_installed() -> Result<std::path::PathBuf, Box<dyn Error>> {
1080    let r = which("scriptisto");
1081    match r {
1082        Ok(_) => {
1083            // installed
1084        }
1085        Err(e) => {
1086            // scriptisto is not found in the PATH
1087            eprintln!("scriptisto is not installed.");
1088            println!("Suggestion: To install scriptisto, run the following command:");
1089            println!("cargo install scriptisto");
1090            return Err(e.into());
1091        }
1092    }
1093    Ok(r?)
1094}
1095
1096pub fn run_scriptisto<P: AsRef<Path>>(script_path: P, args: &[&str]) -> Option<Child> {
1097    let scriptisto = check_scriptisto_installed().ok()?;
1098
1099    let script: &std::path::Path = script_path.as_ref();
1100    let child = Command::new(scriptisto)
1101        .arg(script)
1102        .args(args)
1103        .spawn()
1104        .ok()?;
1105    Some(child)
1106}
1107
1108/// Checks if `rust-script` is installed and suggests installation if it's not.
1109pub fn check_rust_script_installed() -> Result<std::path::PathBuf, Box<dyn Error>> {
1110    let r = which("rust-script");
1111    match r {
1112        Ok(_) => {
1113            // rust-script is installed
1114        }
1115        Err(e) => {
1116            // rust-script is not found in the PATH
1117            eprintln!("rust-script is not installed.");
1118            println!("Suggestion: To install rust-script, run the following command:");
1119            println!("cargo install rust-script");
1120            return Err(e.into());
1121        }
1122    }
1123    Ok(r?)
1124}
1125
1126pub fn run_rust_script<P: AsRef<Path>>(script_path: P, args: &[&str]) -> Option<Child> {
1127    let rust_script = check_rust_script_installed();
1128    if rust_script.is_err() {
1129        return None;
1130    }
1131    let rust_script = rust_script.unwrap();
1132    let script: &std::path::Path = script_path.as_ref();
1133    let child = Command::new(rust_script)
1134        .arg(script)
1135        .args(args)
1136        .spawn()
1137        .ok()?;
1138    Some(child)
1139}
1140
1141pub fn run_rust_script_with_ctrlc_handling(explicit: String, extra_args: Vec<String>) {
1142    let explicit_path = Path::new(&explicit); // Construct Path outside the lock
1143
1144    if explicit_path.exists() {
1145        let extra_str_slice: Vec<String> = extra_args.iter().cloned().collect();
1146        if let Ok(true) = is_active_rust_script(explicit_path) {
1147            // Run the child process in a separate thread to allow Ctrl+C handling
1148            let handle = thread::spawn(move || {
1149                let extra_str_slice_cloned = extra_str_slice.clone();
1150                let mut child = run_rust_script(
1151                    &explicit,
1152                    &extra_str_slice_cloned
1153                        .iter()
1154                        .map(String::as_str)
1155                        .collect::<Vec<_>>(),
1156                )
1157                .unwrap_or_else(|| {
1158                    eprintln!("Failed to run rust-script: {:?}", &explicit);
1159                    std::process::exit(1); // Exit with an error code
1160                });
1161
1162                child.wait()
1163            });
1164
1165            match handle.join() {
1166                Ok(_) => {
1167                    println!("Child process finished successfully.");
1168                }
1169                Err(_) => {
1170                    eprintln!("Child process took too long to finish. Exiting...");
1171                    std::process::exit(1); // Exit if the process takes too long
1172                }
1173            }
1174        }
1175    }
1176}
1177
1178pub fn run_scriptisto_with_ctrlc_handling(explicit: String, extra_args: Vec<String>) {
1179    let relative: String = make_relative(Path::new(&explicit)).unwrap_or_else(|e| {
1180        eprintln!("Error computing relative path: {}", e);
1181        std::process::exit(1);
1182    });
1183
1184    let explicit_path = Path::new(&relative);
1185    if explicit_path.exists() {
1186        // let extra_args = EXTRA_ARGS.lock().unwrap(); // Locking the Mutex to access the data
1187        let extra_str_slice: Vec<String> = extra_args.to_vec();
1188
1189        if let Ok(true) = is_active_scriptisto(explicit_path) {
1190            // Run the child process in a separate thread to allow Ctrl+C handling
1191            let handle = thread::spawn(move || {
1192                let extra_str_slice_cloned: Vec<String> = extra_str_slice.clone();
1193                let mut child = run_scriptisto(
1194                    &relative,
1195                    &extra_str_slice_cloned
1196                        .iter()
1197                        .map(String::as_str)
1198                        .collect::<Vec<_>>(),
1199                )
1200                .unwrap_or_else(|| {
1201                    eprintln!("Failed to run rust-script: {:?}", &explicit);
1202                    std::process::exit(1); // Exit with an error code
1203                });
1204                let _ = child.wait();
1205                // // Lock global to store the child process
1206                // {
1207                //     let mut global = GLOBAL_CHILD.lock().unwrap();
1208                //     *global = Some(child);
1209                // }
1210
1211                // // Wait for the child process to complete
1212                // let status = {
1213                //     let mut global = GLOBAL_CHILD.lock().unwrap();
1214                //     if let Some(mut child) = global.take() {
1215                //         child.wait()
1216                //     } else {
1217                //         // Handle missing child process
1218                //         eprintln!("Child process missing");
1219                //         std::process::exit(1); // Exit with an error code
1220                //     }
1221                // };
1222
1223                // // Handle the child process exit status
1224                // match status {
1225                //     Ok(status) => {
1226                //         eprintln!("Child process exited with status code: {:?}", status.code());
1227                //         std::process::exit(status.code().unwrap_or(1)); // Exit with the child's status code
1228                //     }
1229                //     Err(err) => {
1230                //         eprintln!("Error waiting for child process: {}", err);
1231                //         std::process::exit(1); // Exit with an error code
1232                //     }
1233                // }
1234            });
1235
1236            // Wait for the thread to complete, but with a timeout
1237            // let timeout = Duration::from_secs(10);
1238            match handle.join() {
1239                Ok(_) => {
1240                    println!("Child process finished successfully.");
1241                }
1242                Err(_) => {
1243                    eprintln!("Child process took too long to finish. Exiting...");
1244                    std::process::exit(1); // Exit if the process takes too long
1245                }
1246            }
1247        }
1248    }
1249}
1250/// Given any path, produce a relative path string starting with `./` (or `.\` on Windows).
1251fn make_relative(path: &Path) -> std::io::Result<String> {
1252    let cwd = env::current_dir()?;
1253    // Try to strip the cwd prefix; if it isn’t under cwd, just use the original path.
1254    let rel: PathBuf = match path.strip_prefix(&cwd) {
1255        Ok(stripped) => stripped.to_path_buf(),
1256        Err(_) => path.to_path_buf(),
1257    };
1258
1259    let mut rel = if rel.components().count() == 0 {
1260        // special case: the same directory
1261        PathBuf::from(".")
1262    } else {
1263        rel
1264    };
1265
1266    // Prepend "./" (or ".\") if it doesn’t already start with "." or ".."
1267    let first = rel.components().next().unwrap();
1268    match first {
1269        std::path::Component::CurDir | std::path::Component::ParentDir => {}
1270        _ => {
1271            rel = PathBuf::from(".").join(rel);
1272        }
1273    }
1274
1275    // Convert back to a string with the correct separator
1276    let s = rel
1277        .to_str()
1278        .expect("Relative path should be valid UTF-8")
1279        .to_string();
1280
1281    Ok(s)
1282}
1283
1284// trait JoinTimeout {
1285//     fn join_timeout(self, timeout: Duration) -> Result<(), ()>;
1286// }
1287
1288// impl<T> JoinTimeout for thread::JoinHandle<T> {
1289//     fn join_timeout(self, timeout: Duration) -> Result<(), ()> {
1290//         println!("Waiting for thread to finish...{}", timeout.as_secs());
1291//         let _ = thread::sleep(timeout);
1292//         match self.join() {
1293//             Ok(_) => Ok(()),
1294//             Err(_) => Err(()),
1295//         }
1296//     }
1297// }