use forge::signal::compactor;
use once_cell::sync::Lazy;
use regex::Regex;
static GEM_FETCH_RE: Lazy<Regex> = Lazy::new(||
Regex::new(r"(?m)^Fetching[:\s][^\n]+\n?").unwrap());
static GEM_DL_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^Downloading gem [^\n]+\n?").unwrap());
static GEM_INSTALLING_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^Installing [^\n]+\n?").unwrap());
static BUNDLE_USING_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^Using [^\n]+\n?").unwrap());
static BUNDLE_FETCH_RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"(?m)^(Fetching|Fetching gem metadata|Resolving dependencies)\S*[^\n]*\n?").unwrap()
});
pub fn compress_gem_install(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = GEM_FETCH_RE.replace_all(&cleaned, "");
let s = GEM_DL_RE.replace_all(&s, "");
let s = GEM_INSTALLING_RE.replace_all(&s, "");
let out = compactor::collapse_blanks(&s);
if out.trim().is_empty() {
cleaned
.lines()
.filter(|l| l.starts_with("Successfully installed") || l.contains("gem installed"))
.collect::<Vec<_>>()
.join("\n")
} else {
out
}
}
pub fn compress_gem_update(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = GEM_FETCH_RE.replace_all(&cleaned, "");
let s = GEM_DL_RE.replace_all(&s, "");
let s = GEM_INSTALLING_RE.replace_all(&s, "");
let out = compactor::collapse_blanks(&s);
if out.trim().is_empty() {
return "gem update: nothing to update".to_string();
}
out
}
pub fn compress_gem_list(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= 40 {
return lines.join("\n");
}
format!(
"{}\n... [{} more gems]",
lines[..40].join("\n"),
lines.len() - 40
)
}
pub fn compress_bundle_install(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = BUNDLE_FETCH_RE.replace_all(&cleaned, "");
let s = BUNDLE_USING_RE.replace_all(&s, "");
let s = GEM_INSTALLING_RE.replace_all(&s, "");
let out = compactor::collapse_blanks(&s);
if out.trim().is_empty() {
let summary: Vec<&str> = cleaned
.lines()
.filter(|l| l.starts_with("Bundle complete") || l.starts_with("Bundled gems"))
.collect();
if !summary.is_empty() {
return summary.join("\n");
}
}
out
}
pub fn compress_bundle_update(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = BUNDLE_FETCH_RE.replace_all(&cleaned, "");
let s = BUNDLE_USING_RE.replace_all(&s, "");
compactor::collapse_blanks(&s)
}
pub fn compress_gem(subcmd: &str, raw: &str) -> String {
match subcmd.trim() {
"install" | "i" => compress_gem_install(raw),
"update" => compress_gem_update(raw),
"list" => compress_gem_list(raw),
_ => compactor::normalise(raw),
}
}
pub fn compress_bundle(subcmd: &str, raw: &str) -> String {
match subcmd.trim() {
"install" | "i" => compress_bundle_install(raw),
"update" => compress_bundle_update(raw),
"exec" => compactor::normalise(raw),
_ => compress_bundle_install(raw),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gem_install_strips_fetch_installing() {
let raw = "Fetching: foo-1.0.0.gem\nInstalling foo (1.0.0)\nInstalling bar (2.0.0)\nSuccessfully installed foo-1.0.0\n1 gem installed\n";
let out = compress_gem_install(raw);
assert!(!out.contains("Fetching"), "{out}");
assert!(!out.contains("Installing foo"), "{out}");
assert!(
out.contains("Successfully installed") || out.contains("gem installed"),
"{out}"
);
}
#[test]
fn gem_list_truncates_large_output() {
let raw = (0..60)
.map(|i| format!("gem{i} (1.{i}.0)"))
.collect::<Vec<_>>()
.join("\n");
let out = compress_gem_list(&raw);
assert!(out.contains("more gems"), "{out}");
}
#[test]
fn bundle_install_strips_using_and_fetch() {
let raw = "Fetching gem metadata from https://rubygems.org/\nUsing rake 13.0.6\nUsing bundler 2.3.0\nInstalling activesupport 7.0.0\nBundle complete! 5 Gemfile dependencies, 42 gems now installed.\n";
let out = compress_bundle_install(raw);
assert!(!out.contains("Using rake"), "{out}");
assert!(!out.contains("Fetching gem metadata"), "{out}");
assert!(out.contains("Bundle complete"), "{out}");
}
#[test]
fn bundle_update_keeps_updating_lines() {
let raw = "Fetching gem metadata\nUsing foo 1.0.0\nUpdating foo (1.0.0 => 1.1.0)\nBundle updated!\n";
let out = compress_bundle_update(raw);
assert!(!out.contains("Using foo"), "{out}");
assert!(
out.contains("Updating foo") || out.contains("Bundle updated"),
"{out}"
);
}
}