1use regex::Regex;
2
3pub fn format_stderr(language: &str, stderr: &str, success: bool) -> String {
4 if stderr.trim().is_empty() {
5 return String::new();
6 }
7
8 let (scrubbed, _changed) = scrub_temp_paths(stderr);
9 if success {
10 return scrubbed;
11 }
12
13 format!("Error: {language} failed\n{scrubbed}")
14}
15
16fn scrub_temp_paths(stderr: &str) -> (String, bool) {
17 let mut changed = false;
18 let temp_dir = std::env::temp_dir();
19 let temp = temp_dir.to_string_lossy();
20
21 let mut output = stderr.to_string();
22 if output.contains(temp.as_ref()) {
23 output = output.replace(temp.as_ref(), "<temp>");
24 changed = true;
25 }
26
27 if temp.as_ref().starts_with("/var/") {
28 let private = format!("/private{temp}");
29 if output.contains(&private) {
30 output = output.replace(&private, "<temp>");
31 changed = true;
32 }
33 }
34
35 let re = Regex::new(r"<temp>/?(?:run-[^/]+|\.tmp[^/]+|run-[^/]+[^/]*)/").unwrap();
36 if re.is_match(&output) {
37 output = re.replace_all(&output, "<snippet>/").to_string();
38 changed = true;
39 }
40
41 let re_noslash = Regex::new(r"<temp>\.tmp[^/]+/").unwrap();
42 if re_noslash.is_match(&output) {
43 output = re_noslash.replace_all(&output, "<snippet>/").to_string();
44 changed = true;
45 }
46
47 (output, changed)
48}