From 9918693037dce8aa4bb6f08741b6812923486c18 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:26:03 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/gix/src/head/peel.rs | 158 +++++++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 61 deletions(-) (limited to 'vendor/gix/src/head') diff --git a/vendor/gix/src/head/peel.rs b/vendor/gix/src/head/peel.rs index 88e23636f..4ee116ed0 100644 --- a/vendor/gix/src/head/peel.rs +++ b/vendor/gix/src/head/peel.rs @@ -1,12 +1,14 @@ use crate::{ ext::{ObjectIdExt, ReferenceExt}, + head::Kind, Head, }; mod error { use crate::{object, reference}; - /// The error returned by [`Head::peel_to_id_in_place()`][super::Head::peel_to_id_in_place()] and [`Head::into_fully_peeled_id()`][super::Head::into_fully_peeled_id()]. + /// The error returned by [`Head::peel_to_id_in_place()`](super::Head::try_peel_to_id_in_place()) + /// and [`Head::into_fully_peeled_id()`](super::Head::try_into_peeled_id()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { @@ -19,13 +21,11 @@ mod error { pub use error::Error; -use crate::head::Kind; - /// -pub mod to_commit { +pub mod into_id { use crate::object; - /// The error returned by [`Head::peel_to_commit_in_place()`][super::Head::peel_to_commit_in_place()]. + /// The error returned by [`Head::into_peeled_id()`](super::Head::into_peeled_id()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { @@ -38,86 +38,122 @@ pub mod to_commit { } } +/// +pub mod to_commit { + use crate::object; + + /// The error returned by [`Head::peel_to_commit_in_place()`](super::Head::peel_to_commit_in_place()). + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + PeelToObject(#[from] super::to_object::Error), + #[error(transparent)] + ObjectKind(#[from] object::try_into::Error), + } +} + +/// +pub mod to_object { + /// The error returned by [`Head::peel_to_object_in_place()`](super::Head::peel_to_object_in_place()). + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + Peel(#[from] super::Error), + #[error("Branch '{name}' does not have any commits")] + Unborn { name: gix_ref::FullName }, + } +} + impl<'repo> Head<'repo> { - // TODO: tests - /// Peel this instance to make obtaining its final target id possible, while returning an error on unborn heads. - pub fn peeled(mut self) -> Result { - self.peel_to_id_in_place().transpose()?; - Ok(self) + /// Peel this instance and consume it to make obtaining its final target id possible, while returning an error on unborn heads. + /// + /// The final target is obtained by following symbolic references and peeling tags to their final destination, which + /// typically is a commit, but can be any object. + pub fn into_peeled_id(mut self) -> Result, into_id::Error> { + self.try_peel_to_id_in_place()?; + self.id().ok_or_else(|| match self.kind { + Kind::Symbolic(gix_ref::Reference { name, .. }) | Kind::Unborn(name) => into_id::Error::Unborn { name }, + Kind::Detached { .. } => unreachable!("id can be returned after peeling"), + }) + } + + /// Peel this instance and consume it to make obtaining its final target object possible, while returning an error on unborn heads. + /// + /// The final target is obtained by following symbolic references and peeling tags to their final destination, which + /// typically is a commit, but can be any object as well. + pub fn into_peeled_object(mut self) -> Result, to_object::Error> { + self.peel_to_object_in_place() + } + + /// Consume this instance and transform it into the final object that it points to, or `Ok(None)` if the `HEAD` + /// reference is yet to be born. + /// + /// The final target is obtained by following symbolic references and peeling tags to their final destination, which + /// typically is a commit, but can be any object. + pub fn try_into_peeled_id(mut self) -> Result>, Error> { + self.try_peel_to_id_in_place() } - // TODO: tests - // TODO: Fix this! It's not consistently peeling tags. The whole peeling business should be reconsidered to do what people usually - // want which is to peel references, if present, and then peel objects with control over which object type to end at. - // Finding a good interface for that isn't easy as ideally, it's an iterator that shows the intermediate objects so the user - // can select which tag of a chain to choose. /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no /// more object to follow, and return that object id. /// - /// Returns `None` if the head is unborn. - pub fn peel_to_id_in_place(&mut self) -> Option, Error>> { - Some(match &mut self.kind { - Kind::Unborn(_name) => return None, + /// Returns `Ok(None)` if the head is unborn. + /// + /// The final target is obtained by following symbolic references and peeling tags to their final destination, which + /// typically is a commit, but can be any object. + pub fn try_peel_to_id_in_place(&mut self) -> Result>, Error> { + Ok(Some(match &mut self.kind { + Kind::Unborn(_name) => return Ok(None), Kind::Detached { peeled: Some(peeled), .. - } => Ok((*peeled).attach(self.repo)), + } => (*peeled).attach(self.repo), Kind::Detached { peeled: None, target } => { - match target - .attach(self.repo) - .object() - .map_err(Into::into) - .and_then(|obj| obj.peel_tags_to_end().map_err(Into::into)) - .map(|peeled| peeled.id) - { - Ok(peeled) => { - self.kind = Kind::Detached { - peeled: Some(peeled), - target: *target, - }; - Ok(peeled.attach(self.repo)) + let id = target.attach(self.repo); + if id.header()?.kind() == gix_object::Kind::Commit { + id + } else { + match id.object()?.peel_tags_to_end() { + Ok(obj) => { + self.kind = Kind::Detached { + peeled: Some(obj.id), + target: *target, + }; + obj.id() + } + Err(err) => return Err(err.into()), } - Err(err) => Err(err), } } Kind::Symbolic(r) => { let mut nr = r.clone().attach(self.repo); - let peeled = nr.peel_to_id_in_place().map_err(Into::into); + let peeled = nr.peel_to_id_in_place(); *r = nr.detach(); - peeled + peeled? } - }) + })) } - // TODO: tests - // TODO: something similar in `crate::Reference` /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no /// more object to follow, transform the id into a commit if possible and return that. /// /// Returns an error if the head is unborn or if it doesn't point to a commit. - pub fn peel_to_commit_in_place(&mut self) -> Result, to_commit::Error> { - let id = self.peel_to_id_in_place().ok_or_else(|| to_commit::Error::Unborn { - name: self.referent_name().expect("unborn").to_owned(), - })??; + pub fn peel_to_object_in_place(&mut self) -> Result, to_object::Error> { + let id = self + .try_peel_to_id_in_place()? + .ok_or_else(|| to_object::Error::Unborn { + name: self.referent_name().expect("unborn").to_owned(), + })?; id.object() - .map_err(|err| to_commit::Error::Peel(Error::FindExistingObject(err))) - .and_then(|object| object.try_into_commit().map_err(Into::into)) + .map_err(|err| to_object::Error::Peel(Error::FindExistingObject(err))) } - /// Consume this instance and transform it into the final object that it points to, or `None` if the `HEAD` - /// reference is yet to be born. - pub fn into_fully_peeled_id(self) -> Option, Error>> { - Some(match self.kind { - Kind::Unborn(_name) => return None, - Kind::Detached { - peeled: Some(peeled), .. - } => Ok(peeled.attach(self.repo)), - Kind::Detached { peeled: None, target } => target - .attach(self.repo) - .object() - .map_err(Into::into) - .and_then(|obj| obj.peel_tags_to_end().map_err(Into::into)) - .map(|obj| obj.id.attach(self.repo)), - Kind::Symbolic(r) => r.attach(self.repo).peel_to_id_in_place().map_err(Into::into), - }) + /// Follow the symbolic reference of this head until its target object and peel it by following tag objects until there is no + /// more object to follow, transform the id into a commit if possible and return that. + /// + /// Returns an error if the head is unborn or if it doesn't point to a commit. + pub fn peel_to_commit_in_place(&mut self) -> Result, to_commit::Error> { + Ok(self.peel_to_object_in_place()?.try_into_commit()?) } } -- cgit v1.2.3