1use crate::command::{CommandExecutor, CommandOutput, GitCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone, Default)]
9pub struct LogCommand {
10 pub executor: CommandExecutor,
12 pub max_count: Option<u32>,
14 pub skip: Option<u32>,
16 pub oneline: bool,
18 pub graph: bool,
20 pub all: bool,
22 pub reverse: bool,
24 pub format: Option<String>,
26 pub since: Option<String>,
28 pub until: Option<String>,
30 pub author: Option<String>,
32 pub grep: Option<String>,
34 pub revisions: Vec<String>,
36 pub paths: Vec<String>,
38}
39
40impl LogCommand {
41 #[must_use]
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn max_count(&mut self, n: u32) -> &mut Self {
49 self.max_count = Some(n);
50 self
51 }
52
53 pub fn skip(&mut self, n: u32) -> &mut Self {
55 self.skip = Some(n);
56 self
57 }
58
59 pub fn oneline(&mut self) -> &mut Self {
61 self.oneline = true;
62 self
63 }
64
65 pub fn graph(&mut self) -> &mut Self {
67 self.graph = true;
68 self
69 }
70
71 pub fn all(&mut self) -> &mut Self {
73 self.all = true;
74 self
75 }
76
77 pub fn reverse(&mut self) -> &mut Self {
79 self.reverse = true;
80 self
81 }
82
83 pub fn format(&mut self, fmt: impl Into<String>) -> &mut Self {
85 self.format = Some(fmt.into());
86 self
87 }
88
89 pub fn since(&mut self, s: impl Into<String>) -> &mut Self {
91 self.since = Some(s.into());
92 self
93 }
94
95 pub fn until(&mut self, s: impl Into<String>) -> &mut Self {
97 self.until = Some(s.into());
98 self
99 }
100
101 pub fn author(&mut self, s: impl Into<String>) -> &mut Self {
103 self.author = Some(s.into());
104 self
105 }
106
107 pub fn grep(&mut self, s: impl Into<String>) -> &mut Self {
109 self.grep = Some(s.into());
110 self
111 }
112
113 pub fn revision(&mut self, r: impl Into<String>) -> &mut Self {
115 self.revisions.push(r.into());
116 self
117 }
118
119 pub fn path(&mut self, p: impl Into<String>) -> &mut Self {
121 self.paths.push(p.into());
122 self
123 }
124}
125
126#[async_trait]
127impl GitCommand for LogCommand {
128 type Output = CommandOutput;
129
130 fn get_executor(&self) -> &CommandExecutor {
131 &self.executor
132 }
133
134 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
135 &mut self.executor
136 }
137
138 fn build_command_args(&self) -> Vec<String> {
139 let mut args = vec!["log".to_string()];
140 if let Some(n) = self.max_count {
141 args.push(format!("-n{n}"));
142 }
143 if let Some(n) = self.skip {
144 args.push(format!("--skip={n}"));
145 }
146 if self.oneline {
147 args.push("--oneline".into());
148 }
149 if self.graph {
150 args.push("--graph".into());
151 }
152 if self.all {
153 args.push("--all".into());
154 }
155 if self.reverse {
156 args.push("--reverse".into());
157 }
158 if let Some(f) = &self.format {
159 args.push(format!("--format={f}"));
160 }
161 if let Some(s) = &self.since {
162 args.push(format!("--since={s}"));
163 }
164 if let Some(s) = &self.until {
165 args.push(format!("--until={s}"));
166 }
167 if let Some(s) = &self.author {
168 args.push(format!("--author={s}"));
169 }
170 if let Some(s) = &self.grep {
171 args.push(format!("--grep={s}"));
172 }
173 args.extend(self.revisions.iter().cloned());
174 if !self.paths.is_empty() {
175 args.push("--".into());
176 args.extend(self.paths.iter().cloned());
177 }
178 args
179 }
180
181 async fn execute(&self) -> Result<CommandOutput> {
182 self.execute_raw().await
183 }
184}