#![allow(clippy::unnecessary_map_or)]
#![allow(clippy::collapsible_if)]
use anyhow::{Context, Result};
use clap::{Parser, Subcommand, ArgAction};
use clap_version_flag::colorful_version;
use std::path::PathBuf;
mod commands;
mod manifest;
mod utils;
use commands::*;
#[derive(Parser)]
#[command(
name = "cargoe",
// version,
about = "Advanced Cargo.toml management tool by Hadi Cahyadi <cumulus13@gmail.com>",
long_about = "A powerful CLI tool for managing Cargo.toml fields that cargo doesn't handle directly.\nSupports exclude/include patterns, keywords, categories, badges, and more.",
disable_version_flag = true
)]
struct Cli {
#[arg(short = 'V', long = "version", action = ArgAction::SetTrue)]
version: bool,
#[command(subcommand)]
command: Commands,
#[arg(short, long, global = true, default_value = "Cargo.toml")]
manifest_path: PathBuf,
#[arg(long, global = true)]
dry_run: bool,
#[arg(short, long, global = true)]
quiet: bool,
}
#[derive(Subcommand)]
enum Commands {
#[command(subcommand)]
Exclude(ExcludeCommands),
#[command(subcommand)]
Include(IncludeCommands),
#[command(subcommand)]
Keywords(KeywordsCommands),
#[command(subcommand)]
Categories(CategoriesCommands),
#[command(subcommand)]
Badges(BadgesCommands),
#[command(subcommand)]
Metadata(MetadataCommands),
Set {
field: String,
value: String,
},
Get {
field: String,
},
Validate {
#[arg(long)]
strict: bool,
},
Fmt {
#[arg(long)]
check: bool,
},
Info,
Init {
#[arg(short, long)]
yes: bool,
},
}
#[derive(Subcommand)]
enum ExcludeCommands {
Add { patterns: Vec<String> },
Remove { patterns: Vec<String> },
List,
Clear,
}
#[derive(Subcommand)]
enum IncludeCommands {
Add { patterns: Vec<String> },
Remove { patterns: Vec<String> },
List,
Clear,
}
#[derive(Subcommand)]
enum KeywordsCommands {
Add { keywords: Vec<String> },
Remove { keywords: Vec<String> },
List,
Clear,
}
#[derive(Subcommand)]
enum CategoriesCommands {
Add { categories: Vec<String> },
Remove { categories: Vec<String> },
List,
Clear,
Valid,
}
#[derive(Subcommand)]
enum BadgesCommands {
Add {
badge_type: String,
#[arg(value_parser = utils::parse_key_val)]
attributes: Vec<(String, String)>,
},
Remove {
badge_type: String,
},
List,
Clear,
}
#[derive(Subcommand)]
enum MetadataCommands {
Add {
key: String,
value: String,
#[arg(long)]
json: bool,
},
Remove {
key: String,
},
List,
Clear,
}
fn main() -> Result<()> {
let args: Vec<String> = std::env::args().collect();
if args.len() == 2 && (args[1] == "-V" || args[1] == "--version") {
let version = colorful_version!();
version.print_and_exit();
}
let cli = Cli::parse();
if !cli.manifest_path.exists() {
anyhow::bail!("Cargo.toml not found at: {}", cli.manifest_path.display());
}
let result = match cli.command {
Commands::Exclude(cmd) => exclude::handle(&cli.manifest_path, cmd, cli.dry_run, cli.quiet),
Commands::Include(cmd) => include::handle(&cli.manifest_path, cmd, cli.dry_run, cli.quiet),
Commands::Keywords(cmd) => {
keywords::handle(&cli.manifest_path, cmd, cli.dry_run, cli.quiet)
}
Commands::Categories(cmd) => {
categories::handle(&cli.manifest_path, cmd, cli.dry_run, cli.quiet)
}
Commands::Badges(cmd) => badges::handle(&cli.manifest_path, cmd, cli.dry_run, cli.quiet),
Commands::Metadata(cmd) => {
metadata::handle(&cli.manifest_path, cmd, cli.dry_run, cli.quiet)
}
Commands::Set { field, value } => {
set::handle(&cli.manifest_path, &field, &value, cli.dry_run, cli.quiet)
}
Commands::Get { field } => get::handle(&cli.manifest_path, &field),
Commands::Validate { strict } => validate::handle(&cli.manifest_path, strict),
Commands::Fmt { check } => fmt::handle(&cli.manifest_path, check, cli.dry_run),
Commands::Info => info::handle(&cli.manifest_path),
Commands::Init { yes } => init::handle(&cli.manifest_path, yes, cli.dry_run),
};
result.context("❌ Failed to execute command")
}