♻️ refactor(cli): restructure cli commands for better organization

- 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
This commit is contained in:
Jeremiah Russell
2025-10-15 10:55:32 +01:00
committed by Jeremiah Russell
parent 7c2bcd37b4
commit 3beab7d82d
14 changed files with 101 additions and 77 deletions

View File

@@ -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(())

View File

@@ -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,
}
}

View File

@@ -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)?;

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}