use std::path::Path;
use serde::Serialize;
use crate::context::{open_repo, void_err_to_cli};
use crate::output::{run_command, CliError, CliOptions};
#[derive(Debug, Clone, Serialize)]
pub struct RmOutput {
pub removed: Vec<String>,
pub count: usize,
}
pub fn run(
cwd: &Path,
paths: Vec<String>,
cached_only: bool,
force: bool,
recursive: bool,
opts: &CliOptions,
) -> Result<(), CliError> {
let paths: Vec<String> = paths.into_iter().filter(|p| !p.trim().is_empty()).collect();
run_command("rm", opts, |ctx| {
if paths.is_empty() {
return Err(CliError::invalid_args(
"No paths specified. Provide files or directories to remove.",
));
}
let repo = open_repo(cwd)?;
ctx.progress("Removing files...");
let path_strs: Vec<&str> = paths.iter().map(|s| s.as_str()).collect();
let result = repo
.remove(&path_strs, cached_only, force, recursive)
.map_err(void_err_to_cli)?;
if !ctx.use_json() {
let total_removed = result.removed.len();
if total_removed == 0 {
ctx.info("Nothing to remove");
} else {
for path in &result.removed {
ctx.info(format!("rm '{}'", path));
}
}
}
let count = result.removed.len();
Ok(RmOutput {
removed: result.removed,
count,
})
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rm_output_serialization() {
let output = RmOutput {
removed: vec!["src/main.rs".to_string(), "src/lib.rs".to_string()],
count: 2,
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("\"removed\""));
assert!(json.contains("\"count\":2"));
assert!(json.contains("src/main.rs"));
assert!(json.contains("src/lib.rs"));
}
#[test]
fn test_rm_output_empty() {
let output = RmOutput {
removed: vec![],
count: 0,
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("\"removed\":[]"));
assert!(json.contains("\"count\":0"));
}
}