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/repository/object.rs | 105 +++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 18 deletions(-) (limited to 'vendor/gix/src/repository/object.rs') diff --git a/vendor/gix/src/repository/object.rs b/vendor/gix/src/repository/object.rs index 787dcda4e..c156971d0 100644 --- a/vendor/gix/src/repository/object.rs +++ b/vendor/gix/src/repository/object.rs @@ -2,11 +2,13 @@ use std::{convert::TryInto, ops::DerefMut}; use gix_hash::ObjectId; -use gix_odb::{Find, FindExt, Write}; +use gix_macros::momo; +use gix_odb::{Find, FindExt, Header, HeaderExt, Write}; use gix_ref::{ transaction::{LogChange, PreviousValue, RefLog}, FullName, }; +use smallvec::SmallVec; use crate::{commit, ext::ObjectIdExt, object, tag, Id, Object, Reference, Tree}; @@ -21,6 +23,7 @@ impl crate::Repository { /// /// In order to get the kind of the object, is must be fully decoded from storage if it is packed with deltas. /// Loose object could be partially decoded, even though that's not implemented. + #[momo] pub fn find_object(&self, id: impl Into) -> Result, object::find::existing::Error> { let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { @@ -32,11 +35,46 @@ impl crate::Repository { }); } let mut buf = self.free_buf(); - let kind = self.objects.find(id, &mut buf)?.kind; + let kind = self.objects.find(&id, &mut buf)?.kind; Ok(Object::from_data(id, kind, buf, self)) } + /// Obtain information about an object without fully decoding it, or fail if the object doesn't exist. + /// + /// Note that despite being cheaper than [`Self::find_object()`], there is still some effort traversing delta-chains. + #[doc(alias = "read_header", alias = "git2")] + #[momo] + pub fn find_header(&self, id: impl Into) -> Result { + let id = id.into(); + if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { + return Ok(gix_odb::find::Header::Loose { + kind: gix_object::Kind::Tree, + size: 0, + }); + } + self.objects.header(id) + } + + /// Obtain information about an object without fully decoding it, or `None` if the object doesn't exist. + /// + /// Note that despite being cheaper than [`Self::try_find_object()`], there is still some effort traversing delta-chains. + #[momo] + pub fn try_find_header( + &self, + id: impl Into, + ) -> Result, object::find::Error> { + let id = id.into(); + if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { + return Ok(Some(gix_odb::find::Header::Loose { + kind: gix_object::Kind::Tree, + size: 0, + })); + } + self.objects.try_header(&id).map_err(Into::into) + } + /// Try to find the object with `id` or return `None` if it wasn't found. + #[momo] pub fn try_find_object(&self, id: impl Into) -> Result>, object::find::Error> { let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { @@ -49,7 +87,7 @@ impl crate::Repository { } let mut buf = self.free_buf(); - match self.objects.try_find(id, &mut buf)? { + match self.objects.try_find(&id, &mut buf)? { Some(obj) => { let kind = obj.kind; Ok(Some(Object::from_data(id, kind, buf, self))) @@ -76,15 +114,19 @@ impl crate::Repository { /// we avoid writing duplicate objects using slow disks that will eventually have to be garbage collected. pub fn write_object(&self, object: impl gix_object::WriteTo) -> Result, object::write::Error> { let mut buf = self.shared_empty_buf(); - object.write_to(buf.deref_mut())?; + object.write_to(buf.deref_mut()).expect("write to memory works"); - let oid = gix_object::compute_hash(self.object_hash(), object.kind(), &buf); - if self.objects.contains(oid) { + self.write_object_inner(&buf, object.kind()) + } + + fn write_object_inner(&self, buf: &[u8], kind: gix_object::Kind) -> Result, object::write::Error> { + let oid = gix_object::compute_hash(self.object_hash(), kind, buf); + if self.objects.contains(&oid) { return Ok(oid.attach(self)); } self.objects - .write_buf(object.kind(), &buf) + .write_buf(kind, buf) .map(|oid| oid.attach(self)) .map_err(Into::into) } @@ -93,14 +135,16 @@ impl crate::Repository { /// /// We avoid writing duplicate objects to slow disks that will eventually have to be garbage collected by /// pre-hashing the data, and checking if the object is already present. + #[momo] pub fn write_blob(&self, bytes: impl AsRef<[u8]>) -> Result, object::write::Error> { let bytes = bytes.as_ref(); let oid = gix_object::compute_hash(self.object_hash(), gix_object::Kind::Blob, bytes); - if self.objects.contains(oid) { + if self.objects.contains(&oid) { return Ok(oid.attach(self)); } self.objects .write_buf(gix_object::Kind::Blob, bytes) + .map_err(Into::into) .map(|oid| oid.attach(self)) } @@ -115,14 +159,20 @@ impl crate::Repository { mut bytes: impl std::io::Read + std::io::Seek, ) -> Result, object::write::Error> { let mut buf = self.shared_empty_buf(); - std::io::copy(&mut bytes, buf.deref_mut())?; - let oid = gix_object::compute_hash(self.object_hash(), gix_object::Kind::Blob, &buf); - if self.objects.contains(oid) { + std::io::copy(&mut bytes, buf.deref_mut()).expect("write to memory works"); + + self.write_blob_stream_inner(&buf) + } + + fn write_blob_stream_inner(&self, buf: &[u8]) -> Result, object::write::Error> { + let oid = gix_object::compute_hash(self.object_hash(), gix_object::Kind::Blob, buf); + if self.objects.contains(&oid) { return Ok(oid.attach(self)); } self.objects - .write_buf(gix_object::Kind::Blob, &buf) + .write_buf(gix_object::Kind::Blob, buf) + .map_err(Into::into) .map(|oid| oid.attach(self)) } @@ -131,6 +181,7 @@ impl crate::Repository { /// /// It will be created with `constraint` which is most commonly to [only create it][PreviousValue::MustNotExist] /// or to [force overwriting a possibly existing tag](PreviousValue::Any). + #[momo] pub fn tag( &self, name: impl AsRef, @@ -168,6 +219,25 @@ impl crate::Repository { Name: TryInto, commit::Error: From, { + self.commit_as_inner( + committer.into(), + author.into(), + reference.try_into()?, + message.as_ref(), + tree.into(), + parents.into_iter().map(Into::into).collect(), + ) + } + + fn commit_as_inner( + &self, + committer: gix_actor::SignatureRef<'_>, + author: gix_actor::SignatureRef<'_>, + reference: FullName, + message: &str, + tree: ObjectId, + parents: SmallVec<[gix_hash::ObjectId; 1]>, + ) -> Result, commit::Error> { use gix_ref::{ transaction::{Change, RefEdit}, Target, @@ -175,14 +245,13 @@ impl crate::Repository { // TODO: possibly use CommitRef to save a few allocations (but will have to allocate for object ids anyway. // This can be made vastly more efficient though if we wanted to, so we lie in the API - let reference = reference.try_into()?; let commit = gix_object::Commit { - message: message.as_ref().into(), - tree: tree.into(), - author: author.into().to_owned(), - committer: committer.into().to_owned(), + message: message.into(), + tree, + author: author.into(), + committer: committer.into(), encoding: None, - parents: parents.into_iter().map(|id| id.into()).collect(), + parents, extra_headers: Default::default(), }; -- cgit v1.2.3