Skip to content

Commit 28a8e93

Browse files
committed
feat: add index diffing
1 parent 4989cda commit 28a8e93

File tree

11 files changed

+1944
-4
lines changed

11 files changed

+1944
-4
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-diff/Cargo.toml

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@ rust-version = "1.65"
1313
autotests = false
1414

1515
[features]
16-
default = ["blob"]
17-
## Enable diffing of blobs using imara-diff, which also allows for a generic rewrite tracking implementation.
16+
default = ["blob", "index"]
17+
## Enable diffing of blobs using imara-diff.
1818
blob = ["dep:imara-diff", "dep:gix-filter", "dep:gix-worktree", "dep:gix-path", "dep:gix-fs", "dep:gix-command", "dep:gix-tempfile", "dep:gix-trace", "dep:gix-traverse"]
19+
## Enable diffing of two indices, which also allows for a generic rewrite tracking implementation.
20+
index = ["dep:gix-index"]
1921
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
20-
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"]
22+
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde", "gix-index?/serde"]
2123
## Make it possible to compile to the `wasm32-unknown-unknown` target.
2224
wasm = ["dep:getrandom"]
2325

2426
[lib]
2527
doctest = false
2628

2729
[dependencies]
30+
gix-index = { version = "^0.37.0", path = "../gix-index", optional = true }
2831
gix-hash = { version = "^0.15.1", path = "../gix-hash" }
2932
gix-object = { version = "^0.46.1", path = "../gix-object" }
3033
gix-filter = { version = "^0.16.0", path = "../gix-filter", optional = true }

