From c23a457e72abe608715ac76f076f47dc42af07a5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 20:31:44 +0200 Subject: Merging upstream version 1.74.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/gix/src/object/blob.rs | 1 + vendor/gix/src/object/commit.rs | 16 +++- vendor/gix/src/object/errors.rs | 10 ++- vendor/gix/src/object/tree/diff/for_each.rs | 5 +- vendor/gix/src/object/tree/diff/mod.rs | 4 + vendor/gix/src/object/tree/diff/rewrites.rs | 2 +- vendor/gix/src/object/tree/iter.rs | 19 ++++- vendor/gix/src/object/tree/mod.rs | 111 +++++++++++++++++++++++----- 8 files changed, 140 insertions(+), 28 deletions(-) (limited to 'vendor/gix/src/object') diff --git a/vendor/gix/src/object/blob.rs b/vendor/gix/src/object/blob.rs index f35605422..00b3519ed 100644 --- a/vendor/gix/src/object/blob.rs +++ b/vendor/gix/src/object/blob.rs @@ -1,4 +1,5 @@ /// +#[cfg(feature = "blob-diff")] pub mod diff { use std::ops::Range; diff --git a/vendor/gix/src/object/commit.rs b/vendor/gix/src/object/commit.rs index 5a9dfd4f3..1fb9eff67 100644 --- a/vendor/gix/src/object/commit.rs +++ b/vendor/gix/src/object/commit.rs @@ -1,4 +1,4 @@ -use crate::{bstr, bstr::BStr, revision, Commit, ObjectDetached, Tree}; +use crate::{bstr, bstr::BStr, Commit, ObjectDetached, Tree}; mod error { use crate::object; @@ -65,7 +65,7 @@ impl<'repo> Commit<'repo> { /// Decode the commit and obtain the time at which the commit was created. /// /// For the time at which it was authored, refer to `.decode()?.author.time`. - pub fn time(&self) -> Result { + pub fn time(&self) -> Result { Ok(self.committer()?.time) } @@ -131,12 +131,13 @@ impl<'repo> Commit<'repo> { } /// Obtain a platform for traversing ancestors of this commit. - pub fn ancestors(&self) -> revision::walk::Platform<'repo> { + pub fn ancestors(&self) -> crate::revision::walk::Platform<'repo> { self.id().ancestors() } /// Create a platform to further configure a `git describe` operation to find a name for this commit by looking /// at the closest annotated tags (by default) in its past. + #[cfg(feature = "revision")] pub fn describe(&self) -> crate::commit::describe::Platform<'repo> { crate::commit::describe::Platform { id: self.id, @@ -147,6 +148,15 @@ impl<'repo> Commit<'repo> { max_candidates: 10, } } + + /// Extracts the PGP signature and the data that was used to create the signature, or `None` if it wasn't signed. + // TODO: make it possible to verify the signature, probably by wrapping `SignedData`. It's quite some work to do it properly. + pub fn signature( + &self, + ) -> Result, gix_object::commit::SignedData<'_>)>, gix_object::decode::Error> + { + gix_object::CommitRefIter::signature(&self.data) + } } impl<'r> std::fmt::Debug for Commit<'r> { diff --git a/vendor/gix/src/object/errors.rs b/vendor/gix/src/object/errors.rs index eb7733473..92789b6cb 100644 --- a/vendor/gix/src/object/errors.rs +++ b/vendor/gix/src/object/errors.rs @@ -18,17 +18,21 @@ pub mod conversion { /// pub mod find { /// Indicate that an error occurred when trying to find an object. - pub type Error = gix_odb::store::find::Error; + #[derive(Debug, thiserror::Error)] + #[error(transparent)] + pub struct Error(#[from] pub gix_odb::find::Error); /// pub mod existing { /// An object could not be found in the database, or an error occurred when trying to obtain it. - pub type Error = gix_odb::find::existing::Error; + pub type Error = gix_odb::find::existing::Error; } } /// pub mod write { /// An error to indicate writing to the loose object store failed. - pub type Error = gix_odb::store::write::Error; + #[derive(Debug, thiserror::Error)] + #[error(transparent)] + pub struct Error(#[from] pub gix_odb::find::Error); } 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, 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::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) -> Option> { + 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(&self, path: I, buf: &mut Vec) -> Result>, find::existing::Error> + where + I: IntoIterator, + P: PartialEq, + { + 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(mut self, path: I) -> Result>, find::existing::Error> + pub fn peel_to_entry(&mut self, path: I) -> Result>, find::existing::Error> where I: IntoIterator, P: PartialEq, @@ -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, + buf: &mut Vec, + ) -> Result>, 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, ) -> Result>, 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 { -- cgit v1.2.3