argot-cmd 0.2.0

An agent-first command interface framework for Rust
Documentation
//! Derive macro example — define CLI commands as annotated structs.
//!
//! This example shows how to use `#[derive(ArgotCommand)]` to define commands
//! without manually using the builder API.
//!
//! # Running
//!
//! ```sh
//! cargo run --example derive_example --features derive -- deploy production
//! cargo run --example derive_example --features derive -- deploy production --dry-run
//! cargo run --example derive_example --features derive -- deploy production --strategy blue-green
//! cargo run --example derive_example --features derive -- status
//! cargo run --example derive_example --features derive -- --help
//! ```

#[cfg(feature = "derive")]
mod inner {
    #![allow(dead_code)] // derive structs are command descriptors, not data holders
    use std::sync::Arc;

    use argot_cmd::{ArgotCommand, Cli};

    #[derive(ArgotCommand)]
    #[argot(
        summary = "Deploy the application",
        alias = "d",
        best_practice = "always use --dry-run before deploying to production",
        anti_pattern = "skipping dry-run on production deployments"
    )]
    pub struct Deploy {
        #[argot(
            positional,
            required,
            description = "target environment (staging|production)"
        )]
        env: String,

        #[argot(
            flag,
            short = 'n',
            description = "simulate deployment without making changes"
        )]
        dry_run: bool,

        #[argot(
            flag,
            short = 's',
            takes_value,
            description = "deployment strategy",
            default = "rolling"
        )]
        strategy: String,
    }

    #[derive(ArgotCommand)]
    #[argot(summary = "Show deployment status")]
    pub struct Status {
        #[argot(
            flag,
            short = 'f',
            takes_value,
            description = "output format",
            default = "table"
        )]
        format: String,
    }

    pub fn run() {
        // Build the registry from derived commands, attaching handlers.
        // The `handler` field is public, so we can set it directly after derive.
        let mut deploy_cmd = Deploy::command();
        deploy_cmd.handler = Some(Arc::new(|parsed| {
            println!("Deploying to: {}", parsed.args["env"]);
            if parsed
                .flags
                .get("dry-run")
                .map(|v| v == "true")
                .unwrap_or(false)
            {
                println!("DRY RUN mode — no changes will be made");
            }
            println!(
                "Strategy: {}",
                parsed
                    .flags
                    .get("strategy")
                    .map(|s: &String| s.as_str())
                    .unwrap_or("rolling")
            );
            if parsed
                .flags
                .get("dry-run")
                .map(|v| v == "true")
                .unwrap_or(false)
            {
                println!("[DRY RUN] Deployment simulation complete.");
            } else {
                println!("  [1/3] Pulling artifact... done");
                println!("  [2/3] Running health checks... done");
                println!("  [3/3] Switching traffic... done");
                println!("Deploy complete.");
            }
            Ok(())
        }));

        let mut status_cmd = Status::command();
        status_cmd.handler = Some(Arc::new(|parsed| {
            let format = parsed
                .flags
                .get("format")
                .map(|s: &String| s.as_str())
                .unwrap_or("table");
            match format {
                "json" => {
                    println!(
                        r#"[
  {{"environment":"staging","version":"v1.5.0","status":"healthy"}},
  {{"environment":"production","version":"v1.4.2","status":"healthy"}}
]"#
                    );
                }
                _ => {
                    println!("{:<15} {:<10} STATUS", "ENVIRONMENT", "VERSION");
                    println!("{}", "-".repeat(40));
                    println!("{:<15} {:<10} healthy", "staging", "v1.5.0");
                    println!("{:<15} {:<10} healthy", "production", "v1.4.2");
                }
            }
            Ok(())
        }));

        Cli::new(vec![deploy_cmd, status_cmd])
            .app_name("derive-example")
            .version(env!("CARGO_PKG_VERSION"))
            .with_query_support()
            .run_env_args_and_exit();
    }
}

#[cfg(feature = "derive")]
fn main() {
    inner::run();
}

#[cfg(not(feature = "derive"))]
fn main() {
    eprintln!("This example requires the `derive` feature.");
    eprintln!("Run: cargo run --example derive_example --features derive");
    std::process::exit(1);
}