Add rmdir applet

This commit is contained in:
Nathan Fisher 2023-01-16 23:44:21 -05:00
parent 1ff61def39
commit f7b7fcca16
3 changed files with 76 additions and 3 deletions

View File

@ -36,6 +36,7 @@ code between applets, making for an overall smaller binary.
- nologin
- nproc
- rev
- rmdir
- sleep
- shitbox
- sync

View File

@ -46,8 +46,8 @@ pub use {
self::hostname::Hostname, self::shitbox::Shitbox, base32::Base32, base64::Base64,
basename::Basename, bootstrap::Bootstrap, clear::Clear, cut::Cut, dirname::Dirname, echo::Echo,
factor::Factor, fold::Fold, groups::Groups, head::Head, link::Link, mountpoint::Mountpoint,
nologin::Nologin, nproc::Nproc, r#false::False, r#true::True, rev::Rev, sleep::Sleep,
sync::Sync as SyncCmd, unlink::Unlink, which::Which, whoami::Whoami, yes::Yes,
nologin::Nologin, nproc::Nproc, r#false::False, r#true::True, rev::Rev, rmdir::Rmdir,
sleep::Sleep, sync::Sync as SyncCmd, unlink::Unlink, which::Which, whoami::Whoami, yes::Yes,
};
/// Defines a command or applet, it's cli interface, and it's installation directory
@ -87,6 +87,7 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
"nologin" => Some(Box::new(Nologin::default())),
"nproc" => Some(Box::new(Nproc::default())),
"rev" => Some(Box::new(Rev::default())),
"rmdir" => Some(Box::new(Rmdir::default())),
"shitbox" => Some(Box::new(Shitbox::default())),
"sleep" => Some(Box::new(Sleep::default())),
"sync" => Some(Box::new(SyncCmd::default())),
@ -99,7 +100,7 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
}
}
pub static COMMANDS: [&str; 27] = [
pub static COMMANDS: [&str; 28] = [
"base32",
"base64",
"basename",
@ -119,6 +120,7 @@ pub static COMMANDS: [&str; 27] = [
"nologin",
"nproc",
"rev",
"rmdir",
"sleep",
"shitbox",
"sync",

View File

@ -1 +1,71 @@
use std::{io, error::Error, fs, path::Path};
use super::Cmd;
use clap::{Arg, ArgAction, Command, ValueHint};
#[derive(Debug, Default)]
pub struct Rmdir;
impl Cmd for Rmdir {
fn cli(&self) -> clap::Command {
Command::new("rmdir")
.about("remove directories")
.author("Nathan Fisher")
.version(env!("CARGO_PKG_VERSION"))
.args([
Arg::new("parents")
.help("remove DIRECTORY and it's ancestors")
.short('p')
.long("parents")
.action(ArgAction::SetTrue),
Arg::new("dir")
.num_args(1..)
.value_name("DIRECTORY")
.value_hint(ValueHint::DirPath)
.required(true),
Arg::new("verbose")
.help("output a diagnostic for every directory processed")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue),
])
}
fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box<dyn std::error::Error>> {
let Some(matches) = matches else {
return Err(Box::new(io::Error::new(io::ErrorKind::Other, "no input")));
};
if let Some(directories) = matches.get_many::<String>("dir") {
for dir in directories {
if matches.get_flag("parents") {
let path = Path::new(dir);
rmdir_recursive(path, matches.get_flag("verbose"))?;
} else {
fs::remove_dir(dir)?;
if matches.get_flag("verbose") {
println!("rmdir: removing directory, '{dir}'");
}
}
}
}
Ok(())
}
fn path(&self) -> Option<crate::Path> {
Some(crate::Path::Bin)
}
}
fn rmdir_recursive(dir: &Path, verbose: bool) -> Result<(), Box<dyn Error>> {
fs::remove_dir(dir)?;
if verbose {
println!("rmdir: removing directory, '{}'", dir.display());
}
if let Some(parent) = dir.parent() {
if let Some(name) = parent.to_str() {
if !name.is_empty() {
rmdir_recursive(parent, verbose)?;
}
}
}
Ok(())
}