mod commands;
mod ecosystem_dispatch;
mod output;
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(
name = "socket-patch",
about = "CLI tool for applying security patches to dependencies",
version,
propagate_version = true
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Apply(commands::apply::ApplyArgs),
Rollback(commands::rollback::RollbackArgs),
#[command(visible_alias = "download")]
Get(commands::get::GetArgs),
Scan(commands::scan::ScanArgs),
List(commands::list::ListArgs),
Remove(commands::remove::RemoveArgs),
Setup(commands::setup::SetupArgs),
#[command(visible_alias = "gc")]
Repair(commands::repair::RepairArgs),
}
fn looks_like_uuid(s: &str) -> bool {
let parts: Vec<&str> = s.split('-').collect();
if parts.len() != 5 {
return false;
}
let expected = [8, 4, 4, 4, 12];
parts
.iter()
.zip(expected.iter())
.all(|(p, &len)| p.len() == len && p.chars().all(|c| c.is_ascii_hexdigit()))
}
#[tokio::main]
async fn main() {
let cli = match Cli::try_parse() {
Ok(cli) => cli,
Err(err) => {
let args: Vec<String> = std::env::args().collect();
if args.len() >= 2 && looks_like_uuid(&args[1]) {
let mut new_args = vec![args[0].clone(), "get".into()];
new_args.extend_from_slice(&args[1..]);
match Cli::try_parse_from(&new_args) {
Ok(cli) => cli,
Err(_) => err.exit(),
}
} else {
err.exit()
}
}
};
let exit_code = match cli.command {
Commands::Apply(args) => commands::apply::run(args).await,
Commands::Rollback(args) => commands::rollback::run(args).await,
Commands::Get(args) => commands::get::run(args).await,
Commands::Scan(args) => commands::scan::run(args).await,
Commands::List(args) => commands::list::run(args).await,
Commands::Remove(args) => commands::remove::run(args).await,
Commands::Setup(args) => commands::setup::run(args).await,
Commands::Repair(args) => commands::repair::run(args).await,
};
std::process::exit(exit_code);
}