From 3beab7d82d2f0a573f10b85adb7ec55d8d453dfe Mon Sep 17 00:00:00 2001 From: Jeremiah Russell Date: Wed, 15 Oct 2025 10:55:32 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(cli):=20restructu?= =?UTF-8?q?re=20cli=20commands=20for=20better=20organization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rename `label_cli.rs` to `labels_cli.rs` - rename `message_cli.rs` to `messages_cli.rs` - move config related commands to `rules config` subcommand - introduce `rules run` subcommand --- src/cli/{label_cli.rs => labels_cli.rs} | 4 +- src/cli/main.rs | 36 ++++----- src/cli/{message_cli.rs => messages_cli.rs} | 4 +- src/cli/rules_cli.rs | 74 ++++++------------- src/cli/{ => rules_cli}/config_cli.rs | 0 .../{ => rules_cli}/config_cli/action_cli.rs | 0 .../{ => rules_cli}/config_cli/label_cli.rs | 0 .../config_cli/label_cli/add_cli.rs | 0 .../config_cli/label_cli/list_cli.rs | 0 .../config_cli/label_cli/remove_cli.rs | 0 .../{ => rules_cli}/config_cli/rules_cli.rs | 0 .../config_cli/rules_cli/add_cli.rs | 0 .../config_cli/rules_cli/rm_cli.rs | 0 src/cli/rules_cli/run_cli.rs | 60 +++++++++++++++ 14 files changed, 101 insertions(+), 77 deletions(-) rename src/cli/{label_cli.rs => labels_cli.rs} (83%) rename src/cli/{message_cli.rs => messages_cli.rs} (98%) rename src/cli/{ => rules_cli}/config_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/action_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/label_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/label_cli/add_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/label_cli/list_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/label_cli/remove_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/rules_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/rules_cli/add_cli.rs (100%) rename src/cli/{ => rules_cli}/config_cli/rules_cli/rm_cli.rs (100%) create mode 100644 src/cli/rules_cli/run_cli.rs diff --git a/src/cli/label_cli.rs b/src/cli/labels_cli.rs similarity index 83% rename from src/cli/label_cli.rs rename to src/cli/labels_cli.rs index 6680782..171dc84 100644 --- a/src/cli/label_cli.rs +++ b/src/cli/labels_cli.rs @@ -2,9 +2,9 @@ use clap::Parser; use cull_gmail::{Error, GmailClient}; #[derive(Debug, Parser)] -pub struct LabelCli {} +pub struct LabelsCli {} -impl LabelCli { +impl LabelsCli { pub async fn run(&self, client: GmailClient) -> Result<(), Error> { client.show_label(); Ok(()) diff --git a/src/cli/main.rs b/src/cli/main.rs index 4bd91b5..07cccd9 100644 --- a/src/cli/main.rs +++ b/src/cli/main.rs @@ -1,16 +1,14 @@ use clap::{Parser, Subcommand}; -mod config_cli; -mod label_cli; -mod message_cli; +mod labels_cli; +mod messages_cli; mod rules_cli; use cull_gmail::{Config, GmailClient, Result}; use std::error::Error as stdError; -use config_cli::ConfigCli; -use label_cli::LabelCli; -use message_cli::MessageCli; +use labels_cli::LabelsCli; +use messages_cli::MessagesCli; use rules_cli::RulesCli; #[derive(Parser, Debug)] @@ -24,21 +22,14 @@ struct Cli { #[derive(Subcommand, Debug)] enum SubCmds { - /// Configure rules and labels - #[clap( - name = "config", - display_order = 1, - next_help_heading = "Configuration" - )] - Config(ConfigCli), /// List messages - #[clap(name = "message", display_order = 3, next_help_heading = "Messages")] - Message(MessageCli), + #[clap(name = "messages", display_order = 3, next_help_heading = "Labels")] + Message(MessagesCli), /// List labels - #[clap(name = "label", display_order = 2, next_help_heading = "Labels")] - Labels(LabelCli), - /// Run the rules from the rules configuration - #[clap(name = "run", display_order = 6, next_help_heading = "Rule Processing")] + #[clap(name = "labels", display_order = 2, next_help_heading = "Rules")] + Labels(LabelsCli), + /// Configure and run rules + #[clap(name = "rules", display_order = 2)] Rules(RulesCli), } @@ -72,10 +63,9 @@ async fn run(args: Cli) -> Result<()> { let mut client = GmailClient::new(config.credential_file()).await?; match args.sub_command { - SubCmds::Config(config_cli) => config_cli.run(config), - SubCmds::Message(list_cli) => list_cli.run(&mut client).await, - SubCmds::Labels(label_cli) => label_cli.run(client).await, - SubCmds::Rules(run_cli) => run_cli.run(&mut client, config).await, + SubCmds::Message(messages_cli) => messages_cli.run(&mut client).await, + SubCmds::Labels(labels_cli) => labels_cli.run(client).await, + SubCmds::Rules(rules_cli) => rules_cli.run(&mut client, config).await, } } diff --git a/src/cli/message_cli.rs b/src/cli/messages_cli.rs similarity index 98% rename from src/cli/message_cli.rs rename to src/cli/messages_cli.rs index 0bdf633..7afc1a1 100644 --- a/src/cli/message_cli.rs +++ b/src/cli/messages_cli.rs @@ -10,7 +10,7 @@ enum MessageAction { /// Command line options for the list subcommand #[derive(Debug, Parser)] -pub struct MessageCli { +pub struct MessagesCli { /// Maximum results per page #[arg(short, long,display_order = 1, help_heading = "Config", default_value = cull_gmail::DEFAULT_MAX_RESULTS)] max_results: u32, @@ -34,7 +34,7 @@ pub struct MessageCli { action: MessageAction, } -impl MessageCli { +impl MessagesCli { pub(crate) async fn run(&self, client: &mut GmailClient) -> Result<()> { self.set_parameters(client)?; diff --git a/src/cli/rules_cli.rs b/src/cli/rules_cli.rs index 97cc1e5..f3adf23 100644 --- a/src/cli/rules_cli.rs +++ b/src/cli/rules_cli.rs @@ -1,60 +1,34 @@ -use clap::Parser; -use cull_gmail::{Config, EolAction, GmailClient, Result, RuleProcessor}; +use clap::{Parser, Subcommand}; + +mod config_cli; +mod run_cli; + +use cull_gmail::{Config, GmailClient, Result}; + +use config_cli::ConfigCli; +use run_cli::RunCli; + +#[derive(Subcommand, Debug)] +enum SubCmds { + /// Configure end-of-life rules + #[clap(name = "config")] + Config(ConfigCli), + /// Run end-of-life rules + #[clap(name = "run")] + Run(RunCli), +} #[derive(Debug, Parser)] pub struct RulesCli { - /// Execute the action - #[clap(short, long, display_order = 1, help_heading = "Action")] - execute: bool, - /// Skip any rules that apply the action `trash` - #[clap(short = 't', long, display_order = 2, help_heading = "Skip Action")] - skip_trash: bool, - /// Skip any rules that apply the action `delete` - #[clap(short = 'd', long, display_order = 3, help_heading = "Skip Action")] - skip_delete: bool, + #[command(subcommand)] + sub_command: SubCmds, } impl RulesCli { pub async fn run(&self, client: &mut GmailClient, config: Config) -> Result<()> { - let rules = config.get_rules_by_label(); - - for label in config.labels() { - let Some(rule) = rules.get(&label) else { - log::warn!("no rule found for label `{label}`"); - continue; - }; - - log::info!("Executing rule `#{}` for label `{label}`", rule.describe()); - client.set_rule(rule.clone()); - client.set_execute(self.execute); - client.find_rule_and_messages_for_label(&label).await?; - let Some(action) = client.action() else { - log::warn!("no valid action specified for rule #{}", rule.id()); - continue; - }; - - if self.execute { - match action { - EolAction::Trash => { - log::info!("***executing trash messages***"); - if client.batch_trash().await.is_err() { - log::warn!("Move to trash failed for label `{label}`"); - continue; - } - } - EolAction::Delete => { - log::info!("***executing final delete messages***"); - if client.batch_delete().await.is_err() { - log::warn!("Delete failed for label `{label}`"); - continue; - } - } - } - } else { - log::warn!("Execution stopped for dry run"); - } + match &self.sub_command { + SubCmds::Config(config_cli) => config_cli.run(config), + SubCmds::Run(run_cli) => run_cli.run(client, config).await, } - - Ok(()) } } diff --git a/src/cli/config_cli.rs b/src/cli/rules_cli/config_cli.rs similarity index 100% rename from src/cli/config_cli.rs rename to src/cli/rules_cli/config_cli.rs diff --git a/src/cli/config_cli/action_cli.rs b/src/cli/rules_cli/config_cli/action_cli.rs similarity index 100% rename from src/cli/config_cli/action_cli.rs rename to src/cli/rules_cli/config_cli/action_cli.rs diff --git a/src/cli/config_cli/label_cli.rs b/src/cli/rules_cli/config_cli/label_cli.rs similarity index 100% rename from src/cli/config_cli/label_cli.rs rename to src/cli/rules_cli/config_cli/label_cli.rs diff --git a/src/cli/config_cli/label_cli/add_cli.rs b/src/cli/rules_cli/config_cli/label_cli/add_cli.rs similarity index 100% rename from src/cli/config_cli/label_cli/add_cli.rs rename to src/cli/rules_cli/config_cli/label_cli/add_cli.rs diff --git a/src/cli/config_cli/label_cli/list_cli.rs b/src/cli/rules_cli/config_cli/label_cli/list_cli.rs similarity index 100% rename from src/cli/config_cli/label_cli/list_cli.rs rename to src/cli/rules_cli/config_cli/label_cli/list_cli.rs diff --git a/src/cli/config_cli/label_cli/remove_cli.rs b/src/cli/rules_cli/config_cli/label_cli/remove_cli.rs similarity index 100% rename from src/cli/config_cli/label_cli/remove_cli.rs rename to src/cli/rules_cli/config_cli/label_cli/remove_cli.rs diff --git a/src/cli/config_cli/rules_cli.rs b/src/cli/rules_cli/config_cli/rules_cli.rs similarity index 100% rename from src/cli/config_cli/rules_cli.rs rename to src/cli/rules_cli/config_cli/rules_cli.rs diff --git a/src/cli/config_cli/rules_cli/add_cli.rs b/src/cli/rules_cli/config_cli/rules_cli/add_cli.rs similarity index 100% rename from src/cli/config_cli/rules_cli/add_cli.rs rename to src/cli/rules_cli/config_cli/rules_cli/add_cli.rs diff --git a/src/cli/config_cli/rules_cli/rm_cli.rs b/src/cli/rules_cli/config_cli/rules_cli/rm_cli.rs similarity index 100% rename from src/cli/config_cli/rules_cli/rm_cli.rs rename to src/cli/rules_cli/config_cli/rules_cli/rm_cli.rs diff --git a/src/cli/rules_cli/run_cli.rs b/src/cli/rules_cli/run_cli.rs new file mode 100644 index 0000000..e06eab2 --- /dev/null +++ b/src/cli/rules_cli/run_cli.rs @@ -0,0 +1,60 @@ +use clap::Parser; +use cull_gmail::{Config, EolAction, GmailClient, Result, RuleProcessor}; + +#[derive(Debug, Parser)] +pub struct RunCli { + /// Execute the action + #[clap(short, long, display_order = 1, help_heading = "Action")] + execute: bool, + /// Skip any rules that apply the action `trash` + #[clap(short = 't', long, display_order = 2, help_heading = "Skip Action")] + skip_trash: bool, + /// Skip any rules that apply the action `delete` + #[clap(short = 'd', long, display_order = 3, help_heading = "Skip Action")] + skip_delete: bool, +} + +impl RunCli { + pub async fn run(&self, client: &mut GmailClient, config: Config) -> Result<()> { + let rules = config.get_rules_by_label(); + + for label in config.labels() { + let Some(rule) = rules.get(&label) else { + log::warn!("no rule found for label `{label}`"); + continue; + }; + + log::info!("Executing rule `#{}` for label `{label}`", rule.describe()); + client.set_rule(rule.clone()); + client.set_execute(self.execute); + client.find_rule_and_messages_for_label(&label).await?; + let Some(action) = client.action() else { + log::warn!("no valid action specified for rule #{}", rule.id()); + continue; + }; + + if self.execute { + match action { + EolAction::Trash => { + log::info!("***executing trash messages***"); + if client.batch_trash().await.is_err() { + log::warn!("Move to trash failed for label `{label}`"); + continue; + } + } + EolAction::Delete => { + log::info!("***executing final delete messages***"); + if client.batch_delete().await.is_err() { + log::warn!("Delete failed for label `{label}`"); + continue; + } + } + } + } else { + log::warn!("Execution stopped for dry run"); + } + } + + Ok(()) + } +}