1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
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::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 {
#[error(transparent)]
FindExistingObject(#[from] object::find::existing::Error),
#[error(transparent)]
PeelReference(#[from] reference::peel::Error),
}
}
pub use error::Error;
///
#[allow(clippy::empty_docs)]
pub mod into_id {
use crate::object;
/// The error returned by [`Head::into_peeled_id()`](super::Head::into_peeled_id()).
#[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 },
#[error(transparent)]
ObjectKind(#[from] object::try_into::Error),
}
}
///
#[allow(clippy::empty_docs)]
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),
}
}
///
#[allow(clippy::empty_docs)]
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> {
/// 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<crate::Id<'repo>, 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<crate::Object<'repo>, 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<Option<crate::Id<'repo>>, Error> {
self.try_peel_to_id_in_place()
}
/// 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 `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<Option<crate::Id<'repo>>, Error> {
Ok(Some(match &mut self.kind {
Kind::Unborn(_name) => return Ok(None),
Kind::Detached {
peeled: Some(peeled), ..
} => (*peeled).attach(self.repo),
Kind::Detached { peeled: None, target } => {
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()),
}
}
}
Kind::Symbolic(r) => {
let mut nr = r.clone().attach(self.repo);
let peeled = nr.peel_to_id_in_place();
*r = nr.detach();
peeled?
}
}))
}
/// 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_object_in_place(&mut self) -> Result<crate::Object<'repo>, 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_object::Error::Peel(Error::FindExistingObject(err)))
}
/// 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<crate::Commit<'repo>, to_commit::Error> {
Ok(self.peel_to_object_in_place()?.try_into_commit()?)
}
}