use clap::{ErrorKind, IntoApp, Parser}; #[derive(Parser)] #[clap(author, version, about)] struct Cli { /// set version manually #[clap(long, value_name = "VER")] set_ver: Option, /// auto inc major #[clap(long)] major: bool, /// auto inc minor #[clap(long)] minor: bool, /// auto inc patch #[clap(long)] patch: bool, /// some regular input input_file: Option, /// some special input argument #[clap(long)] spec_in: Option, #[clap(short)] config: Option, } fn main() { let cli = Cli::parse(); // Let's assume the old version 1.2.3 let mut major = 1; let mut minor = 2; let mut patch = 3; // See if --set-ver was used to set the version manually let version = if let Some(ver) = cli.set_ver.as_deref() { if cli.major || cli.minor || cli.patch { let mut app = Cli::into_app(); app.error( ErrorKind::ArgumentConflict, "Can't do relative and absolute version change", ) .exit(); } ver.to_string() } else { // Increment the one requested (in a real program, we'd reset the lower numbers) let (maj, min, pat) = (cli.major, cli.minor, cli.patch); match (maj, min, pat) { (true, false, false) => major += 1, (false, true, false) => minor += 1, (false, false, true) => patch += 1, _ => { let mut app = Cli::into_app(); app.error( ErrorKind::ArgumentConflict, "Cam only modify one version field", ) .exit(); } }; format!("{}.{}.{}", major, minor, patch) }; println!("Version: {}", version); // Check for usage of -c if let Some(config) = cli.config.as_deref() { // todo: remove `#[allow(clippy::or_fun_call)]` lint when MSRV is bumped. #[allow(clippy::or_fun_call)] let input = cli .input_file .as_deref() // 'or' is preferred to 'or_else' here since `Option::as_deref` is 'const' .or(cli.spec_in.as_deref()) .unwrap_or_else(|| { let mut app = Cli::into_app(); app.error( ErrorKind::MissingRequiredArgument, "INPUT_FILE or --spec-in is required when using --config", ) .exit() }); println!("Doing work using input {} and config {}", input, config); } }