gix_protocol/handshake/
mod.rs

1use bstr::BString;
2
3///
4pub mod refs;
5
6/// A git reference, commonly referred to as 'ref', as returned by a git server before sending a pack.
7#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum Ref {
10    /// A ref pointing to a `tag` object, which in turns points to an `object`, usually a commit
11    Peeled {
12        /// The name at which the ref is located, like `refs/tags/1.0`.
13        full_ref_name: BString,
14        /// The hash of the tag the ref points to.
15        tag: gix_hash::ObjectId,
16        /// The hash of the object the `tag` points to.
17        object: gix_hash::ObjectId,
18    },
19    /// A ref pointing to a commit object
20    Direct {
21        /// The name at which the ref is located, like `refs/heads/main` or `refs/tags/v1.0` for lightweight tags.
22        full_ref_name: BString,
23        /// The hash of the object the ref points to.
24        object: gix_hash::ObjectId,
25    },
26    /// A symbolic ref pointing to `target` ref, which in turn, ultimately after possibly following `tag`, points to an `object`
27    Symbolic {
28        /// The name at which the symbolic ref is located, like `HEAD`.
29        full_ref_name: BString,
30        /// The path of the ref the symbolic ref points to, like `refs/heads/main`.
31        ///
32        /// See issue [#205] for details
33        ///
34        /// [#205]: https://github.com/GitoxideLabs/gitoxide/issues/205
35        target: BString,
36        /// The hash of the annotated tag the ref points to, if present.
37        ///
38        /// Note that this field is also `None` if `full_ref_name` is a lightweight tag.
39        tag: Option<gix_hash::ObjectId>,
40        /// The hash of the object the `target` ref ultimately points to.
41        object: gix_hash::ObjectId,
42    },
43    /// A ref is unborn on the remote and just points to the initial, unborn branch, as is the case in a newly initialized repository
44    /// or dangling symbolic refs.
45    Unborn {
46        /// The name at which the ref is located, typically `HEAD`.
47        full_ref_name: BString,
48        /// The path of the ref the symbolic ref points to, like `refs/heads/main`, even though the `target` does not yet exist.
49        target: BString,
50    },
51}
52
53#[cfg(feature = "handshake")]
54pub(crate) mod hero {
55    use crate::handshake::Ref;
56
57    /// The result of the [`handshake()`](crate::handshake()) function.
58    #[derive(Default, Debug, Clone)]
59    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
60    pub struct Handshake {
61        /// The protocol version the server responded with. It might have downgraded the desired version.
62        pub server_protocol_version: gix_transport::Protocol,
63        /// The references reported as part of the `Protocol::V1` handshake, or `None` otherwise as V2 requires a separate request.
64        pub refs: Option<Vec<Ref>>,
65        /// Shallow updates as part of the `Protocol::V1`, to shallow a particular object.
66        /// Note that unshallowing isn't supported here.
67        pub v1_shallow_updates: Option<Vec<crate::fetch::response::ShallowUpdate>>,
68        /// The server capabilities.
69        pub capabilities: gix_transport::client::Capabilities,
70    }
71
72    #[cfg(feature = "fetch")]
73    mod fetch {
74        #[cfg(feature = "async-client")]
75        use crate::transport::client::async_io::Transport;
76        #[cfg(feature = "blocking-client")]
77        use crate::transport::client::blocking_io::Transport;
78        use crate::Handshake;
79        use gix_features::progress::Progress;
80        use std::borrow::Cow;
81
82        impl Handshake {
83            /// Obtain a [refmap](crate::fetch::RefMap) either from this instance, taking it out in the process, if the handshake was
84            /// created from a V1 connection, or use `transport` to fetch the refmap as a separate command invocation.
85            #[allow(clippy::result_large_err)]
86            #[maybe_async::maybe_async]
87            pub async fn fetch_or_extract_refmap<T>(
88                &mut self,
89                mut progress: impl Progress,
90                transport: &mut T,
91                user_agent: (&'static str, Option<Cow<'static, str>>),
92                trace_packetlines: bool,
93                prefix_from_spec_as_filter_on_remote: bool,
94                refmap_context: crate::fetch::refmap::init::Context,
95            ) -> Result<crate::fetch::RefMap, crate::fetch::refmap::init::Error>
96            where
97                T: Transport,
98            {
99                Ok(match self.refs.take() {
100                    Some(refs) => crate::fetch::RefMap::from_refs(refs, &self.capabilities, refmap_context)?,
101                    None => {
102                        crate::fetch::RefMap::fetch(
103                            &mut progress,
104                            &self.capabilities,
105                            transport,
106                            user_agent,
107                            trace_packetlines,
108                            prefix_from_spec_as_filter_on_remote,
109                            refmap_context,
110                        )
111                        .await?
112                    }
113                })
114            }
115        }
116    }
117}
118
119#[cfg(feature = "handshake")]
120mod error {
121    use bstr::BString;
122    use gix_transport::client;
123
124    use crate::{credentials, handshake::refs};
125
126    /// The error returned by [`handshake()`][crate::handshake()].
127    #[derive(Debug, thiserror::Error)]
128    #[allow(missing_docs)]
129    pub enum Error {
130        #[error("Failed to obtain credentials")]
131        Credentials(#[from] credentials::protocol::Error),
132        #[error("No credentials were returned at all as if the credential helper isn't functioning unknowingly")]
133        EmptyCredentials,
134        #[error("Credentials provided for \"{url}\" were not accepted by the remote")]
135        InvalidCredentials { url: BString, source: std::io::Error },
136        #[error(transparent)]
137        Transport(#[from] client::Error),
138        #[error("The transport didn't accept the advertised server version {actual_version:?} and closed the connection client side")]
139        TransportProtocolPolicyViolation { actual_version: gix_transport::Protocol },
140        #[error(transparent)]
141        ParseRefs(#[from] refs::parse::Error),
142    }
143
144    impl gix_transport::IsSpuriousError for Error {
145        fn is_spurious(&self) -> bool {
146            match self {
147                Error::Transport(err) => err.is_spurious(),
148                _ => false,
149            }
150        }
151    }
152}
153#[cfg(feature = "handshake")]
154pub use error::Error;
155
156#[cfg(any(feature = "blocking-client", feature = "async-client"))]
157#[cfg(feature = "handshake")]
158pub(crate) mod function;