args.rs (2816B)
1 use core::{ 2 error::Error, 3 fmt::{self, Display, Formatter}, 4 }; 5 use std::{ 6 env::{self, Args}, 7 path::{Path, PathBuf}, 8 }; 9 /// Wrapper around an absolute [`PathBuf`] to a directory. 10 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 11 pub(crate) struct AbsDirPath { 12 /// The directory. 13 path: PathBuf, 14 } 15 impl AbsDirPath { 16 /// Returns an `AbsDirPath` iff `PathBuf::from(val).is_absolute()`. 17 /// 18 /// If `PathBuf::from(val).as_bytes().last().unwrap() != b'/'`, `val` 19 /// will have `/` appended to it. 20 #[expect(clippy::option_if_let_else, reason = "can't without moving val")] 21 pub(crate) fn from_string(val: String) -> Option<Self> { 22 match val.as_bytes().last() { 23 Some(byt) => { 24 let last = *byt; 25 let mut path = PathBuf::from(val); 26 path.is_absolute().then(|| { 27 if last != b'/' { 28 path.as_mut_os_string().push("/"); 29 } 30 Self { path } 31 }) 32 } 33 None => None, 34 } 35 } 36 } 37 impl AsRef<Path> for AbsDirPath { 38 fn as_ref(&self) -> &Path { 39 self.path.as_path() 40 } 41 } 42 /// Error returned when parsing arguments passed to the application. 43 #[derive(Debug)] 44 pub(crate) enum ArgsErr { 45 /// Error when no arguments were passed to the application. 46 NoArgs, 47 /// Error when an option was passed that was not an absolute file path to a directory. 48 InvalidDir, 49 /// Error when more than one option is passed. 50 MoreThanOneOption, 51 } 52 impl Display for ArgsErr { 53 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 54 match *self { 55 Self::NoArgs => f.write_str("no arguments were passed, but the absolute path to the directory of git repos must be passed"), 56 Self::InvalidDir => f.write_str("an absolute path to the directory of git repos was not passed"), 57 Self::MoreThanOneOption => f.write_str("more than one argument was passed, but only the absolute path to the directory of git repos must be passed"), 58 } 59 } 60 } 61 impl Error for ArgsErr {} 62 /// Returns `AbsDirPath` based on arguments passed to the application. 63 pub(crate) fn from_env_args() -> Result<AbsDirPath, ArgsErr> { 64 /// Attempts to parse the next `Arg` into an absolute path to a directory. 65 fn get_path(args: &mut Args) -> Result<AbsDirPath, ArgsErr> { 66 args.next() 67 .ok_or(ArgsErr::NoArgs) 68 .and_then(|path| AbsDirPath::from_string(path).ok_or(ArgsErr::InvalidDir)) 69 } 70 let mut args = env::args(); 71 let Some(_) = args.next() else { 72 return Err(ArgsErr::NoArgs); 73 }; 74 get_path(&mut args).and_then(|path| { 75 args.next() 76 .map_or(Ok(path), |_| Err(ArgsErr::MoreThanOneOption)) 77 }) 78 }