Skip to content

Commit

Permalink
feat: support workspace filters when fetching them from the object da…
Browse files Browse the repository at this point in the history
…tabase
  • Loading branch information
Byron committed Nov 15, 2023
1 parent 4d06306 commit 44f4ac6
Show file tree
Hide file tree
Showing 8 changed files with 326 additions and 7 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.

3 changes: 2 additions & 1 deletion gix-diff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ autotests = false
[features]
default = ["blob"]
## Enable diffing of blobs using imara-diff, which also allows for a generic rewrite tracking implementation.
blob = ["dep:imara-diff"]
blob = ["dep:imara-diff", "dep:gix-filter"]
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"]
## Make it possible to compile to the `wasm32-unknown-unknown` target.
Expand All @@ -25,6 +25,7 @@ doctest = false
[dependencies]
gix-hash = { version = "^0.13.1", path = "../gix-hash" }
gix-object = { version = "^0.38.0", path = "../gix-object" }
gix-filter = { version = "^0.6.0", path = "../gix-filter", optional = true }

thiserror = "1.0.32"
imara-diff = { version = "0.1.3", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion gix-diff/src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//!
//!
/// Information about the diff performed to detect similarity.
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DiffLineStats {
/// The amount of lines to remove from the source to get to the destination.
pub removals: u32,
Expand Down
39 changes: 34 additions & 5 deletions gix-diff/src/rewrites/tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,24 @@ pub enum ChangeKind {
Addition,
}

/// A trait to help access the worktree version of a file, if present.
pub trait WorktreeBlob {
/// Write the contents of the file, executable or link (i.e. the link target itself) at
/// `rela_path` to the initially empty `buf`.
/// `is_source` is `true` if this is the blob for the source of a rewrite (copy or rename). Otherwise it is the
/// destination.
///
/// Return `std::io::ErrorKind::NotFound` if the file is not available in the working tree, which will make the
/// implementation to extract it from the object database instead and convert it to its working-tree counterpart.
fn worktree_blob(&mut self, rela_path: &BStr, buf: &mut Vec<u8>, is_source: bool) -> std::io::Result<()>;
}

/// A trait providing all functionality to abstract over the concept of a change, as seen by the [`Tracker`].
pub trait Change: Clone {
/// Return the hash of this change for identification.
///
/// Note that this is the id of the object as stored in `git`, i.e. it must have gone through workspace
/// conversions.
fn id(&self) -> &gix_hash::oid;
/// Return the kind of this change.
fn kind(&self) -> ChangeKind;
Expand Down Expand Up @@ -71,6 +86,7 @@ pub mod visit {
use gix_object::tree::EntryMode;

/// The source of a rewrite, rename or copy.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Source<'a> {
/// The kind of entry.
pub entry_mode: EntryMode,
Expand All @@ -85,7 +101,7 @@ pub mod visit {
}

/// Further identify the kind of [Source].
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum SourceKind {
/// This is the source of an entry that was renamed, as `source` was renamed to `destination`.
Rename,
Expand All @@ -94,7 +110,8 @@ pub mod visit {
}

/// A change along with a location.
pub struct Destination<'a, T> {
#[derive(Clone)]
pub struct Destination<'a, T: Clone> {
/// The change at the given `location`.
pub change: T,
/// The repository-relative location of this destination.
Expand Down Expand Up @@ -162,10 +179,14 @@ impl<T: Change> Tracker<T> {
///
/// `cb(destination, source)` is called for each item, either with `Some(source)` if it's
/// the destination of a copy or rename, or with `None` for source if no relation to other
/// items in the tracked set exist.
/// items in the tracked set exist, which is like saying 'no rename or rewrite or copy' happened.
///
/// `objects` is used to access blob data for similarity checks if required and is taken directly from the object database.
/// Worktree filters and diff conversions will be applied afterwards automatically.
/// Worktree filters and text conversions will be applied afterwards automatically.
///
/// Use `worktree_filter` to obtain working-tree versions of files present on disk before diffing to see if rewrites happened,
/// with text-conversions being applied afterwards.
/// If it indicates no such file exists, it's read from objects instead.
///
/// `push_source_tree(push_fn: push(change, location))` is a function that is called when the entire tree of the source
/// should be added as modifications by calling `push` repeatedly to use for perfect copy tracking. Note that `push`
Expand All @@ -174,6 +195,7 @@ impl<T: Change> Tracker<T> {
&mut self,
mut cb: impl FnMut(visit::Destination<'_, T>, Option<visit::Source<'_>>) -> crate::tree::visit::Action,
objects: &dyn gix_object::Find,
worktree_filter: &mut gix_filter::Pipeline,
mut push_source_tree: PushSourceTreeFn,
) -> Result<Outcome, emit::Error>
where
Expand Down Expand Up @@ -417,7 +439,7 @@ fn find_match<'a, T: Change>(
return Ok(Some(src));
}
} else {
let new = objects.find_blob(item_id, buf1)?;
let mut new = None;
let (percentage, algo) = percentage.expect("it's set to something below 1.0 and we assured this");
debug_assert_eq!(
item.change.entry_mode().kind(),
Expand All @@ -429,6 +451,13 @@ fn find_match<'a, T: Change>(
.enumerate()
.filter(|(src_idx, src)| *src_idx != item_idx && src.is_source_for_destination_of(kind, item_mode))
{
let new = match &new {
Some(new) => new,
None => {
new = objects.find_blob(item_id, buf1)?.into();
new.as_ref().expect("just set")
}
};
let old = objects.find_blob(src.change.id(), buf2)?;
// TODO: make sure we get attribute handling/worktree conversion and binary skips and filters right here.
let tokens = crate::blob::intern::InternedInput::new(
Expand Down
1 change: 1 addition & 0 deletions gix-diff/tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ gix-diff = { path = ".." }
gix-hash = { path = "../../gix-hash" }
gix-object = { path = "../../gix-object" }
gix-odb = { path = "../../gix-odb" }
gix-filter = { path = "../../gix-filter" }
gix-traverse = { path = "../../gix-traverse" }
gix-testtools = { path = "../../tests/tools" }
1 change: 1 addition & 0 deletions gix-diff/tests/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ fn hex_to_id(hex: &str) -> gix_hash::ObjectId {
}

mod blob;
mod rewrites;
mod tree;
56 changes: 56 additions & 0 deletions gix-diff/tests/rewrites/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use gix_diff::rewrites::tracker::ChangeKind;
use gix_hash::{oid, ObjectId};
use gix_object::tree::{EntryKind, EntryMode};

mod tracker;

#[derive(Clone)]
pub struct Change {
id: ObjectId,
kind: ChangeKind,
mode: EntryMode,
}

impl gix_diff::rewrites::tracker::Change for Change {
fn id(&self) -> &oid {
&self.id
}

fn kind(&self) -> ChangeKind {
self.kind
}

fn entry_mode(&self) -> EntryMode {
self.mode
}

fn id_and_entry_mode(&self) -> (&oid, EntryMode) {
(&self.id, self.mode)
}
}

const NULL_ID: gix_hash::ObjectId = gix_hash::Kind::Sha1.null();

impl Change {
fn modification() -> Self {
Change {
id: NULL_ID,
kind: ChangeKind::Modification,
mode: EntryKind::Blob.into(),
}
}
fn deletion() -> Self {
Change {
id: NULL_ID,
kind: ChangeKind::Deletion,
mode: EntryKind::Blob.into(),
}
}
fn addition() -> Self {
Change {
id: NULL_ID,
kind: ChangeKind::Addition,
mode: EntryKind::Blob.into(),
}
}
}
Loading

0 comments on commit 44f4ac6

Please sign in to comment.