204 lines · 8.3 KB · Rust
RawDownload
use bstr::BString; ///pub mod refs; /// A git reference, commonly referred to as 'ref', as returned by a git server before sending a pack.#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]pub enum Ref {    /// A ref pointing to a `tag` object, which in turns points to an `object`, usually a commit    Peeled {        /// The name at which the ref is located, like `refs/tags/1.0`.        full_ref_name: BString,        /// The hash of the tag the ref points to.        tag: gix_hash::ObjectId,        /// The hash of the object the `tag` points to.        object: gix_hash::ObjectId,    },    /// A ref pointing to a commit object    Direct {        /// The name at which the ref is located, like `refs/heads/main` or `refs/tags/v1.0` for lightweight tags.        full_ref_name: BString,        /// The hash of the object the ref points to.        object: gix_hash::ObjectId,    },    /// A symbolic ref pointing to `target` ref, which in turn, ultimately after possibly following `tag`, points to an `object`    Symbolic {        /// The name at which the symbolic ref is located, like `HEAD`.        full_ref_name: BString,        /// The path of the ref the symbolic ref points to, like `refs/heads/main`.        ///        /// See issue [#205] for details        ///        /// [#205]: https://github.com/GitoxideLabs/gitoxide/issues/205        target: BString,        /// The hash of the annotated tag the ref points to, if present.        ///        /// Note that this field is also `None` if `full_ref_name` is a lightweight tag.        tag: Option<gix_hash::ObjectId>,        /// The hash of the object the `target` ref ultimately points to.        object: gix_hash::ObjectId,    },    /// A ref is unborn on the remote and just points to the initial, unborn branch, as is the case in a newly initialized repository    /// or dangling symbolic refs.    Unborn {        /// The name at which the ref is located, typically `HEAD`.        full_ref_name: BString,        /// The path of the ref the symbolic ref points to, like `refs/heads/main`, even though the `target` does not yet exist.        target: BString,    },} #[cfg(feature = "handshake")]pub(crate) mod hero {    use crate::handshake::Ref;     /// The result of the [`handshake()`](crate::handshake()) function.    #[derive(Default, Debug, Clone)]    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]    pub struct Handshake {        /// The protocol version the server responded with. It might have downgraded the desired version.        pub server_protocol_version: gix_transport::Protocol,        /// The references reported as part of the `Protocol::V1` handshake, or `None` otherwise as V2 requires a separate request.        pub refs: Option<Vec<Ref>>,        /// Shallow updates as part of the `Protocol::V1`, to shallow a particular object.        /// Note that unshallowing isn't supported here.        pub v1_shallow_updates: Option<Vec<crate::fetch::response::ShallowUpdate>>,        /// The server capabilities.        pub capabilities: gix_transport::client::Capabilities,    }     #[cfg(feature = "fetch")]    mod fetch {        use crate::{Handshake, command::Feature, fetch::RefMap, ls_refs::RefPrefixes};        use gix_features::progress::Progress;         /// Intermediate state while potentially fetching a refmap after the handshake.        pub enum ObtainRefMap<'a> {            /// We already got a refmap to use from the V1 handshake, which always sends them.            Existing(RefMap),            /// We need to invoke another `ls-refs` command to retrieve the refmap as part of the V2 protocol.            LsRefsCommand(crate::LsRefsCommand<'a>, crate::fetch::refmap::init::Context),        }         macro_rules! fetch {            ($name:ident, $bisync:path, $transport:path, $invoke:ident, $mode:literal) => {                /// Fetch the refmap, either by returning the existing one or invoking the `ls-refs` command.                #[$bisync]                pub async fn $name(                    self,                    mut progress: impl Progress,                    transport: &mut impl $transport,                    trace_packetlines: bool,                ) -> Result<RefMap, crate::fetch::refmap::init::Error> {                    let (cmd, cx) = match self {                        ObtainRefMap::Existing(map) => return Ok(map),                        ObtainRefMap::LsRefsCommand(cmd, cx) => (cmd, cx),                    };                     let _span = gix_trace::coarse!(                        "gix_protocol::handshake::ObtainRefMap::fetch()",                        mode = $mode                    );                    let capabilities = cmd.capabilities;                    let remote_refs = cmd                        .$invoke(transport, &mut progress, trace_packetlines)                        .await?;                    RefMap::from_refs(remote_refs, capabilities, cx)                }            };        }         impl ObtainRefMap<'_> {            #[cfg(feature = "async-client")]            fetch!(                fetch_async,                ::bisync::asynchronous::bisync,                crate::transport::client::async_io::Transport,                invoke_async,                "async"            );             #[cfg(feature = "blocking-client")]            fetch!(                fetch_blocking,                ::bisync::synchronous::bisync,                crate::transport::client::blocking_io::Transport,                invoke_blocking,                "blocking"            );        }         impl Handshake {            /// Prepare fetching a [refmap](RefMap) if not present in the handshake.            pub fn prepare_lsrefs_or_extract_refmap(                &mut self,                user_agent: Feature,                prefix_from_spec_as_filter_on_remote: bool,                refmap_context: crate::fetch::refmap::init::Context,            ) -> Result<ObtainRefMap<'_>, crate::fetch::refmap::init::Error> {                if let Some(refs) = self.refs.take() {                    return Ok(ObtainRefMap::Existing(RefMap::from_refs(                        refs,                        &self.capabilities,                        refmap_context,                    )?));                }                 let prefix_refs = prefix_from_spec_as_filter_on_remote.then(|| {                    let all_refspecs = refmap_context.aggregate_refspecs();                    RefPrefixes::from_refspecs(&all_refspecs)                });                Ok(ObtainRefMap::LsRefsCommand(                    crate::LsRefsCommand::new(prefix_refs, &self.capabilities, user_agent),                    refmap_context,                ))            }        }    }} #[cfg(feature = "handshake")]mod error {    use bstr::BString;    use gix_transport::client;     use crate::{credentials, handshake::refs};     /// The error returned by [`handshake()`][crate::handshake()].    #[derive(Debug, thiserror::Error)]    #[expect(missing_docs)]    pub enum Error {        #[error("Failed to obtain credentials")]        Credentials(#[from] credentials::protocol::Error),        #[error("No credentials were returned at all as if the credential helper isn't functioning unknowingly")]        EmptyCredentials,        #[error("Credentials provided for \"{url}\" were not accepted by the remote")]        InvalidCredentials { url: BString, source: std::io::Error },        #[error(transparent)]        Transport(#[from] client::Error),        #[error(            "The transport didn't accept the advertised server version {actual_version:?} and closed the connection client side"        )]        TransportProtocolPolicyViolation { actual_version: gix_transport::Protocol },        #[error(transparent)]        ParseRefs(#[from] refs::parse::Error),    }     impl gix_transport::IsSpuriousError for Error {        fn is_spurious(&self) -> bool {            match self {                Error::Transport(err) => err.is_spurious(),                _ => false,            }        }    }} #[cfg(feature = "handshake")]pub use error::Error; #[cfg(any(feature = "blocking-client", feature = "async-client"))]#[cfg(feature = "handshake")]pub(crate) mod function;