|
1 use crate::errors::HgError; |
|
2 use crate::matchers::Matcher; |
|
3 use crate::repo::Repo; |
|
4 use crate::revlog::manifest::Manifest; |
|
5 use crate::utils::filter_map_results; |
|
6 use crate::utils::hg_path::HgPath; |
|
7 use crate::utils::merge_join_results_by; |
|
8 |
|
9 use crate::Revision; |
|
10 |
|
11 use itertools::EitherOrBoth; |
|
12 |
|
13 #[derive(Debug, Copy, Clone)] |
|
14 pub enum DiffStatus { |
|
15 Removed, |
|
16 Added, |
|
17 Matching, |
|
18 Modified, |
|
19 } |
|
20 |
|
21 pub struct StatusRevRev { |
|
22 manifest1: Manifest, |
|
23 manifest2: Manifest, |
|
24 narrow_matcher: Box<dyn Matcher>, |
|
25 } |
|
26 |
|
27 fn manifest_for_rev(repo: &Repo, rev: Revision) -> Result<Manifest, HgError> { |
|
28 repo.manifest_for_rev(rev.into()).map_err(|e| { |
|
29 HgError::corrupted(format!( |
|
30 "manifest lookup failed for revision {}: {}", |
|
31 rev, e |
|
32 )) |
|
33 }) |
|
34 } |
|
35 |
|
36 pub fn status_rev_rev_no_copies( |
|
37 repo: &Repo, |
|
38 rev1: Revision, |
|
39 rev2: Revision, |
|
40 narrow_matcher: Box<dyn Matcher>, |
|
41 ) -> Result<StatusRevRev, HgError> { |
|
42 let manifest1 = manifest_for_rev(repo, rev1)?; |
|
43 let manifest2 = manifest_for_rev(repo, rev2)?; |
|
44 Ok(StatusRevRev { |
|
45 manifest1, |
|
46 manifest2, |
|
47 narrow_matcher, |
|
48 }) |
|
49 } |
|
50 |
|
51 impl StatusRevRev { |
|
52 pub fn iter( |
|
53 &self, |
|
54 ) -> impl Iterator<Item = Result<(&HgPath, DiffStatus), HgError>> { |
|
55 let iter1 = self.manifest1.iter(); |
|
56 let iter2 = self.manifest2.iter(); |
|
57 |
|
58 let merged = |
|
59 merge_join_results_by(iter1, iter2, |i1, i2| i1.path.cmp(i2.path)); |
|
60 |
|
61 filter_map_results(merged, |entry| { |
|
62 let (path, status) = match entry { |
|
63 EitherOrBoth::Left(entry) => { |
|
64 let path = entry.path; |
|
65 (path, DiffStatus::Removed) |
|
66 } |
|
67 EitherOrBoth::Right(entry) => { |
|
68 let path = entry.path; |
|
69 (path, DiffStatus::Added) |
|
70 } |
|
71 EitherOrBoth::Both(entry1, entry2) => { |
|
72 let path = entry1.path; |
|
73 if entry1.node_id().unwrap() == entry2.node_id().unwrap() |
|
74 && entry1.flags == entry2.flags |
|
75 { |
|
76 (path, DiffStatus::Matching) |
|
77 } else { |
|
78 (path, DiffStatus::Modified) |
|
79 } |
|
80 } |
|
81 }; |
|
82 Ok(if self.narrow_matcher.matches(path) { |
|
83 Some((path, status)) |
|
84 } else { |
|
85 None |
|
86 }) |
|
87 }) |
|
88 } |
|
89 } |