|
1 | | -use gix::bstr::{BStr, BString, ByteSlice}; |
| 1 | +use anyhow::Context; |
| 2 | +use gix::bstr::{BString, ByteSlice}; |
2 | 3 | use gix::diff::blob::intern::TokenSource; |
3 | 4 | use gix::diff::blob::UnifiedDiffBuilder; |
4 | 5 | use gix::objs::tree::EntryMode; |
5 | 6 | use gix::odb::store::RefreshMode; |
6 | 7 | use gix::prelude::ObjectIdExt; |
7 | | -use gix::ObjectId; |
8 | 8 |
|
9 | 9 | pub fn tree( |
10 | 10 | mut repo: gix::Repository, |
@@ -118,156 +118,42 @@ fn typed_location(mut location: BString, mode: EntryMode) -> BString { |
118 | 118 | pub fn file( |
119 | 119 | mut repo: gix::Repository, |
120 | 120 | out: &mut dyn std::io::Write, |
121 | | - old_treeish: BString, |
122 | | - new_treeish: BString, |
123 | | - path: BString, |
| 121 | + old_revspec: BString, |
| 122 | + new_revspec: BString, |
124 | 123 | ) -> Result<(), anyhow::Error> { |
125 | 124 | repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?)); |
126 | 125 | repo.objects.refresh = RefreshMode::Never; |
127 | 126 |
|
128 | | - let old_tree_id = repo.rev_parse_single(old_treeish.as_bstr())?; |
129 | | - let new_tree_id = repo.rev_parse_single(new_treeish.as_bstr())?; |
130 | | - |
131 | | - let old_tree = old_tree_id.object()?.peel_to_tree()?; |
132 | | - let new_tree = new_tree_id.object()?.peel_to_tree()?; |
133 | | - |
134 | | - let mut old_tree_buf = Vec::new(); |
135 | | - let mut new_tree_buf = Vec::new(); |
136 | | - |
137 | | - use gix::diff::object::FindExt; |
138 | | - |
139 | | - let old_tree_iter = repo.objects.find_tree_iter(&old_tree.id(), &mut old_tree_buf)?; |
140 | | - let new_tree_iter = repo.objects.find_tree_iter(&new_tree.id(), &mut new_tree_buf)?; |
141 | | - |
142 | | - use gix::diff::tree::{ |
143 | | - recorder::{self, Location}, |
144 | | - Recorder, |
145 | | - }; |
146 | | - |
147 | | - struct FindChangeToPath { |
148 | | - inner: Recorder, |
149 | | - interesting_path: BString, |
150 | | - change: Option<recorder::Change>, |
151 | | - } |
152 | | - |
153 | | - impl FindChangeToPath { |
154 | | - fn new(interesting_path: &BStr) -> Self { |
155 | | - let inner = Recorder::default().track_location(Some(Location::Path)); |
156 | | - |
157 | | - FindChangeToPath { |
158 | | - inner, |
159 | | - interesting_path: interesting_path.into(), |
160 | | - change: None, |
161 | | - } |
162 | | - } |
163 | | - } |
164 | | - |
165 | | - use gix::diff::tree::{visit, Visit}; |
| 127 | + let old_resolved_revspec = repo.rev_parse(old_revspec.as_bstr())?; |
| 128 | + let new_resolved_revspec = repo.rev_parse(new_revspec.as_bstr())?; |
166 | 129 |
|
167 | | - impl Visit for FindChangeToPath { |
168 | | - fn pop_front_tracked_path_and_set_current(&mut self) { |
169 | | - self.inner.pop_front_tracked_path_and_set_current(); |
170 | | - } |
171 | | - |
172 | | - fn push_back_tracked_path_component(&mut self, component: &BStr) { |
173 | | - self.inner.push_back_tracked_path_component(component); |
174 | | - } |
175 | | - |
176 | | - fn push_path_component(&mut self, component: &BStr) { |
177 | | - self.inner.push_path_component(component); |
178 | | - } |
179 | | - |
180 | | - fn pop_path_component(&mut self) { |
181 | | - self.inner.pop_path_component(); |
182 | | - } |
183 | | - |
184 | | - fn visit(&mut self, change: visit::Change) -> visit::Action { |
185 | | - if self.inner.path() == self.interesting_path { |
186 | | - self.change = Some(match change { |
187 | | - visit::Change::Deletion { |
188 | | - entry_mode, |
189 | | - oid, |
190 | | - relation, |
191 | | - } => recorder::Change::Deletion { |
192 | | - entry_mode, |
193 | | - oid, |
194 | | - path: self.inner.path_clone(), |
195 | | - relation, |
196 | | - }, |
197 | | - visit::Change::Addition { |
198 | | - entry_mode, |
199 | | - oid, |
200 | | - relation, |
201 | | - } => recorder::Change::Addition { |
202 | | - entry_mode, |
203 | | - oid, |
204 | | - path: self.inner.path_clone(), |
205 | | - relation, |
206 | | - }, |
207 | | - visit::Change::Modification { |
208 | | - previous_entry_mode, |
209 | | - previous_oid, |
210 | | - entry_mode, |
211 | | - oid, |
212 | | - } => recorder::Change::Modification { |
213 | | - previous_entry_mode, |
214 | | - previous_oid, |
215 | | - entry_mode, |
216 | | - oid, |
217 | | - path: self.inner.path_clone(), |
218 | | - }, |
219 | | - }); |
220 | | - |
221 | | - visit::Action::Cancel |
222 | | - } else { |
223 | | - visit::Action::Continue |
224 | | - } |
225 | | - } |
226 | | - } |
227 | | - |
228 | | - let mut recorder = FindChangeToPath::new(path.as_ref()); |
229 | | - let state = gix::diff::tree::State::default(); |
230 | | - let result = gix::diff::tree(old_tree_iter, new_tree_iter, state, &repo.objects, &mut recorder); |
231 | | - |
232 | | - let change = match result { |
233 | | - Ok(_) | Err(gix::diff::tree::Error::Cancelled) => recorder.change, |
234 | | - Err(error) => return Err(error.into()), |
235 | | - }; |
| 130 | + let old_blob_id = old_resolved_revspec |
| 131 | + .single() |
| 132 | + .context(format!("rev-spec '{old_revspec}' must resolve to a single object"))?; |
| 133 | + let new_blob_id = new_resolved_revspec |
| 134 | + .single() |
| 135 | + .context(format!("rev-spec '{new_revspec}' must resolve to a single object"))?; |
236 | 136 |
|
237 | | - let Some(change) = change else { |
238 | | - anyhow::bail!( |
239 | | - "There was no change to {} between {} and {}", |
240 | | - &path, |
241 | | - old_treeish, |
242 | | - new_treeish |
243 | | - ) |
244 | | - }; |
| 137 | + let (old_path, _) = old_resolved_revspec |
| 138 | + .path_and_mode() |
| 139 | + .context(format!("rev-spec '{old_revspec}' must contain a path"))?; |
| 140 | + let (new_path, _) = new_resolved_revspec |
| 141 | + .path_and_mode() |
| 142 | + .context(format!("rev-spec '{new_revspec}' must contain a path"))?; |
245 | 143 |
|
246 | 144 | let mut resource_cache = repo.diff_resource_cache(gix::diff::blob::pipeline::Mode::ToGit, Default::default())?; |
247 | 145 |
|
248 | | - let (previous_oid, oid) = match change { |
249 | | - recorder::Change::Addition { oid, .. } => { |
250 | | - // Setting `previous_oid` to `ObjectId::empty_blob` makes `diff` see an addition. |
251 | | - (ObjectId::empty_blob(gix::hash::Kind::Sha1), oid) |
252 | | - } |
253 | | - recorder::Change::Deletion { oid: previous_oid, .. } => { |
254 | | - // Setting `oid` to `ObjectId::empty_blob` makes `diff` see a deletion. |
255 | | - (previous_oid, ObjectId::empty_blob(gix::hash::Kind::Sha1)) |
256 | | - } |
257 | | - recorder::Change::Modification { previous_oid, oid, .. } => (previous_oid, oid), |
258 | | - }; |
259 | | - |
260 | 146 | resource_cache.set_resource( |
261 | | - previous_oid, |
| 147 | + old_blob_id.into(), |
262 | 148 | gix::object::tree::EntryKind::Blob, |
263 | | - path.as_slice().into(), |
| 149 | + old_path, |
264 | 150 | gix::diff::blob::ResourceKind::OldOrSource, |
265 | 151 | &repo.objects, |
266 | 152 | )?; |
267 | 153 | resource_cache.set_resource( |
268 | | - oid, |
| 154 | + new_blob_id.into(), |
269 | 155 | gix::object::tree::EntryKind::Blob, |
270 | | - path.as_slice().into(), |
| 156 | + new_path, |
271 | 157 | gix::diff::blob::ResourceKind::NewOrDestination, |
272 | 158 | &repo.objects, |
273 | 159 | )?; |
|
0 commit comments