From 7630e016c98ac329071d41ab42939c3ce22782f2 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Sun, 22 Jan 2023 00:26:26 -0500 Subject: [PATCH] Add `realpath` applet --- README.md | 1 + src/cmd/mod.rs | 5 +++- src/cmd/realpath/mod.rs | 66 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/cmd/realpath/mod.rs diff --git a/README.md b/README.md index 3006454..96f6e1e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ code between applets, making for an overall smaller binary. - nproc - printenv - pwd +- readlink - rev - rm - rmdir diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 640d893..454a0d8 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -35,6 +35,7 @@ mod nologin; mod nproc; mod printenv; mod pwd; +mod realpath; mod rev; mod rm; mod rmdir; @@ -92,6 +93,7 @@ pub fn get(name: &str) -> Option> { "nproc" => Some(Box::new(nproc::Nproc::default())), "printenv" => Some(Box::new(printenv::Printenv::default())), "pwd" => Some(Box::new(pwd::Pwd::default())), + "realpath" => Some(Box::new(realpath::Realpath::default())), "rev" => Some(Box::new(rev::Rev::default())), "rm" => Some(Box::new(rm::Rm::default())), "rmdir" => Some(Box::new(rmdir::Rmdir::default())), @@ -107,7 +109,7 @@ pub fn get(name: &str) -> Option> { } } -pub static COMMANDS: [&str; 38] = [ +pub static COMMANDS: [&str; 39] = [ "base32", "base64", "basename", @@ -135,6 +137,7 @@ pub static COMMANDS: [&str; 38] = [ "nproc", "printenv", "pwd", + "realpath", "rev", "rm", "rmdir", diff --git a/src/cmd/realpath/mod.rs b/src/cmd/realpath/mod.rs new file mode 100644 index 0000000..d66d24c --- /dev/null +++ b/src/cmd/realpath/mod.rs @@ -0,0 +1,66 @@ +use super::Cmd; +use clap::{Arg, ArgAction, Command, ValueHint}; +use std::{env, fs, io, process}; + +#[derive(Debug, Default)] +pub struct Realpath; + +impl Cmd for Realpath { + fn cli(&self) -> clap::Command { + Command::new("realpath") + .about("return resolved physical path") + .author("Nathan Fisher") + .version(env!("CARGO_PKG_VERSION")) + .args([ + Arg::new("quiet") + .short('q') + .long("quiet") + .help("ignore warnings") + .action(ArgAction::SetTrue), + Arg::new("path") + .value_hint(ValueHint::AnyPath) + .num_args(1..) + .required(false), + ]) + } + + fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box> { + let Some(matches) = matches else { + return Err(io::Error::new(io::ErrorKind::Other, "no input").into()); + }; + if let Some(files) = matches.get_many::("path") { + let mut erred = false; + for f in files { + match fs::canonicalize(f) { + Ok(p) => println!("{}", p.display()), + Err(e) => { + if !matches.get_flag("quiet") { + erred = true; + } else { + return Err(e.into()); + } + } + } + } + if erred { + process::exit(1); + } + } else { + match env::current_dir().and_then(|d| fs::canonicalize(d)) { + Ok(p) => println!("{}", p.display()), + Err(e) => { + if matches.get_flag("quiet") { + process::exit(1); + } else { + return Err(e.into()); + } + } + } + } + Ok(()) + } + + fn path(&self) -> Option { + Some(crate::Path::Bin) + } +}