Skip to main content

#
04_04_custom_derive/
04_04_custom.rs

    1use clap::error::ErrorKind;
    2use clap::{CommandFactory, Parser};
    3
    4#[derive(Parser)]
    5#[command(version, about, long_about = None)]
    6struct Cli {
    7    /// set version manually
    8    #[arg(long, value_name = "VER")]
    9    set_ver: Option<String>,
    10
    11    /// auto inc major
    12    #[arg(long)]
    13    major: bool,
    14
    15    /// auto inc minor
    16    #[arg(long)]
    17    minor: bool,
    18
    19    /// auto inc patch
    20    #[arg(long)]
    21    patch: bool,
    22
    23    /// some regular input
    24    input_file: Option<String>,
    25
    26    /// some special input argument
    27    #[arg(long)]
    28    spec_in: Option<String>,
    29
    30    #[arg(short)]
    31    config: Option<String>,
    32}
    33
    34fn main() {
    35    let cli = Cli::parse();
    36
    37    // Let's assume the old version 1.2.3
    38    let mut major = 1;
    39    let mut minor = 2;
    40    let mut patch = 3;
    41
    42    // See if --set-ver was used to set the version manually
    43    let version = if let Some(ver) = cli.set_ver.as_deref() {
    44        if cli.major || cli.minor || cli.patch {
    45            let mut cmd = Cli::command();
    46            cmd.error(
    47                ErrorKind::ArgumentConflict,
    48                "Can't do relative and absolute version change",
    49            )
    50            .exit();
    51        }
    52        ver.to_owned()
    53    } else {
    54        // Increment the one requested (in a real program, we'd reset the lower numbers)
    55        let (maj, min, pat) = (cli.major, cli.minor, cli.patch);
    56        match (maj, min, pat) {
    57            (true, false, false) => major += 1,
    58            (false, true, false) => minor += 1,
    59            (false, false, true) => patch += 1,
    60            _ => {
    61                let mut cmd = Cli::command();
    62                cmd.error(
    63                    ErrorKind::ArgumentConflict,
    64                    "Can only modify one version field",
    65                )
    66                .exit();
    67            }
    68        };
    69        format!("{major}.{minor}.{patch}")
    70    };
    71
    72    println!("Version: {version}");
    73
    74    // Check for usage of -c
    75    if let Some(config) = cli.config.as_deref() {
    76        let input = cli
    77            .input_file
    78            .as_deref()
    79            // 'or' is preferred to 'or_else' here since `Option::as_deref` is 'const'
    80            .or(cli.spec_in.as_deref())
    81            .unwrap_or_else(|| {
    82                let mut cmd = Cli::command();
    83                cmd.error(
    84                    ErrorKind::MissingRequiredArgument,
    85                    "INPUT_FILE or --spec-in is required when using --config",
    86                )
    87                .exit()
    88            });
    89        println!("Doing work using input {input} and config {config}");
    90    }
    91}