use forge::signal::compactor;
const MAX_PS_LINES: usize = 30;
const MAX_LSOF_LINES: usize = 40;
const MAX_NETSTAT_LINES: usize = 40;
pub fn compress_ps(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= MAX_PS_LINES + 1 {
return cleaned;
}
let header = lines.first().copied().unwrap_or("");
let body = &lines[1..MAX_PS_LINES + 1];
let omitted = lines.len() - 1 - MAX_PS_LINES;
format!(
"{}\n{}\n... [{} more processes] ...",
header,
body.join("\n"),
omitted
)
}
pub fn compress_df(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let kept: Vec<&str> = cleaned
.lines()
.filter(|l| {
let t = l.trim();
t.is_empty() ||
t.starts_with("Filesystem") || t.starts_with("udev") ||
(!t.contains("tmpfs") && !t.contains("devtmpfs")) ||
t.contains("9") && t.contains('%')
})
.collect();
if kept.is_empty() {
return cleaned;
}
kept.join("\n")
}
pub fn compress_du(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= 50 {
return cleaned;
}
let last = lines.last().copied().unwrap_or("");
let omitted = lines.len() - 50;
format!(
"{}\n... [{} more entries] ...\n{}",
lines[..50].join("\n"),
omitted,
last
)
}
pub fn compress_lsof(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= MAX_LSOF_LINES + 1 {
return cleaned;
}
let header = lines.first().copied().unwrap_or("");
let body = &lines[1..MAX_LSOF_LINES + 1];
let omitted = lines.len() - 1 - MAX_LSOF_LINES;
format!(
"{}\n{}\n... [{} more open files] ...",
header,
body.join("\n"),
omitted
)
}
pub fn compress_netstat(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= MAX_NETSTAT_LINES + 1 {
return cleaned;
}
let header = lines.first().copied().unwrap_or("");
let body = &lines[1..MAX_NETSTAT_LINES + 1];
let omitted = lines.len() - 1 - MAX_NETSTAT_LINES;
format!(
"{}\n{}\n... [{} more connections] ...",
header,
body.join("\n"),
omitted
)
}
pub fn compress_free(raw: &str) -> String {
compactor::normalise(raw)
}
pub fn compress_uname(raw: &str) -> String {
compactor::normalise(raw)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ps_truncates_many_processes() {
let header = "PID TTY TIME CMD\n";
let rows: String = (0..50)
.map(|i| format!("{i:5} pts/0 00:00:0{i} prog{i}\n"))
.collect();
let out = compress_ps(&format!("{header}{rows}"));
assert!(out.contains("more processes"), "{out}");
}
#[test]
fn du_truncates_large_output() {
let raw: String = (0..80).map(|i| format!("4.0K\t./dir_{i:02}\n")).collect();
let out = compress_du(&raw);
assert!(out.contains("more entries"), "{out}");
}
#[test]
fn lsof_truncates_many_files() {
let header = "COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME\n";
let rows: String = (0..60)
.map(|i| format!("cmd {i} user {i} REG 8,1 1024 {i} /path/file{i}\n"))
.collect();
let out = compress_lsof(&format!("{header}{rows}"));
assert!(out.contains("more open files"), "{out}");
}
}