|
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