1pub mod prompts;
2pub mod status;
3pub mod template;
4
5use std::collections::HashMap;
6
7use inquire::InquireError;
8use status::Status;
9use template::Template;
10
11use crate::{
12 cli::ReviseCommands,
13 config::{self, Hook},
14 error::ReviseResult,
15 git::GitUtils,
16 hook::{HookRunner, HookType},
17};
18
19#[derive(Default, Debug)]
20pub struct Revise {
21 pub template: Template,
22 pub status: Status,
23 pub message: String,
24 pub hooks: HashMap<HookType, Vec<Hook>>,
25}
26
27impl Revise {
28 pub async fn run(&mut self, cmd: ReviseCommands) -> ReviseResult<()> {
29 let cfg = config::get_config();
30 self.hooks.clone_from(&cfg.hooks);
31 if let Some(msg) = &cmd.message {
33 self.run_pre_commit_hooks()?;
34 GitUtils::new().commit(msg)?;
35 self.run_post_commit_hooks()?;
36 return Ok(());
37 }
38
39 if !cmd.add.is_empty() {
40 self.run_pre_add_hooks()?;
41 GitUtils::new().add(&cmd.add)?;
42 self.run_post_add_hooks()?;
43 }
44 self.run_pre_commit_hooks()?;
45 match self.template.run(&cmd).await {
46 Ok(msg) => {
47 GitUtils::new().commit(&msg)?;
48 self.run_post_commit_hooks()?;
49 Ok(())
50 }
51 Err(err) => {
52 if let Some(
53 InquireError::OperationCanceled
54 | InquireError::OperationInterrupted,
55 ) = err.downcast_ref()
56 {
57 Ok(())
58 } else {
59 Err(err)
60 }
61 }
62 }
63 }
64
65 pub fn run_pre_commit_hooks(&self) -> ReviseResult<()> {
66 let hooks = self.hooks.get(&HookType::PreCommit);
67 let mut sorted_hooks: Vec<_> = hooks.unwrap().iter().collect();
68 sorted_hooks.sort_by_key(|h| h.order.unwrap_or(u32::MAX));
69
70 for hook in sorted_hooks {
71 if hook.skip.unwrap_or(false) {
72 println!("Skipping hook: {}", hook.command);
73 continue;
74 }
75 HookRunner::run_hook(HookRunner::run_command, &hook.command)?;
76 }
77 Ok(())
78 }
79
80 pub fn run_post_commit_hooks(&self) -> ReviseResult<()> {
81 let hooks = self.hooks.get(&HookType::PostCommit);
82 let mut sorted_hooks: Vec<_> = hooks.unwrap().iter().collect();
83 sorted_hooks.sort_by_key(|h| h.order.unwrap_or(u32::MAX));
84
85 for hook in sorted_hooks {
86 if hook.skip.unwrap_or(false) {
87 println!("Skipping hook: {}", hook.command);
88 continue;
89 }
90 HookRunner::run_hook(HookRunner::run_command, &hook.command)?;
91 }
92 Ok(())
93 }
94
95 pub fn run_pre_add_hooks(&self) -> ReviseResult<()> {
96 let hooks = self.hooks.get(&HookType::PreAdd);
97 let mut sorted_hooks: Vec<_> = hooks.unwrap().iter().collect();
98 sorted_hooks.sort_by_key(|h| h.order.unwrap_or(u32::MAX));
99
100 for hook in sorted_hooks {
101 if hook.skip.unwrap_or(false) {
102 println!("Skipping hook: {}", hook.command);
103 continue;
104 }
105 HookRunner::run_hook(HookRunner::run_command, &hook.command)?;
106 }
107 Ok(())
108 }
109
110 pub fn run_post_add_hooks(&self) -> ReviseResult<()> {
111 let hooks = self.hooks.get(&HookType::PostAdd);
112 let mut sorted_hooks: Vec<_> = hooks.unwrap().iter().collect();
113 sorted_hooks.sort_by_key(|h| h.order.unwrap_or(u32::MAX));
114
115 for hook in sorted_hooks {
116 if hook.skip.unwrap_or(false) {
117 println!("Skipping hook: {}", hook.command);
118 continue;
119 }
120 HookRunner::run_hook(HookRunner::run_command, &hook.command)?;
121 }
122 Ok(())
123 }
124}