use std::{fmt::Display, process::Command};
pub enum ShellCommand {
Find {
builder: FindCommand,
},
}
impl ShellCommand {
fn error_msg(&self) -> String {
match self {
ShellCommand::Find { builder: find } => {
format!("Find command failed on {}", &find.filename)
}
}
}
pub fn command(self) -> Command {
match self {
ShellCommand::Find { builder: find } => find.command,
}
}
pub fn run(self) -> String {
let error_msg = self.error_msg();
let output = self.command().output().expect(&error_msg);
String::from_utf8_lossy(&output.stdout).to_string()
}
}
pub enum FileType {
File,
Directory,
SymbolicLink,
}
impl Display for FileType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
FileType::File => "f",
FileType::Directory => "d",
FileType::SymbolicLink => "l",
}
)
}
}
pub struct FindCommand {
filename: String,
command: Command,
}
impl FindCommand {
pub fn new(filename: &str) -> Self {
let mut cmd = Command::new("find");
cmd.arg(filename);
FindCommand {
filename: filename.to_string(),
command: cmd,
}
}
pub fn file_extension(mut self, ext: &str) -> Self {
self.command.arg("-name");
self.command.arg(format!("*.{ext}"));
self
}
pub fn file_extensions<'a, I>(mut self, extensions: I) -> Self
where
I: IntoIterator<Item = &'a String>,
{
self.command.arg("(");
let mut joined_ext = extensions
.into_iter()
.flat_map(|ext| vec!["-name".to_string(), format!("*.{}", ext), "-o".to_string()])
.collect::<Vec<String>>();
joined_ext.pop();
self.command.args(joined_ext);
self.command.arg(")");
self
}
pub fn file_type(mut self, file_type: FileType) -> Self {
self.command.arg("-type");
self.command.arg(file_type.to_string());
self
}
pub fn empty(mut self) -> Self {
self.command.arg("-empty");
self
}
pub fn delete(mut self) -> Self {
self.command.arg("-delete");
self
}
pub fn not(mut self) -> Self {
self.command.arg("!");
self
}
}