|
1 | 1 | use crate::{Change, CrateVersion, Index}; |
2 | 2 | use git_repository as git; |
3 | | -use git_repository::bstr::BStr; |
4 | | -use git_repository::diff::tree::visit::Action; |
5 | 3 | use git_repository::prelude::{FindExt, ObjectIdExt, TreeIterExt}; |
6 | 4 | use git_repository::refs::transaction::PreviousValue; |
7 | | -use similar::ChangeTag; |
8 | 5 | use std::convert::TryFrom; |
9 | 6 |
|
10 | 7 | static LINE_ADDED_INDICATOR: char = '+'; |
11 | 8 |
|
| 9 | +mod delegate; |
| 10 | +use delegate::Delegate; |
| 11 | + |
12 | 12 | /// The error returned by methods dealing with obtaining index changes. |
13 | 13 | #[derive(Debug, thiserror::Error)] |
14 | 14 | #[allow(missing_docs)] |
@@ -175,119 +175,6 @@ impl Index { |
175 | 175 | }; |
176 | 176 | let from = into_tree(from.into())?; |
177 | 177 | let to = into_tree(to.into())?; |
178 | | - struct Delegate<'repo> { |
179 | | - changes: Vec<Change>, |
180 | | - deletes: Vec<CrateVersion>, |
181 | | - file_name: git::bstr::BString, |
182 | | - err: Option<Error>, |
183 | | - repo: &'repo git::Repository, |
184 | | - } |
185 | | - impl<'repo> Delegate<'repo> { |
186 | | - fn from_repo(repo: &'repo git::Repository) -> Self { |
187 | | - Delegate { |
188 | | - changes: Vec::new(), |
189 | | - deletes: Vec::new(), |
190 | | - err: None, |
191 | | - file_name: Default::default(), |
192 | | - repo, |
193 | | - } |
194 | | - } |
195 | | - fn handle(&mut self, change: git::diff::tree::visit::Change) -> Result<(), Error> { |
196 | | - use git::diff::tree::visit::Change::*; |
197 | | - use git::objs::tree::EntryMode::*; |
198 | | - fn entry_data( |
199 | | - repo: &git::Repository, |
200 | | - entry: git::objs::tree::EntryMode, |
201 | | - oid: git::hash::ObjectId, |
202 | | - ) -> Result<Option<git::Object<'_>>, Error> { |
203 | | - matches!(entry, Blob | BlobExecutable) |
204 | | - .then(|| repo.find_object(oid)) |
205 | | - .transpose() |
206 | | - .map_err(Into::into) |
207 | | - } |
208 | | - use git::bstr::ByteSlice; |
209 | | - match change { |
210 | | - Addition { entry_mode, oid } => { |
211 | | - if let Some(obj) = entry_data(self.repo, entry_mode, oid)? { |
212 | | - for line in (&obj.data).lines() { |
213 | | - self.changes |
214 | | - .push(Change::Added(serde_json::from_slice(line)?)); |
215 | | - } |
216 | | - } |
217 | | - } |
218 | | - Deletion { .. } => { |
219 | | - self.changes.push(Change::Deleted { |
220 | | - name: self.file_name.to_string(), |
221 | | - }); |
222 | | - } |
223 | | - Modification { |
224 | | - previous_entry_mode, |
225 | | - previous_oid, |
226 | | - entry_mode, |
227 | | - oid, |
228 | | - } => { |
229 | | - let pair = entry_data(self.repo, previous_entry_mode, previous_oid)? |
230 | | - .zip(entry_data(self.repo, entry_mode, oid)?); |
231 | | - if let Some((old, new)) = pair { |
232 | | - let diff = similar::TextDiffConfig::default() |
233 | | - .algorithm(similar::Algorithm::Myers) |
234 | | - .diff_lines(old.data.as_slice(), new.data.as_slice()); |
235 | | - for change in diff.iter_all_changes() { |
236 | | - match change.tag() { |
237 | | - ChangeTag::Delete | ChangeTag::Insert => { |
238 | | - let version = |
239 | | - serde_json::from_slice::<CrateVersion>(change.value())?; |
240 | | - if change.tag() == ChangeTag::Insert { |
241 | | - self.changes.push(if version.yanked { |
242 | | - Change::Yanked(version) |
243 | | - } else { |
244 | | - Change::Added(version) |
245 | | - }); |
246 | | - } else { |
247 | | - self.deletes.push(version); |
248 | | - } |
249 | | - } |
250 | | - ChangeTag::Equal => {} |
251 | | - } |
252 | | - } |
253 | | - } |
254 | | - } |
255 | | - } |
256 | | - Ok(()) |
257 | | - } |
258 | | - fn into_result(self) -> Result<Vec<Change>, Error> { |
259 | | - // assert_eq!( |
260 | | - // self.deletes.len(), |
261 | | - // 0, |
262 | | - // "TODO: handle apparent version deletions" |
263 | | - // ); |
264 | | - match self.err { |
265 | | - Some(err) => Err(err), |
266 | | - None => Ok(self.changes), |
267 | | - } |
268 | | - } |
269 | | - } |
270 | | - impl git::diff::tree::Visit for Delegate<'_> { |
271 | | - fn pop_front_tracked_path_and_set_current(&mut self) {} |
272 | | - fn push_back_tracked_path_component(&mut self, _component: &BStr) {} |
273 | | - fn push_path_component(&mut self, component: &BStr) { |
274 | | - use git::bstr::ByteVec; |
275 | | - self.file_name.clear(); |
276 | | - self.file_name.push_str(component); |
277 | | - } |
278 | | - fn pop_path_component(&mut self) {} |
279 | | - |
280 | | - fn visit(&mut self, change: git::diff::tree::visit::Change) -> Action { |
281 | | - match self.handle(change) { |
282 | | - Ok(()) => Action::Continue, |
283 | | - Err(err) => { |
284 | | - self.err = err.into(); |
285 | | - Action::Cancel |
286 | | - } |
287 | | - } |
288 | | - } |
289 | | - } |
290 | | - |
291 | 178 | let mut delegate = Delegate::from_repo(&self.repo); |
292 | 179 | let file_changes = git::objs::TreeRefIter::from_bytes(&from.data).changes_needed( |
293 | 180 | git::objs::TreeRefIter::from_bytes(&to.data), |
|
0 commit comments