Building Your First CLI App
Complete tutorial for building a CLI application with XaCLI
⏱️ 10 minutes
Building Your First CLI App
Setup
cargo new mycli
cd mycli
# Cargo.toml
[dependencies]
xacli = { version = "0.1", features = ["derive"] }
Define CLI with Derive Macros
use xacli::derive::{App, Command};
use xacli::Context;
// Application definition
#[derive(App)]
#[app(
name = "mycli",
version = "1.0.0",
title = "My CLI",
description = "A sample CLI application"
)]
struct MyCli {
#[command(subcommands)]
commands: Commands,
}
// Top-level commands
#[derive(Command)]
enum Commands {
/// Greet someone
Greet(GreetCmd),
/// Database operations
Db(DbCmd),
}
// Leaf command with arguments
#[derive(Command)]
#[command(description = "Say hello")]
struct GreetCmd {
#[arg(short = 'n', long = "name")]
name: bool,
#[arg(short = 'c', long = "count")]
count: bool,
}
impl GreetCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli::Result<()> {
use std::io::Write;
writeln!(ctx.stdout(), "Hello!")?;
Ok(())
}
}
// Nested command group
#[derive(Command)]
#[command(description = "Database commands")]
struct DbCmd {
#[command(subcommands)]
action: DbActions,
}
#[derive(Command)]
enum DbActions {
/// Run migrations
Migrate(DbMigrateCmd),
/// Seed database
Seed(DbSeedCmd),
}
#[derive(Command)]
#[command(name = "migrate")]
struct DbMigrateCmd {
#[arg(long = "dry-run")]
dry_run: bool,
}
impl DbMigrateCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli::Result<()> {
use std::io::Write;
writeln!(ctx.stdout(), "Running migrations...")?;
Ok(())
}
}
#[derive(Command)]
#[command(name = "seed")]
struct DbSeedCmd {}
impl DbSeedCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli::Result<()> {
use std::io::Write;
writeln!(ctx.stdout(), "Seeding database...")?;
Ok(())
}
}
fn main() {
if let Err(e) = MyCli::execute() {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
Run
cargo run -- --help
cargo run -- greet --help
cargo run -- db migrate --dry-run
cargo run -- db seed
Key Patterns
| Pattern | Usage |
|---|---|
#[derive(App)] | Application entry point |
#[derive(Command)] | Commands and subcommands |
#[command(subcommands)] | Mark field as subcommand container |
#[arg(short, long)] | Define arguments |
impl XxxCmd { fn run() } | Command execution logic |
Next Steps
- Run full example:
cargo run -p xacli --example derive --features derive,testing - Add testing with
xacli::testing - Add interactive components with
features = ["components"]