use clap::Parser;
use crate::{build_version, commands};
#[derive(Parser, Debug)]
#[command(bin_name = "cargo")]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Parser, Debug)]
pub enum Commands {
#[command(
about = "A cargo plugin for Buck2 integration",
long_about = "Seamlessly build Cargo projects with Buck2 — the simpler alternative to Reindeer"
)]
Buckal(BuckalArgs),
}
#[derive(Parser, Debug)]
#[command(arg_required_else_help = true)]
pub struct BuckalArgs {
#[command(subcommand)]
pub subcommands: Option<BuckalSubCommands>,
#[arg(long, short = 'V', help = "Print version")]
pub version: bool,
}
#[derive(Parser, Debug)]
pub enum BuckalSubCommands {
Add(crate::commands::add::AddArgs),
Autoremove(crate::commands::autoremove::AutoremoveArgs),
Build(crate::commands::build::BuildArgs),
Clean(crate::commands::clean::CleanArgs),
Init(crate::commands::init::InitArgs),
Login(crate::commands::login::LoginArgs),
Logout(crate::commands::logout::LogoutArgs),
Migrate(crate::commands::migrate::MigrateArgs),
New(crate::commands::new::NewArgs),
Push(crate::commands::push::PushArgs),
Remove(crate::commands::remove::RemoveArgs),
Test(Box<crate::commands::test::TestArgs>),
Update(crate::commands::update::UpdateArgs),
}
impl Cli {
pub fn run(&self) {
match &self.command {
Commands::Buckal(args) => {
if args.version {
println!("buckal {}", build_version());
return;
}
match &args.subcommands {
Some(subcommand) => match subcommand {
BuckalSubCommands::Add(args) => commands::add::execute(args),
BuckalSubCommands::Autoremove(args) => commands::autoremove::execute(args),
BuckalSubCommands::Build(args) => commands::build::execute(args),
BuckalSubCommands::Clean(args) => commands::clean::execute(args),
BuckalSubCommands::Init(args) => commands::init::execute(args),
BuckalSubCommands::Login(args) => commands::login::execute(args),
BuckalSubCommands::Logout(args) => commands::logout::execute(args),
BuckalSubCommands::Migrate(args) => commands::migrate::execute(args),
BuckalSubCommands::New(args) => commands::new::execute(args),
BuckalSubCommands::Push(args) => commands::push::execute(args),
BuckalSubCommands::Remove(args) => commands::remove::execute(args),
BuckalSubCommands::Test(args) => commands::test::execute(args),
BuckalSubCommands::Update(args) => commands::update::execute(args),
},
None => {
unreachable!("`arg_required_else_help` should prevent this branch")
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::validate_target_triple;
#[test]
fn test_cli_build_accepts_target() {
let cli = Cli::try_parse_from([
"cargo",
"buckal",
"build",
"--target",
"x86_64-unknown-linux-gnu",
])
.expect("failed to parse build args with --target");
match cli.command {
Commands::Buckal(args) => match args.subcommands {
Some(BuckalSubCommands::Build(build_args)) => {
assert_eq!(
build_args.target.as_deref(),
Some("x86_64-unknown-linux-gnu")
);
assert!(build_args.target_platforms.is_none());
}
other => panic!("expected build subcommand, got {other:?}"),
},
}
}
#[test]
fn test_cli_test_accepts_target() {
let cli = Cli::try_parse_from([
"cargo",
"buckal",
"test",
"--target",
"x86_64-unknown-linux-gnu",
])
.expect("failed to parse test args with --target");
match cli.command {
Commands::Buckal(args) => match args.subcommands {
Some(BuckalSubCommands::Test(test_args)) => {
assert_eq!(
test_args.target.as_deref(),
Some("x86_64-unknown-linux-gnu")
);
assert!(test_args.target_platforms.is_none());
}
other => panic!("expected test subcommand, got {other:?}"),
},
}
}
#[test]
fn test_cli_build_rejects_target_and_target_platforms() {
let result = Cli::try_parse_from([
"cargo",
"buckal",
"build",
"--target",
"x86_64-unknown-linux-gnu",
"--target-platforms",
"//platforms:x86_64-unknown-linux-gnu",
]);
assert!(result.is_err());
}
#[test]
fn test_cli_test_rejects_target_and_target_platforms() {
let result = Cli::try_parse_from([
"cargo",
"buckal",
"test",
"--target",
"x86_64-unknown-linux-gnu",
"--target-platforms",
"//platforms:x86_64-unknown-linux-gnu",
]);
assert!(result.is_err());
}
#[test]
fn test_cli_build_invalid_target_fails_validation() {
let cli =
Cli::try_parse_from(["cargo", "buckal", "build", "--target", "not-a-real-target"])
.expect("failed to parse build args with invalid --target");
match cli.command {
Commands::Buckal(args) => match args.subcommands {
Some(BuckalSubCommands::Build(build_args)) => {
let err = validate_target_triple(build_args.target.as_deref().unwrap())
.expect_err("expected invalid target triple to fail validation");
assert!(err.to_string().contains("not a valid rustc target"));
}
other => panic!("expected build subcommand, got {other:?}"),
},
}
}
#[test]
fn test_cli_test_invalid_target_fails_validation() {
let cli = Cli::try_parse_from(["cargo", "buckal", "test", "--target", "not-a-real-target"])
.expect("failed to parse test args with invalid --target");
match cli.command {
Commands::Buckal(args) => match args.subcommands {
Some(BuckalSubCommands::Test(test_args)) => {
let err = validate_target_triple(test_args.target.as_deref().unwrap())
.expect_err("expected invalid target triple to fail validation");
assert!(err.to_string().contains("not a valid rustc target"));
}
other => panic!("expected test subcommand, got {other:?}"),
},
}
}
}