1use crate::command::GitCommand;
33use crate::command::log::LogCommand;
34use crate::error::Result;
35use crate::parse::{LOG_FORMAT, parse_log};
36use crate::repo::Repository;
37
38pub use crate::parse::CommitEntry as Commit;
39
40#[derive(Debug)]
43pub struct HistoryWalk<'a> {
44 repo: &'a Repository,
45 revisions: Vec<String>,
46 paths: Vec<String>,
47 max_count: Option<u32>,
48 skip: Option<u32>,
49 since: Option<String>,
50 until: Option<String>,
51 author: Option<String>,
52 grep: Option<String>,
53 reverse: bool,
54}
55
56impl<'a> HistoryWalk<'a> {
57 fn new(repo: &'a Repository) -> Self {
58 Self {
59 repo,
60 revisions: Vec::new(),
61 paths: Vec::new(),
62 max_count: None,
63 skip: None,
64 since: None,
65 until: None,
66 author: None,
67 grep: None,
68 reverse: false,
69 }
70 }
71
72 #[must_use]
74 pub fn max_count(mut self, n: u32) -> Self {
75 self.max_count = Some(n);
76 self
77 }
78
79 #[must_use]
81 pub fn skip(mut self, n: u32) -> Self {
82 self.skip = Some(n);
83 self
84 }
85
86 #[must_use]
88 pub fn since(mut self, s: impl Into<String>) -> Self {
89 self.since = Some(s.into());
90 self
91 }
92
93 #[must_use]
95 pub fn until(mut self, s: impl Into<String>) -> Self {
96 self.until = Some(s.into());
97 self
98 }
99
100 #[must_use]
102 pub fn author(mut self, s: impl Into<String>) -> Self {
103 self.author = Some(s.into());
104 self
105 }
106
107 #[must_use]
109 pub fn grep(mut self, s: impl Into<String>) -> Self {
110 self.grep = Some(s.into());
111 self
112 }
113
114 #[must_use]
117 pub fn revision(mut self, r: impl Into<String>) -> Self {
118 self.revisions.push(r.into());
119 self
120 }
121
122 #[must_use]
124 pub fn path(mut self, p: impl Into<String>) -> Self {
125 self.paths.push(p.into());
126 self
127 }
128
129 #[must_use]
131 pub fn reverse(mut self) -> Self {
132 self.reverse = true;
133 self
134 }
135
136 pub async fn execute(self) -> Result<Vec<Commit>> {
138 let mut cmd = LogCommand::new();
139 cmd.format(LOG_FORMAT);
140 if let Some(n) = self.max_count {
141 cmd.max_count(n);
142 }
143 if let Some(n) = self.skip {
144 cmd.skip(n);
145 }
146 if let Some(s) = self.since {
147 cmd.since(s);
148 }
149 if let Some(s) = self.until {
150 cmd.until(s);
151 }
152 if let Some(s) = self.author {
153 cmd.author(s);
154 }
155 if let Some(s) = self.grep {
156 cmd.grep(s);
157 }
158 if self.reverse {
159 cmd.reverse();
160 }
161 for r in self.revisions {
162 cmd.revision(r);
163 }
164 for p in self.paths {
165 cmd.path(p);
166 }
167 cmd.current_dir(self.repo.path());
168 let out = cmd.execute().await?;
169 parse_log(&out.stdout)
170 }
171}
172
173impl Repository {
174 #[must_use]
176 pub fn history(&self) -> HistoryWalk<'_> {
177 HistoryWalk::new(self)
178 }
179}