gix-diff/src/index/change.rs

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
use crate::index::{Change, ChangeRef};
2+
use crate::rewrites;
3+
use crate::rewrites::tracker::ChangeKind;
4+
use crate::tree::visit::Relation;
5+
use bstr::BStr;
6+
use gix_object::tree;
7+
use std::borrow::Cow;
8+
9+
impl ChangeRef<'_, '_> {
10+
/// Copy everything into an owned version of this instance.
11+
pub fn into_owned(self) -> Change {
12+
match self {
13+
ChangeRef::Addition {
14+
location,
15+
index,
16+
entry_mode,
17+
id,
18+
} => ChangeRef::Addition {
19+
location: Cow::Owned(location.into_owned()),
20+
index,
21+
entry_mode,
22+
id: Cow::Owned(id.into_owned()),
23+
},
24+
ChangeRef::Deletion {
25+
location,
26+
index,
27+
entry_mode,
28+
id,
29+
} => ChangeRef::Deletion {
30+
location: Cow::Owned(location.into_owned()),
31+
index,
32+
entry_mode,
33+
id: Cow::Owned(id.into_owned()),
34+
},
35+
ChangeRef::Modification {
36+
location,
37+
previous_index,
38+
previous_entry_mode,
39+
previous_id,
40+
index,
41+
entry_mode,
42+
id,
43+
} => ChangeRef::Modification {
44+
location: Cow::Owned(location.into_owned()),
45+
previous_index,
46+
previous_entry_mode,
47+
previous_id: Cow::Owned(previous_id.into_owned()),
48+
index,
49+
entry_mode,
50+
id: Cow::Owned(id.into_owned()),
51+
},
52+
ChangeRef::Rewrite {
53+
source_location,
54+
source_index,
55+
source_entry_mode,
56+
source_id,
57+
location,
58+
index,
59+
entry_mode,
60+
id,
61+
copy,
62+
} => ChangeRef::Rewrite {
63+
source_location: Cow::Owned(source_location.into_owned()),
64+
source_index,
65+
source_entry_mode,
66+
source_id: Cow::Owned(source_id.into_owned()),
67+
location: Cow::Owned(location.into_owned()),
68+
index,
69+
entry_mode,
70+
id: Cow::Owned(id.into_owned()),
71+
copy,
72+
},
73+
ChangeRef::Unmerged {
74+
location,
75+
stage,
76+
index,
77+
entry_mode,
78+
id,
79+
} => ChangeRef::Unmerged {
80+
location: Cow::Owned(location.into_owned()),
81+
stage,
82+
index,
83+
entry_mode,
84+
id: Cow::Owned(id.into_owned()),
85+
},
86+
}
87+
}
88+
}
89+
90+
impl ChangeRef<'_, '_> {
91+
/// Return all shared fields among all variants: `(location, index, entry_mode, id)`
92+
///
93+
/// In case of rewrites, the fields return to the current change.
94+
pub fn fields(&self) -> (&BStr, usize, gix_index::entry::Mode, &gix_hash::oid) {
95+
match self {
96+
ChangeRef::Addition {
97+
location,
98+
index,
99+
entry_mode,
100+
id,
101+
..
102+
}
103+
| ChangeRef::Deletion {
104+
location,
105+
index,
106+
entry_mode,
107+
id,
108+
..
109+
}
110+
| ChangeRef::Modification {
111+
location,
112+
index,
113+
entry_mode,
114+
id,
115+
..
116+
}
117+
| ChangeRef::Rewrite {
118+
location,
119+
index,
120+
entry_mode,
121+
id,
122+
..
123+
}
124+
| ChangeRef::Unmerged {
125+
location,
126+
index,
127+
entry_mode,
128+
id,
129+
..
130+
} => (location.as_ref(), *index, *entry_mode, id),
131+
}
132+
}
133+
}
134+
135+
impl rewrites::tracker::Change for ChangeRef<'_, '_> {
136+
fn id(&self) -> &gix_hash::oid {
137+
match self {
138+
ChangeRef::Addition { id, .. } | ChangeRef::Deletion { id, .. } | ChangeRef::Modification { id, .. } => {
139+
id.as_ref()
140+
}
141+
ChangeRef::Rewrite { .. } | ChangeRef::Unmerged { .. } => {
142+
unreachable!("BUG")
143+
}
144+
}
145+
}
146+
147+
fn relation(&self) -> Option<Relation> {
148+
None
149+
}
150+
151+
fn kind(&self) -> ChangeKind {
152+
match self {
153+
ChangeRef::Addition { .. } => ChangeKind::Addition,
154+
ChangeRef::Deletion { .. } => ChangeKind::Deletion,
155+
ChangeRef::Modification { .. } => ChangeKind::Modification,
156+
ChangeRef::Rewrite { .. } => {
157+
unreachable!("BUG: rewrites can't be determined ahead of time")
158+
}
159+
ChangeRef::Unmerged { .. } => {
160+
unreachable!("BUG: unmerged don't participate in rename tracking")
161+
}
162+
}
163+
}
164+
165+
fn entry_mode(&self) -> tree::EntryMode {
166+
match self {
167+
ChangeRef::Addition { entry_mode, .. }
168+
| ChangeRef::Deletion { entry_mode, .. }
169+
| ChangeRef::Modification { entry_mode, .. }
170+
| ChangeRef::Rewrite { entry_mode, .. }
171+
| ChangeRef::Unmerged { entry_mode, .. } => {
172+
entry_mode
173+
.to_tree_entry_mode()
174+
// Default is for the impossible case - just don't let it participate in rename tracking.
175+
.unwrap_or(tree::EntryKind::Tree.into())
176+
}
177+
}
178+
}
179+
180+
fn id_and_entry_mode(&self) -> (&gix_hash::oid, tree::EntryMode) {
181+
match self {
182+
ChangeRef::Addition { id, entry_mode, .. }
183+
| ChangeRef::Deletion { id, entry_mode, .. }
184+
| ChangeRef::Modification { id, entry_mode, .. }
185+
| ChangeRef::Rewrite { id, entry_mode, .. }
186+
| ChangeRef::Unmerged { id, entry_mode, .. } => {
187+
(
188+
id,
189+
entry_mode
190+
.to_tree_entry_mode()
191+
// Default is for the impossible case - just don't let it participate in rename tracking.
192+
.unwrap_or(tree::EntryKind::Tree.into()),
193+
)
194+
}
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)