use std::process::ExitCode; mod cli; mod cmd; mod commands; mod ctx; mod fsops; mod output; mod project; use anyhow::Result; use clap::Parser; use crate::ctx::Ctx; use crate::output::note; // 0 ran with nothing to report, 1 could not finish, 2 bad arguments, 4 found something const FINDINGS: u8 = 4; fn main() -> ExitCode { let args = cli::Ahab::parse(); let ctx = Ctx { verbose: args.verbose, dry_run: args.dry_run, quiet: args.quiet, }; // said once here rather than by each command, so every line that follows // reads as the plan it is if ctx.dry_run { note!(ctx, "dry run, nothing will be changed"); } match run(&ctx, args.command) { Ok(code) => code, Err(e) => { eprintln!("Error: {e:#}"); ExitCode::FAILURE } } } fn run(ctx: &Ctx, command: cli::Commands) -> Result { let done = ExitCode::SUCCESS; match command { cli::Commands::Django { command } => { match command { cli::Django::Bash => commands::django::bash(ctx), cli::Django::Run { rest } => commands::django::run(ctx, &rest), cli::Django::MakeCommand { app, name } => { commands::django::make_command(ctx, &app, &name) } cli::Django::Makemigrations => commands::django::makemigrations(ctx), cli::Django::Manage { rest } => commands::django::manage(ctx, &rest), cli::Django::Migrate { rest } => commands::django::migrate(ctx, &rest), cli::Django::Shell => commands::django::shell(ctx), }?; Ok(done) } cli::Commands::Postgres { command } => { match command { cli::Postgres::Import { path } => commands::postgres::import(ctx, &path), cli::Postgres::Psql { rest } => commands::postgres::psql(ctx, &rest), cli::Postgres::Dump { path, format, gzip } => { commands::postgres::dump(ctx, &path, format, gzip) } }?; Ok(done) } cli::Commands::Link { command } => match command { cli::Link::Add { paths, force, store, } => commands::link::add(ctx, &paths, force, store.root.as_deref()).map(|()| done), cli::Link::List { store } => { commands::link::list(ctx, store.root.as_deref()).map(|()| done) } cli::Link::Restore { paths, all, store } => { commands::link::restore(ctx, &paths, all, store.root.as_deref()).map(|()| done) } // the one command with something to say through its exit code cli::Link::Check { paths, porcelain, null, exit_code, store, } => { let exposed = commands::link::check(ctx, &paths, porcelain, null, store.root.as_deref())?; match exit_code && exposed { true => Ok(ExitCode::from(FINDINGS)), false => Ok(done), } } }, cli::Commands::Status { store } => { commands::status::status(ctx, store.root.as_deref())?; Ok(done) } cli::Commands::Completions { shell } => { commands::completions::completions(shell)?; Ok(done) } } }