// use std::path::PathBuf; use clap::Parser; use color_eyre::eyre::eyre; use config::AppConfig; use kxio::{fs::FileSystem, net::Net, print::Printer}; mod api_result; mod check; mod config; mod execute; mod init; mod macros; mod nextcloud; mod template; mod trello; #[cfg(test)] mod tests; const NAME: &str = "trello-to-deck"; use crate::nextcloud::client::DeckClient; use crate::trello::client::TrelloClient; use execute::Execute; use kxio::kxeprintln as e; use kxio::kxprintln as p; #[derive(Parser, Debug)] #[clap(version = clap::crate_version!(), author = clap::crate_authors!(), about = clap::crate_description!())] pub struct Commands { #[clap(long, action = clap::ArgAction::SetTrue)] pub log: bool, #[clap(subcommand)] pub command: Command, } #[derive(Parser, Debug)] pub enum Command { /// Initialize the configuration #[command(about = "Initialize configuration")] Init, /// Check the configuration and connection #[command(about = "Check configuration and connection")] Check, /// Import boards from Trello to Nextcloud Deck #[command(about = "Import boards from Trello to Nextcloud Deck")] Import, /// Trello-specific commands #[command(about = "Trello-specific commands")] #[clap(subcommand)] Trello(trello::TrelloCommand), /// Nextcloud-specific commands #[command(about = "Nextcloud-specific commands")] #[clap(subcommand)] Nextcloud(nextcloud::NextcloudCommand), } #[derive(Clone)] pub struct Ctx { pub fs: FileSystem, pub net: Net, pub prt: Printer, } impl From for Ctx { fn from(base: PathBuf) -> Self { Self { fs: kxio::fs::new(base), net: kxio::net::new(), prt: kxio::print::standard(), } } } #[derive(Clone)] pub(crate) struct FullCtx { pub fs: FileSystem, pub net: Net, pub prt: Printer, pub cfg: AppConfig, } impl FullCtx { pub(crate) fn deck_client(&self) -> DeckClient { DeckClient::new(self) } pub(crate) fn trello_client(&self) -> TrelloClient { TrelloClient::new(self) } } #[cfg_attr(test, mutants::skip)] pub async fn run(ctx: &Ctx, commands: &Commands) -> color_eyre::Result<()> { if commands.log { tracing::subscriber::set_global_default( tracing_subscriber::FmtSubscriber::builder() .with_max_level(tracing::Level::TRACE) .finish(), )?; tracing::info!("ready"); } let cfg = AppConfig::load(ctx); match cfg { Err(err) => { if matches!(commands.command, Command::Init) { init::run(ctx) } else { Err(eyre!("Missing or invalid config: {err}")) } } Ok(cfg) => { commands .command .execute(&FullCtx { fs: ctx.fs.clone(), net: ctx.net.clone(), prt: ctx.prt.clone(), cfg, }) .await } } }