Skip to main content

lean_ctx/core/patterns/
bazel.rs

1pub 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}