Skip to content

Commit

Permalink
feat: add index diffing
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Dec 30, 2024
1 parent 4989cda commit 28a8e93
Show file tree
Hide file tree
Showing 11 changed files with 1,944 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions gix-diff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ rust-version = "1.65"
autotests = false

[features]
default = ["blob"]
## Enable diffing of blobs using imara-diff, which also allows for a generic rewrite tracking implementation.
default = ["blob", "index"]
## Enable diffing of blobs using imara-diff.
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"]
## Enable diffing of two indices, which also allows for a generic rewrite tracking implementation.
index = ["dep:gix-index"]
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"]
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde", "gix-index?/serde"]
## Make it possible to compile to the `wasm32-unknown-unknown` target.
wasm = ["dep:getrandom"]

[lib]
doctest = false

[dependencies]
gix-index = { version = "^0.37.0", path = "../gix-index", optional = true }
gix-hash = { version = "^0.15.1", path = "../gix-hash" }
gix-object = { version = "^0.46.1", path = "../gix-object" }
gix-filter = { version = "^0.16.0", path = "../gix-filter", optional = true }
Expand Down
197 changes: 197 additions & 0 deletions gix-diff/src/index/change.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use crate::index::{Change, ChangeRef};
use crate::rewrites;
use crate::rewrites::tracker::ChangeKind;
use crate::tree::visit::Relation;
use bstr::BStr;
use gix_object::tree;
use std::borrow::Cow;

impl ChangeRef<'_, '_> {
/// Copy everything into an owned version of this instance.
pub fn into_owned(self) -> Change {
match self {
ChangeRef::Addition {
location,
index,
entry_mode,
id,
} => ChangeRef::Addition {
location: Cow::Owned(location.into_owned()),
index,
entry_mode,
id: Cow::Owned(id.into_owned()),
},
ChangeRef::Deletion {
location,
index,
entry_mode,
id,
} => ChangeRef::Deletion {
location: Cow::Owned(location.into_owned()),
index,
entry_mode,
id: Cow::Owned(id.into_owned()),
},
ChangeRef::Modification {
location,
previous_index,
previous_entry_mode,
previous_id,
index,
entry_mode,
id,
} => ChangeRef::Modification {
location: Cow::Owned(location.into_owned()),
previous_index,
previous_entry_mode,
previous_id: Cow::Owned(previous_id.into_owned()),
index,
entry_mode,
id: Cow::Owned(id.into_owned()),
},
ChangeRef::Rewrite {
source_location,
source_index,
source_entry_mode,
source_id,
location,
index,
entry_mode,
id,
copy,
} => ChangeRef::Rewrite {
source_location: Cow::Owned(source_location.into_owned()),
source_index,
source_entry_mode,
source_id: Cow::Owned(source_id.into_owned()),
location: Cow::Owned(location.into_owned()),
index,
entry_mode,
id: Cow::Owned(id.into_owned()),
copy,
},
ChangeRef::Unmerged {
location,
stage,
index,
entry_mode,
id,
} => ChangeRef::Unmerged {
location: Cow::Owned(location.into_owned()),
stage,
index,
entry_mode,
id: Cow::Owned(id.into_owned()),
},
}
}
}

impl ChangeRef<'_, '_> {
/// Return all shared fields among all variants: `(location, index, entry_mode, id)`
///
/// In case of rewrites, the fields return to the current change.
pub fn fields(&self) -> (&BStr, usize, gix_index::entry::Mode, &gix_hash::oid) {
match self {
ChangeRef::Addition {
location,
index,
entry_mode,
id,
..
}
| ChangeRef::Deletion {
location,
index,
entry_mode,
id,
..
}
| ChangeRef::Modification {
location,
index,
entry_mode,
id,
..
}
| ChangeRef::Rewrite {
location,
index,
entry_mode,
id,
..
}
| ChangeRef::Unmerged {
location,
index,
entry_mode,
id,
..
} => (location.as_ref(), *index, *entry_mode, id),
}
}
}

impl rewrites::tracker::Change for ChangeRef<'_, '_> {
fn id(&self) -> &gix_hash::oid {
match self {
ChangeRef::Addition { id, .. } | ChangeRef::Deletion { id, .. } | ChangeRef::Modification { id, .. } => {
id.as_ref()
}
ChangeRef::Rewrite { .. } | ChangeRef::Unmerged { .. } => {
unreachable!("BUG")
}
}
}

fn relation(&self) -> Option<Relation> {
None
}

fn kind(&self) -> ChangeKind {
match self {
ChangeRef::Addition { .. } => ChangeKind::Addition,
ChangeRef::Deletion { .. } => ChangeKind::Deletion,
ChangeRef::Modification { .. } => ChangeKind::Modification,
ChangeRef::Rewrite { .. } => {
unreachable!("BUG: rewrites can't be determined ahead of time")
}
ChangeRef::Unmerged { .. } => {
unreachable!("BUG: unmerged don't participate in rename tracking")
}
}
}

fn entry_mode(&self) -> tree::EntryMode {
match self {
ChangeRef::Addition { entry_mode, .. }
| ChangeRef::Deletion { entry_mode, .. }
| ChangeRef::Modification { entry_mode, .. }
| ChangeRef::Rewrite { entry_mode, .. }
| ChangeRef::Unmerged { entry_mode, .. } => {
entry_mode
.to_tree_entry_mode()
// Default is for the impossible case - just don't let it participate in rename tracking.
.unwrap_or(tree::EntryKind::Tree.into())
}
}
}

fn id_and_entry_mode(&self) -> (&gix_hash::oid, tree::EntryMode) {
match self {
ChangeRef::Addition { id, entry_mode, .. }
| ChangeRef::Deletion { id, entry_mode, .. }
| ChangeRef::Modification { id, entry_mode, .. }
| ChangeRef::Rewrite { id, entry_mode, .. }
| ChangeRef::Unmerged { id, entry_mode, .. } => {
(
id,
entry_mode
.to_tree_entry_mode()
// Default is for the impossible case - just don't let it participate in rename tracking.
.unwrap_or(tree::EntryKind::Tree.into()),
)
}
}
}
}
Loading

0 comments on commit 28a8e93

Please sign in to comment.