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 (3569B)


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