summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/object/tree
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/object/tree')
-rw-r--r--vendor/gix/src/object/tree/diff/for_each.rs5
-rw-r--r--vendor/gix/src/object/tree/diff/mod.rs4
-rw-r--r--vendor/gix/src/object/tree/diff/rewrites.rs2
-rw-r--r--vendor/gix/src/object/tree/iter.rs19
-rw-r--r--vendor/gix/src/object/tree/mod.rs111
5 files changed, 119 insertions, 22 deletions
diff --git a/vendor/gix/src/object/tree/diff/for_each.rs b/vendor/gix/src/object/tree/diff/for_each.rs
index a72033182..3932f9027 100644
--- a/vendor/gix/src/object/tree/diff/for_each.rs
+++ b/vendor/gix/src/object/tree/diff/for_each.rs
@@ -75,8 +75,9 @@ impl<'a, 'old> Platform<'a, 'old> {
}
Err(gix_diff::tree::changes::Error::Cancelled) => delegate
.err
- .map(|err| Err(Error::ForEach(Box::new(err))))
- .unwrap_or(Err(Error::Diff(gix_diff::tree::changes::Error::Cancelled))),
+ .map_or(Err(Error::Diff(gix_diff::tree::changes::Error::Cancelled)), |err| {
+ Err(Error::ForEach(Box::new(err)))
+ }),
Err(err) => Err(err.into()),
}
}
diff --git a/vendor/gix/src/object/tree/diff/mod.rs b/vendor/gix/src/object/tree/diff/mod.rs
index 447eeaa84..5f7a041e4 100644
--- a/vendor/gix/src/object/tree/diff/mod.rs
+++ b/vendor/gix/src/object/tree/diff/mod.rs
@@ -34,6 +34,10 @@ impl<'repo> Tree<'repo> {
///
/// It's highly recommended to set an object cache to avoid extracting the same object multiple times.
/// By default, similar to `git diff`, rename tracking will be enabled if it is not configured.
+ ///
+ /// Note that if a clone with `--filter=blob=none` was created, rename tracking may fail as it might
+ /// try to access blobs to compute a similarity metric. Thus, it's more compatible to turn rewrite tracking off
+ /// using [`Platform::track_rewrites()`].
#[allow(clippy::result_large_err)]
pub fn changes<'a>(&'a self) -> Result<Platform<'a, 'repo>, rewrites::Error> {
Ok(Platform {
diff --git a/vendor/gix/src/object/tree/diff/rewrites.rs b/vendor/gix/src/object/tree/diff/rewrites.rs
index 1502048ec..e434726d9 100644
--- a/vendor/gix/src/object/tree/diff/rewrites.rs
+++ b/vendor/gix/src/object/tree/diff/rewrites.rs
@@ -80,7 +80,7 @@ impl Rewrites {
let key = "diff.renames";
let copies = match config
.boolean_by_key(key)
- .map(|value| Diff::RENAMES.try_into_renames(value, || config.string_by_key(key)))
+ .map(|value| Diff::RENAMES.try_into_renames(value))
.transpose()
.with_leniency(lenient)?
{
diff --git a/vendor/gix/src/object/tree/iter.rs b/vendor/gix/src/object/tree/iter.rs
index c841e2574..848d9eeab 100644
--- a/vendor/gix/src/object/tree/iter.rs
+++ b/vendor/gix/src/object/tree/iter.rs
@@ -25,10 +25,25 @@ impl<'repo, 'a> EntryRef<'repo, 'a> {
crate::Id::from_id(self.inner.oid, self.repo)
}
- /// Return the entries id, without repository connection.
- pub fn oid(&self) -> gix_hash::ObjectId {
+ /// Return the plain object id of this entry, without access to the repository.
+ pub fn oid(&self) -> &gix_hash::oid {
+ self.inner.oid
+ }
+
+ /// Return the object this entry points to.
+ pub fn object(&self) -> Result<crate::Object<'repo>, crate::object::find::existing::Error> {
+ self.id().object()
+ }
+
+ /// Return the plain object id of this entry, without access to the repository.
+ pub fn object_id(&self) -> gix_hash::ObjectId {
self.inner.oid.to_owned()
}
+
+ /// Detach the repository from this instance.
+ pub fn detach(&self) -> gix_object::tree::EntryRef<'a> {
+ self.inner
+ }
}
impl<'repo, 'a> std::fmt::Display for EntryRef<'repo, 'a> {
diff --git a/vendor/gix/src/object/tree/mod.rs b/vendor/gix/src/object/tree/mod.rs
index bbd392289..5bf59a25c 100644
--- a/vendor/gix/src/object/tree/mod.rs
+++ b/vendor/gix/src/object/tree/mod.rs
@@ -1,5 +1,8 @@
use gix_hash::ObjectId;
+use gix_macros::momo;
+pub use gix_object::tree::EntryMode;
use gix_object::{bstr::BStr, TreeRefIter};
+use gix_odb::FindExt;
use crate::{object::find, Id, Tree};
@@ -27,9 +30,20 @@ impl<'repo> Tree<'repo> {
gix_object::TreeRef::from_bytes(&self.data)
}
- // TODO: tests.
+ /// Find the entry named `name` by iteration, or return `None` if it wasn't found.
+ pub fn find_entry(&self, name: impl PartialEq<BStr>) -> Option<EntryRef<'repo, '_>> {
+ TreeRefIter::from_bytes(&self.data)
+ .filter_map(Result::ok)
+ .find(|entry| name.eq(entry.filename))
+ .map(|entry| EntryRef {
+ inner: entry,
+ repo: self.repo,
+ })
+ }
+
/// Follow a sequence of `path` components starting from this instance, and look them up one by one until the last component
/// is looked up and its tree entry is returned.
+ /// Use `buf` as temporary location for sub-trees to avoid allocating a temporary buffer for each lookup.
///
/// # Performance Notes
///
@@ -37,12 +51,51 @@ impl<'repo> Tree<'repo> {
/// to re-use a vector and use a binary search instead, which might be able to improve performance over all.
/// However, a benchmark should be created first to have some data and see which trade-off to choose here.
///
- /// # Why is this consuming?
+ pub fn lookup_entry<I, P>(&self, path: I, buf: &mut Vec<u8>) -> Result<Option<Entry<'repo>>, find::existing::Error>
+ where
+ I: IntoIterator<Item = P>,
+ P: PartialEq<BStr>,
+ {
+ let mut path = path.into_iter().peekable();
+ buf.clear();
+ buf.extend_from_slice(&self.data);
+ while let Some(component) = path.next() {
+ match TreeRefIter::from_bytes(buf)
+ .filter_map(Result::ok)
+ .find(|entry| component.eq(entry.filename))
+ {
+ Some(entry) => {
+ if path.peek().is_none() {
+ return Ok(Some(Entry {
+ inner: entry.into(),
+ repo: self.repo,
+ }));
+ } else {
+ let next_id = entry.oid.to_owned();
+ let obj = self.repo.objects.find(&next_id, buf)?;
+ if !obj.kind.is_tree() {
+ return Ok(None);
+ }
+ }
+ }
+ None => return Ok(None),
+ }
+ }
+ Ok(None)
+ }
+
+ /// Follow a sequence of `path` components starting from this instance, and look them up one by one until the last component
+ /// is looked up and its tree entry is returned, while changing this instance to point to the last seen tree.
+ /// Note that if the lookup fails, it may be impossible to continue making lookups through this tree.
+ /// It's useful to have this function to be able to reuse the internal buffer of the tree.
+ ///
+ /// # Performance Notes
+ ///
+ /// Searching tree entries is currently done in sequence, which allows to the search to be allocation free. It would be possible
+ /// to re-use a vector and use a binary search instead, which might be able to improve performance over all.
+ /// However, a benchmark should be created first to have some data and see which trade-off to choose here.
///
- /// The borrow checker shows pathological behaviour in loops that mutate a buffer, but also want to return from it.
- /// Workarounds include keeping an index and doing a separate access to the memory, which seems hard to do here without
- /// re-parsing the entries.
- pub fn lookup_entry<I, P>(mut self, path: I) -> Result<Option<Entry<'repo>>, find::existing::Error>
+ pub fn peel_to_entry<I, P>(&mut self, path: I) -> Result<Option<Entry<'repo>>, find::existing::Error>
where
I: IntoIterator<Item = P>,
P: PartialEq<BStr>,
@@ -61,12 +114,11 @@ impl<'repo> Tree<'repo> {
}));
} else {
let next_id = entry.oid.to_owned();
- let repo = self.repo;
- drop(self);
- self = match repo.find_object(next_id)?.try_into_tree() {
- Ok(tree) => tree,
- Err(_) => return Ok(None),
- };
+ let obj = self.repo.objects.find(&next_id, &mut self.data)?;
+ self.id = next_id;
+ if !obj.kind.is_tree() {
+ return Ok(None);
+ }
}
}
None => return Ok(None),
@@ -75,18 +127,42 @@ impl<'repo> Tree<'repo> {
Ok(None)
}
- /// Like [`lookup_entry()`][Self::lookup_entry()], but takes a `Path` directly via `relative_path`, a path relative to this tree.
+ /// Like [`Self::lookup_entry()`], but takes a `Path` directly via `relative_path`, a path relative to this tree.
///
/// # Note
///
/// If any path component contains illformed UTF-8 and thus can't be converted to bytes on platforms which can't do so natively,
/// the returned component will be empty which makes the lookup fail.
+ #[momo]
pub fn lookup_entry_by_path(
- self,
+ &self,
+ relative_path: impl AsRef<std::path::Path>,
+ buf: &mut Vec<u8>,
+ ) -> Result<Option<Entry<'repo>>, find::existing::Error> {
+ use crate::bstr::ByteSlice;
+ self.lookup_entry(
+ relative_path.as_ref().components().map(|c: std::path::Component<'_>| {
+ gix_path::os_str_into_bstr(c.as_os_str())
+ .unwrap_or_else(|_| "".into())
+ .as_bytes()
+ }),
+ buf,
+ )
+ }
+
+ /// Like [`Self::peel_to_entry()`], but takes a `Path` directly via `relative_path`, a path relative to this tree.
+ ///
+ /// # Note
+ ///
+ /// If any path component contains illformed UTF-8 and thus can't be converted to bytes on platforms which can't do so natively,
+ /// the returned component will be empty which makes the lookup fail.
+ #[momo]
+ pub fn peel_to_entry_by_path(
+ &mut self,
relative_path: impl AsRef<std::path::Path>,
) -> Result<Option<Entry<'repo>>, find::existing::Error> {
use crate::bstr::ByteSlice;
- self.lookup_entry(relative_path.as_ref().components().map(|c: std::path::Component<'_>| {
+ self.peel_to_entry(relative_path.as_ref().components().map(|c: std::path::Component<'_>| {
gix_path::os_str_into_bstr(c.as_os_str())
.unwrap_or_else(|_| "".into())
.as_bytes()
@@ -95,6 +171,7 @@ impl<'repo> Tree<'repo> {
}
///
+#[cfg(feature = "blob-diff")]
pub mod diff;
///
@@ -113,8 +190,8 @@ impl<'r> std::fmt::Debug for Tree<'r> {
/// An entry in a [`Tree`], similar to an entry in a directory.
#[derive(PartialEq, Debug, Clone)]
pub struct Entry<'repo> {
- inner: gix_object::tree::Entry,
- repo: &'repo crate::Repository,
+ pub(crate) inner: gix_object::tree::Entry,
+ pub(crate) repo: &'repo crate::Repository,
}
mod entry {