Skip to main content

git_spawn/command/
reflog.rs

1//! `git reflog` — manage and inspect reflog information.
2
3use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Actions supported by `git reflog`.
8#[derive(Debug, Clone)]
9pub enum ReflogAction {
10    /// `git reflog [show] [<ref>]`.
11    Show {
12        /// Ref to inspect (default `HEAD`).
13        ref_name: Option<String>,
14        /// `-n N` / `--max-count=N`.
15        max_count: Option<u32>,
16        /// Extra arbitrary format.
17        format: Option<String>,
18    },
19    /// `git reflog expire [options] <refs>`.
20    Expire {
21        /// `--all`.
22        all: bool,
23        /// `--expire=<time>`.
24        expire: Option<String>,
25        /// `--expire-unreachable=<time>`.
26        expire_unreachable: Option<String>,
27        /// `--stale-fix`.
28        stale_fix: bool,
29        /// Refs to expire.
30        refs: Vec<String>,
31    },
32    /// `git reflog delete <entry>…`.
33    Delete {
34        /// Entries to delete (e.g. `HEAD@{0}`).
35        entries: Vec<String>,
36        /// `--rewrite`.
37        rewrite: bool,
38    },
39    /// `git reflog exists <ref>`.
40    Exists {
41        /// Ref to check.
42        ref_name: String,
43    },
44}
45
46/// Builder for `git reflog`.
47#[derive(Debug, Clone)]
48pub struct ReflogCommand {
49    /// Shared executor.
50    pub executor: CommandExecutor,
51    /// Action.
52    pub action: ReflogAction,
53}
54
55impl ReflogCommand {
56    /// `reflog` / `reflog show`.
57    #[must_use]
58    pub fn show() -> Self {
59        Self {
60            executor: CommandExecutor::default(),
61            action: ReflogAction::Show {
62                ref_name: None,
63                max_count: None,
64                format: None,
65            },
66        }
67    }
68
69    /// Set the ref (for `show`).
70    #[must_use]
71    pub fn ref_name(mut self, r: impl Into<String>) -> Self {
72        if let ReflogAction::Show { ref_name, .. } = &mut self.action {
73            *ref_name = Some(r.into());
74        }
75        self
76    }
77
78    /// `-n` / `--max-count` (for `show`).
79    #[must_use]
80    pub fn max_count(mut self, n: u32) -> Self {
81        if let ReflogAction::Show { max_count, .. } = &mut self.action {
82            *max_count = Some(n);
83        }
84        self
85    }
86
87    /// Set `--format` (for `show`).
88    #[must_use]
89    pub fn format(mut self, f: impl Into<String>) -> Self {
90        if let ReflogAction::Show { format, .. } = &mut self.action {
91            *format = Some(f.into());
92        }
93        self
94    }
95
96    /// `reflog expire`.
97    #[must_use]
98    pub fn expire() -> Self {
99        Self {
100            executor: CommandExecutor::default(),
101            action: ReflogAction::Expire {
102                all: false,
103                expire: None,
104                expire_unreachable: None,
105                stale_fix: false,
106                refs: vec![],
107            },
108        }
109    }
110
111    /// `reflog delete`.
112    #[must_use]
113    pub fn delete(entries: Vec<String>) -> Self {
114        Self {
115            executor: CommandExecutor::default(),
116            action: ReflogAction::Delete {
117                entries,
118                rewrite: false,
119            },
120        }
121    }
122
123    /// `reflog exists <ref>`.
124    pub fn exists(r: impl Into<String>) -> Self {
125        Self {
126            executor: CommandExecutor::default(),
127            action: ReflogAction::Exists { ref_name: r.into() },
128        }
129    }
130}
131
132#[async_trait]
133impl GitCommand for ReflogCommand {
134    type Output = CommandOutput;
135    fn get_executor(&self) -> &CommandExecutor {
136        &self.executor
137    }
138    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
139        &mut self.executor
140    }
141    fn build_command_args(&self) -> Vec<String> {
142        let mut args = vec!["reflog".to_string()];
143        match &self.action {
144            ReflogAction::Show {
145                ref_name,
146                max_count,
147                format,
148            } => {
149                args.push("show".into());
150                if let Some(n) = max_count {
151                    args.push(format!("-n{n}"));
152                }
153                if let Some(f) = format {
154                    args.push(format!("--format={f}"));
155                }
156                if let Some(r) = ref_name {
157                    args.push(r.clone());
158                }
159            }
160            ReflogAction::Expire {
161                all,
162                expire,
163                expire_unreachable,
164                stale_fix,
165                refs,
166            } => {
167                args.push("expire".into());
168                if *all {
169                    args.push("--all".into());
170                }
171                if *stale_fix {
172                    args.push("--stale-fix".into());
173                }
174                if let Some(e) = expire {
175                    args.push(format!("--expire={e}"));
176                }
177                if let Some(e) = expire_unreachable {
178                    args.push(format!("--expire-unreachable={e}"));
179                }
180                args.extend(refs.iter().cloned());
181            }
182            ReflogAction::Delete { entries, rewrite } => {
183                args.push("delete".into());
184                if *rewrite {
185                    args.push("--rewrite".into());
186                }
187                args.extend(entries.iter().cloned());
188            }
189            ReflogAction::Exists { ref_name } => {
190                args.push("exists".into());
191                args.push(ref_name.clone());
192            }
193        }
194        args
195    }
196    async fn execute(&self) -> Result<CommandOutput> {
197        self.execute_raw().await
198    }
199}