use xacli::derive::{App, Command};
use xacli::Context;
#[derive(App)]
#[app(
name = "myapp",
version = "1.0.0",
title = "My CLI Application",
description = "A demo CLI built with xacli-derive macros"
)]
struct MyApp {
#[command(subcommands)]
commands: AppCommands,
}
#[derive(Command)]
enum AppCommands {
Serve(ServeCmd),
Build(BuildCmd),
Db(DbCmd),
}
#[derive(Command)]
#[command(description = "Start the development server with hot reload")]
struct ServeCmd {
#[arg(short = 'p', long = "port", default = "8080")]
port: i64,
#[arg(short = 'H', long = "host", default = "127.0.0.1")]
host: String,
#[arg(short = 'v', long = "verbose")]
verbose: bool,
}
impl ServeCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli_core::Result<()> {
use std::io::Write;
let mut out = ctx.stdout();
writeln!(out, "Starting development server...")?;
writeln!(out, " Listening on http://{}:{}", self.host, self.port)?;
if self.verbose {
writeln!(out, " Verbose logging enabled")?;
}
writeln!(out, " Press Ctrl+C to stop")?;
Ok(())
}
}
#[derive(Command)]
#[command(description = "Build the project for production deployment")]
struct BuildCmd {
#[arg(long = "release")]
release: bool,
#[arg(short = 'o', long = "output", default = "./dist")]
output: String,
}
impl BuildCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli_core::Result<()> {
use std::io::Write;
let mut out = ctx.stdout();
let mode = if self.release {
"release"
} else {
"development"
};
writeln!(out, "Building project...")?;
writeln!(out, " Mode: {}", mode)?;
writeln!(out, " Output: {}", self.output)?;
writeln!(out, "Build complete!")?;
Ok(())
}
}
#[derive(Command)]
#[command(description = "Database management commands")]
struct DbCmd {
#[command(subcommands)]
action: DbActions,
}
#[derive(Command)]
enum DbActions {
Migrate(DbMigrateCmd),
Seed(DbSeedCmd),
Reset(DbResetCmd),
}
#[derive(Command)]
#[command(name = "migrate", description = "Run pending database migrations")]
struct DbMigrateCmd {
#[arg(long = "dry-run")]
dry_run: bool,
#[arg(long = "fresh")]
fresh: bool,
}
impl DbMigrateCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli_core::Result<()> {
use std::io::Write;
let mut out = ctx.stdout();
if self.dry_run {
writeln!(out, "Dry run - no changes will be applied")?;
}
if self.fresh {
writeln!(out, "Running fresh migration (up and down)...")?;
}
writeln!(out, "Running database migrations...")?;
writeln!(out, " Applied: 001_create_users")?;
writeln!(out, " Applied: 002_create_posts")?;
writeln!(out, "Migrations complete!")?;
Ok(())
}
}
#[derive(Command)]
#[command(name = "seed", description = "Populate database with sample data")]
struct DbSeedCmd {
#[arg(short = 'n', long = "count", default = "10")]
count: i64,
}
impl DbSeedCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli_core::Result<()> {
use std::io::Write;
let mut out = ctx.stdout();
writeln!(out, "Seeding database...")?;
writeln!(out, " Created {} users", self.count)?;
writeln!(out, " Created {} posts", self.count * 5)?;
writeln!(out, "Seeding complete!")?;
Ok(())
}
}
#[derive(Command)]
#[command(name = "reset", description = "Drop all tables and re-run migrations")]
struct DbResetCmd {
#[arg(short = 'f', long = "force")]
force: bool,
}
impl DbResetCmd {
fn run(&self, ctx: &mut dyn Context) -> xacli_core::Result<()> {
use std::io::Write;
let mut out = ctx.stdout();
if !self.force {
writeln!(
out,
"Warning: This will delete all data. Use --force to confirm."
)?;
return Ok(());
}
writeln!(out, "Resetting database...")?;
writeln!(out, " Dropped all tables")?;
writeln!(out, " Re-running migrations...")?;
writeln!(out, "Database reset complete!")?;
Ok(())
}
}
fn main() {
if let Err(e) = MyApp::execute() {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
#[cfg(test)]
mod tests {
use super::*;
use xacli::testing::{assert, TestCase, TestCaseStatus, TestingApp};
#[test]
fn test_with_testing_framework() {
let app = TestingApp::new(MyApp::build());
let test_case = TestCase::new("help output")
.args(vec!["--help".to_string()])
.assertions(vec![
assert::success(),
assert::stdout()
.contains("My CLI Application")
.contains("serve")
.contains("build")
.contains("db"),
]);
let result = app.execute(test_case);
assert!(
matches!(result.status, TestCaseStatus::Passed),
"Test failed: {:?}",
result.status
);
}
}