Skip to main content

lean_ctx_patterns/
helm.rs

1// SPDX-License-Identifier: Apache-2.0
2
3pub fn compress(cmd: &str, output: &str) -> Option<String> {
4    let trimmed = output.trim();
5    if trimmed.is_empty() {
6        return Some("ok".to_string());
7    }
8
9    if cmd.contains("list") || cmd.contains("ls") {
10        return Some(compress_list(trimmed));
11    }
12    if cmd.contains("install") || cmd.contains("upgrade") {
13        return Some(compress_install(trimmed));
14    }
15    if cmd.contains("status") {
16        return Some(compress_status(trimmed));
17    }
18    if cmd.contains("template") || cmd.contains("dry-run") {
19        return Some(compress_template(trimmed));
20    }
21    if cmd.contains("repo") {
22        return Some(compress_repo(trimmed));
23    }
24
25    Some(compact_lines(trimmed, 15))
26}
27
28fn compress_list(output: &str) -> String {
29    let lines: Vec<&str> = output.lines().collect();
30    if lines.len() <= 1 {
31        return "no releases".to_string();
32    }
33
34    let header = lines[0];
35    let releases: Vec<&str> = lines[1..]
36        .iter()
37        .copied()
38        .filter(|l| !l.trim().is_empty())
39        .collect();
40    if releases.len() <= 15 {
41        return output.to_string();
42    }
43    format!(
44        "{header}\n{}\n... ({} more)",
45        releases[..10].join("\n"),
46        releases.len() - 10
47    )
48}
49
50fn compress_install(output: &str) -> String {
51    let mut name = String::new();
52    let mut status = String::new();
53    let mut notes_start = false;
54    let mut notes = Vec::new();
55
56    for line in output.lines() {
57        let trimmed = line.trim();
58        if trimmed.starts_with("NAME:") {
59            name = trimmed
60                .strip_prefix("NAME:")
61                .unwrap_or("")
62                .trim()
63                .to_string();
64        } else if trimmed.starts_with("STATUS:") {
65            status = trimmed
66                .strip_prefix("STATUS:")
67                .unwrap_or("")
68                .trim()
69                .to_string();
70        } else if trimmed == "NOTES:" {
71            notes_start = true;
72        } else if notes_start && !trimmed.is_empty() && notes.len() < 5 {
73            notes.push(trimmed.to_string());
74        }
75    }
76
77    let mut result = format!("{name}: {status}");
78    if !notes.is_empty() {
79        result.push_str(&format!("\nnotes: {}", notes.join(" | ")));
80    }
81    result
82}
83
84fn compress_status(output: &str) -> String {
85    let mut parts = Vec::new();
86    for line in output.lines() {
87        let trimmed = line.trim();
88        if trimmed.starts_with("NAME:")
89            || trimmed.starts_with("STATUS:")
90            || trimmed.starts_with("NAMESPACE:")
91            || trimmed.starts_with("REVISION:")
92            || trimmed.starts_with("LAST DEPLOYED:")
93        {
94            parts.push(trimmed.to_string());
95        }
96    }
97    if parts.is_empty() {
98        return compact_lines(output, 10);
99    }
100    parts.join("\n")
101}
102
103fn compress_template(output: &str) -> String {
104    let lines: Vec<&str> = output.lines().collect();
105    let yaml_docs: Vec<usize> = lines
106        .iter()
107        .enumerate()
108        .filter(|(_, l)| l.trim() == "---")
109        .map(|(i, _)| i)
110        .collect();
111
112    let mut kinds = Vec::new();
113    for line in &lines {
114        let trimmed = line.trim();
115        if trimmed.starts_with("kind:") {
116            kinds.push(
117                trimmed
118                    .strip_prefix("kind:")
119                    .unwrap_or("")
120                    .trim()
121                    .to_string(),
122            );
123        }
124    }
125
126    if kinds.is_empty() {
127        return format!("{} lines of YAML", lines.len());
128    }
129
130    let mut counts: std::collections::HashMap<&str, u32> = std::collections::HashMap::new();
131    for k in &kinds {
132        *counts.entry(k.as_str()).or_insert(0) += 1;
133    }
134    let summary: Vec<String> = counts.iter().map(|(k, v)| format!("  {k}: {v}")).collect();
135    format!(
136        "{} YAML docs ({} resources):\n{}",
137        yaml_docs.len().max(1),
138        kinds.len(),
139        summary.join("\n")
140    )
141}
142
143fn compress_repo(output: &str) -> String {
144    compact_lines(output, 10)
145}
146
147fn compact_lines(text: &str, max: usize) -> String {
148    let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
149    if lines.len() <= max {
150        return lines.join("\n");
151    }
152    format!(
153        "{}\n{}",
154        lines[..max].join("\n"),
155        super::elision_marker(lines.len() - max)
156    )
157}