broxus_util/
argh.rs

1use std::marker::PhantomData;
2
3#[macro_export]
4macro_rules! read_args_with_version {
5    ($ty:ty) => {{
6        struct VersionProvider;
7        impl $crate::AppVersionProvider for VersionProvider {
8            fn version() -> &'static str {
9                env!("CARGO_PKG_VERSION")
10            }
11        }
12
13        ::argh::from_env::<$crate::ArgsOrVersion<$ty, VersionProvider>>().app
14    }};
15}
16
17pub trait AppVersionProvider {
18    fn version() -> &'static str;
19}
20
21pub struct ArgsOrVersion<T: argh::FromArgs, V> {
22    pub app: T,
23    _version_marker: PhantomData<V>,
24}
25
26impl<T: argh::FromArgs, V: AppVersionProvider> argh::TopLevelCommand for ArgsOrVersion<T, V> {}
27
28impl<T: argh::FromArgs, V: AppVersionProvider> argh::FromArgs for ArgsOrVersion<T, V> {
29    fn from_args(command_name: &[&str], args: &[&str]) -> Result<Self, argh::EarlyExit> {
30        /// Also use argh for catching `--version`-only invocations
31        #[derive(argh::FromArgs)]
32        struct Version {
33            /// print version information and exit
34            #[argh(switch, short = 'v')]
35            pub version: bool,
36        }
37
38        match Version::from_args(command_name, args) {
39            Ok(v) if v.version => Err(argh::EarlyExit {
40                output: format!("{} {}", command_name.first().unwrap_or(&""), V::version()),
41                status: Ok(()),
42            }),
43            Err(exit) if exit.status.is_ok() => {
44                let help = match T::from_args(command_name, &["--help"]) {
45                    Ok(_) => unreachable!(),
46                    Err(exit) => exit.output,
47                };
48                Err(argh::EarlyExit {
49                    output: format!("{help}  -v, --version     print version information and exit"),
50                    status: Ok(()),
51                })
52            }
53            _ => T::from_args(command_name, args).map(|app| Self {
54                app,
55                _version_marker: PhantomData,
56            }),
57        }
58    }
59}