Skip to main content

luaur_reduce_cli/methods/
reducer_run_reduce.rs

1use crate::enums::test_result::TestResult;
2use crate::methods::reducer_escape::reducer_escape;
3use crate::records::reducer::Reducer;
4use std::io::{BufRead, BufReader};
5use std::process::{Command, Stdio};
6
7impl Reducer {
8    pub fn run(&mut self) -> TestResult {
9        self.write_temp_script(false);
10
11        let escaped_script_name = reducer_escape(self, &self.script_name);
12        let mut cmd = self.command.clone();
13        while let Some(pos) = cmd.find("{}") {
14            cmd.replace_range(pos..pos + 2, &escaped_script_name);
15        }
16
17        let mut result = TestResult::NoBug;
18
19        self.step += 1;
20        println!("Step {:4}...", self.step);
21
22        // Run the user command through the platform shell, mirroring C++
23        // `popen`, which delegates to `cmd.exe /C` on Windows and `/bin/sh -c`
24        // elsewhere. The previous port hardcoded `sh`, which does not exist on a
25        // stock Windows install and made the reducer abort there.
26        let mut command = {
27            #[cfg(windows)]
28            {
29                use std::os::windows::process::CommandExt;
30                // cmd.exe does not understand the MSVC `\"`-escaping that Rust's
31                // normal argument quoting applies; pass the (already shell-quoted)
32                // command line verbatim with `raw_arg` so cmd parses it itself.
33                let mut c = Command::new("cmd");
34                c.arg("/C");
35                c.raw_arg(&cmd);
36                c
37            }
38            #[cfg(not(windows))]
39            {
40                let mut c = Command::new("sh");
41                c.arg("-c").arg(&cmd);
42                c
43            }
44        };
45        let mut child = command
46            .stdout(Stdio::piped())
47            .spawn()
48            .expect("failed to run reducer command");
49
50        if let Some(stdout) = child.stdout.take() {
51            let mut reader = BufReader::new(stdout);
52            let mut line = String::new();
53
54            loop {
55                line.clear();
56                let bytes_read = reader.read_line(&mut line).unwrap_or(0);
57                if bytes_read == 0 {
58                    break;
59                }
60
61                if line.contains(self.search_text.as_str()) {
62                    result = TestResult::BugFound;
63                    break;
64                }
65            }
66        }
67
68        let _ = child.wait();
69
70        result
71    }
72}