git_index

Generates arguments to pass to stagit-index in descending order by commit date.
git clone https://git.philomathiclife.com/repos/git_index
Log | Files | Refs | README

args.rs (2946B)


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