use flag_rs::{CommandBuilder, CompletionResult, Flag};
fn main() {
let app = CommandBuilder::new("deploy")
.short("Deploy application to various environments")
.flag(
Flag::choice("environment", &["dev", "staging", "prod"])
.short('e')
.usage("Target environment")
.required()
.completion(|_ctx, prefix| {
let environments = vec![
("dev", "Development environment"),
("staging", "Staging environment (pre-production)"),
("prod", "Production environment"),
];
let mut result = CompletionResult::new();
for (env, desc) in environments {
if env.starts_with(prefix) {
result = result.add_with_description(env.to_string(), desc.to_string());
}
}
if prefix.is_empty() {
result = result.add_help_text("Available environments: dev, staging, prod");
}
Ok(result)
}),
)
.flag(
Flag::file("config")
.short('c')
.usage("Configuration file")
.default_str("config.yaml")
.completion(|_ctx, prefix| {
let configs = vec![
"config.yaml",
"config.dev.yaml",
"config.staging.yaml",
"config.prod.yaml",
"secrets.yaml",
];
Ok(CompletionResult::new().extend(
configs
.into_iter()
.filter(|c| c.starts_with(prefix))
.map(String::from),
))
}),
)
.flag(
Flag::directory("output")
.short('o')
.usage("Output directory for deployment artifacts")
.completion(|_ctx, prefix| {
let dirs = vec!["./build", "./dist", "./output", "/tmp/deploy"];
Ok(CompletionResult::new().extend(
dirs.into_iter()
.filter(|d| d.starts_with(prefix))
.map(String::from),
))
}),
)
.flag(
Flag::string_slice("service")
.short('s')
.usage("Services to deploy (can be specified multiple times)")
.completion(|ctx, prefix| {
let env = ctx.flag_str_or("environment", "dev");
let services = match env {
"dev" => vec!["api", "web", "worker", "scheduler", "debug-panel"],
"staging" => vec!["api", "web", "worker", "scheduler"],
"prod" => vec!["api", "web", "worker"],
_ => vec!["api", "web"],
};
let mut result = CompletionResult::new().extend(
services
.into_iter()
.filter(|s| s.starts_with(prefix))
.map(String::from),
);
if prefix.is_empty() {
result = result
.add_help_text(format!("Available services for {} environment", env));
}
Ok(result)
}),
)
.flag(
Flag::range("replicas", 1, 10)
.short('r')
.usage("Number of replicas to deploy")
.default_int(2)
.completion(|_ctx, _prefix| {
Ok(CompletionResult::new()
.add_with_description(
"1".to_string(),
"Single instance (dev/test)".to_string(),
)
.add_with_description("2".to_string(), "Basic redundancy".to_string())
.add_with_description("3".to_string(), "Standard production".to_string())
.add_with_description("5".to_string(), "High availability".to_string()))
}),
)
.run(|ctx| {
let env = ctx.flag_str_or("environment", "dev");
let config = ctx.flag_str_or("config", "config.yaml");
let replicas = ctx.flag_int_or("replicas", 2);
println!("Deploying to {} environment", env);
println!("Using configuration: {}", config);
println!("Replica count: {}", replicas);
if let Some(output) = ctx.flag("output") {
println!("Output directory: {}", output);
}
if let Some(services) = ctx.flag("service") {
println!("Deploying services: {}", services);
} else {
println!("Deploying all services");
}
Ok(())
})
.build();
let args: Vec<String> = std::env::args().skip(1).collect();
if let Err(e) = app.execute(args) {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}