lean_ctx/core/patterns/
bazel.rs1pub fn compress(cmd: &str, output: &str) -> Option<String> {
2 let trimmed = output.trim();
3 if trimmed.is_empty() {
4 return Some("ok".to_string());
5 }
6
7 if cmd.contains("test") {
8 return Some(compress_test(trimmed));
9 }
10 if cmd.contains("build") {
11 return Some(compress_build(trimmed));
12 }
13 if cmd.contains("query") {
14 return Some(compress_query(trimmed));
15 }
16
17 Some(compact_lines(trimmed, 15))
18}
19
20fn compress_test(output: &str) -> String {
21 let mut passed = 0u32;
22 let mut failed = 0u32;
23 let mut failures = Vec::new();
24
25 for line in output.lines() {
26 let trimmed = line.trim();
27 if trimmed.contains("PASSED") {
28 passed += 1;
29 }
30 if trimmed.contains("FAILED") {
31 failed += 1;
32 failures.push(trimmed.to_string());
33 }
34 }
35
36 let summary = output
37 .lines()
38 .find(|l| l.contains("executed") || l.contains("test(s)"));
39
40 if passed == 0 && failed == 0 {
41 if let Some(s) = summary {
42 return format!("bazel test: {}", s.trim());
43 }
44 return compact_lines(output, 10);
45 }
46
47 let mut result = format!("bazel test: {passed} passed");
48 if failed > 0 {
49 result.push_str(&format!(", {failed} failed"));
50 }
51 for f in failures.iter().take(5) {
52 result.push_str(&format!("\n {f}"));
53 }
54 result
55}
56
57fn compress_build(output: &str) -> String {
58 let mut targets = 0u32;
59 let mut errors = Vec::new();
60
61 for line in output.lines() {
62 let trimmed = line.trim();
63 if trimmed.contains("up-to-date") || trimmed.contains("Build completed") {
64 if let Some(n) = trimmed
65 .split_whitespace()
66 .find_map(|w| w.parse::<u32>().ok())
67 {
68 targets = n;
69 }
70 }
71 if trimmed.starts_with("ERROR:") || trimmed.starts_with("error:") {
72 errors.push(trimmed.to_string());
73 }
74 }
75
76 if !errors.is_empty() {
77 let mut result = format!("{} errors:", errors.len());
78 for e in errors.iter().take(10) {
79 result.push_str(&format!("\n {e}"));
80 }
81 return result;
82 }
83
84 let info_line = output
85 .lines()
86 .rev()
87 .find(|l| l.contains("INFO: Build completed") || l.contains("up-to-date"));
88 if let Some(info) = info_line {
89 return info.trim().to_string();
90 }
91
92 format!("ok ({targets} targets)")
93}
94
95fn compress_query(output: &str) -> String {
96 let targets: Vec<&str> = output.lines().filter(|l| !l.trim().is_empty()).collect();
97 if targets.len() <= 20 {
98 return targets.join("\n");
99 }
100 format!(
101 "{} targets:\n{}\n... ({} more)",
102 targets.len(),
103 targets[..15].join("\n"),
104 targets.len() - 15
105 )
106}
107
108fn compact_lines(text: &str, max: usize) -> String {
109 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
110 if lines.len() <= max {
111 return lines.join("\n");
112 }
113 format!(
114 "{}\n... ({} more lines)",
115 lines[..max].join("\n"),
116 lines.len() - max
117 )
118}