gix_protocol/fetch/
types.rs

1use std::path::PathBuf;
2
3use crate::fetch::response::{Acknowledgement, ShallowUpdate, WantedRef};
4
5/// Options for use in [`fetch()`](`crate::fetch()`)
6#[derive(Debug, Clone)]
7pub struct Options<'a> {
8    /// The path to the file containing the shallow commit boundary.
9    ///
10    /// When needed, it will be locked in preparation for being modified.
11    pub shallow_file: PathBuf,
12    /// How to deal with shallow repositories. It does affect how negotiations are performed.
13    pub shallow: &'a Shallow,
14    /// Describe how to handle tags when fetching.
15    pub tags: Tags,
16    /// If `true`, if we fetch from a remote that only offers shallow clones, the operation will fail with an error
17    /// instead of writing the shallow boundary to the shallow file.
18    pub reject_shallow_remote: bool,
19}
20
21/// For use in [`RefMap::new()`] and [`fetch`](crate::fetch()).
22#[cfg(feature = "handshake")]
23pub struct Context<'a, T> {
24    /// The outcome of the handshake performed with the remote.
25    ///
26    /// Note that it's mutable as depending on the protocol, it may contain refs that have been sent unconditionally.
27    pub handshake: &'a mut crate::handshake::Outcome,
28    /// The transport to use when making an `ls-refs` or `fetch` call.
29    ///
30    /// This is always done if the underlying protocol is V2, which is implied by the absence of refs in the `handshake` outcome.
31    pub transport: &'a mut T,
32    /// How to self-identify during the `ls-refs` call in [`RefMap::new()`] or the `fetch` call in [`fetch()`](crate::fetch()).
33    ///
34    /// This could be read from the `gitoxide.userAgent` configuration variable.
35    pub user_agent: (&'static str, Option<std::borrow::Cow<'static, str>>),
36    /// If `true`, output all packetlines using the the `gix-trace` machinery.
37    pub trace_packetlines: bool,
38}
39
40#[cfg(feature = "fetch")]
41mod with_fetch {
42    use crate::{
43        fetch,
44        fetch::{negotiate, refmap},
45    };
46
47    /// For use in [`fetch`](crate::fetch()).
48    pub struct NegotiateContext<'a, 'b, 'c, Objects, Alternates, AlternatesOut, AlternatesErr, Find>
49    where
50        Objects: gix_object::Find + gix_object::FindHeader + gix_object::Exists,
51        Alternates: FnOnce() -> Result<AlternatesOut, AlternatesErr>,
52        AlternatesErr: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
53        AlternatesOut: Iterator<Item = (gix_ref::file::Store, Find)>,
54        Find: gix_object::Find,
55    {
56        /// Access to the object database.
57        /// *Note* that the `exists()` calls must not trigger a refresh of the ODB packs as plenty of them might fail, i.e. find on object.
58        pub objects: &'a Objects,
59        /// Access to the git references database.
60        pub refs: &'a gix_ref::file::Store,
61        /// A function that returns an iterator over `(refs, objects)` for each alternate repository, to assure all known objects are added also according to their tips.
62        pub alternates: Alternates,
63        /// The implementation that performs the negotiation later, i.e. prepare wants and haves.
64        pub negotiator: &'a mut dyn gix_negotiate::Negotiator,
65        /// The commit-graph for use by the `negotiator` - we populate it with tips to initialize the graph traversal.
66        pub graph: &'a mut gix_negotiate::Graph<'b, 'c>,
67    }
68
69    /// A trait to encapsulate steps to negotiate the contents of the pack.
70    ///
71    /// Typical implementations use the utilities found in the [`negotiate`] module.
72    pub trait Negotiate {
73        /// Typically invokes [`negotiate::mark_complete_and_common_ref()`].
74        fn mark_complete_and_common_ref(&mut self) -> Result<negotiate::Action, negotiate::Error>;
75        /// Typically invokes [`negotiate::add_wants()`].
76        /// Returns `true` if wants were added, or `false` if the negotiation should be aborted.
77        #[must_use]
78        fn add_wants(&mut self, arguments: &mut fetch::Arguments, remote_ref_target_known: &[bool]) -> bool;
79        /// Typically invokes [`negotiate::one_round()`].
80        fn one_round(
81            &mut self,
82            state: &mut negotiate::one_round::State,
83            arguments: &mut fetch::Arguments,
84            previous_response: Option<&fetch::Response>,
85        ) -> Result<(negotiate::Round, bool), negotiate::Error>;
86    }
87
88    /// The outcome of [`fetch()`](crate::fetch()).
89    #[derive(Debug, Clone)]
90    pub struct Outcome {
91        /// The most recent server response.
92        ///
93        /// Useful to obtain information about new shallow boundaries.
94        pub last_response: fetch::Response,
95        /// Information about the negotiation to receive the new pack.
96        pub negotiate: NegotiateOutcome,
97    }
98
99    /// The negotiation-specific outcome of [`fetch()`](crate::fetch()).
100    #[derive(Debug, Clone)]
101    pub struct NegotiateOutcome {
102        /// The outcome of the negotiation stage of the fetch operation.
103        ///
104        /// If it is…
105        ///
106        /// * [`negotiate::Action::MustNegotiate`] there will always be a `pack`.
107        /// * [`negotiate::Action::SkipToRefUpdate`] there is no `pack` but references can be updated right away.
108        ///
109        /// Note that this is never [negotiate::Action::NoChange`] as this would mean there is no negotiation information at all
110        /// so this structure wouldn't be present.
111        pub action: negotiate::Action,
112        /// Additional information for each round of negotiation.
113        pub rounds: Vec<negotiate::Round>,
114    }
115
116    /// Information about the relationship between our refspecs, and remote references with their local counterparts.
117    ///
118    /// It's the first stage that offers connection to the server, and is typically required to perform one or more fetch operations.
119    #[derive(Default, Debug, Clone)]
120    pub struct RefMap {
121        /// A mapping between a remote reference and a local tracking branch.
122        pub mappings: Vec<refmap::Mapping>,
123        /// The explicit refspecs that were supposed to be used for fetching.
124        ///
125        /// Typically, they are configured by the remote and are referred to by
126        /// [`refmap::SpecIndex::ExplicitInRemote`] in [`refmap::Mapping`].
127        pub refspecs: Vec<gix_refspec::RefSpec>,
128        /// Refspecs which have been added implicitly due to settings of the `remote`, usually pre-initialized from
129        /// [`extra_refspecs` in RefMap options](refmap::init::Options).
130        /// They are referred to by [`refmap::SpecIndex::Implicit`] in [`refmap::Mapping`].
131        ///
132        /// They are never persisted nor are they typically presented to the user.
133        pub extra_refspecs: Vec<gix_refspec::RefSpec>,
134        /// Information about the fixes applied to the `mapping` due to validation and sanitization.
135        pub fixes: Vec<gix_refspec::match_group::validate::Fix>,
136        /// All refs advertised by the remote.
137        pub remote_refs: Vec<crate::handshake::Ref>,
138        /// The kind of hash used for all data sent by the server, if understood by this client implementation.
139        ///
140        /// It was extracted from the `handshake` as advertised by the server.
141        pub object_hash: gix_hash::Kind,
142    }
143}
144#[cfg(feature = "fetch")]
145pub use with_fetch::*;
146
147/// Describe how shallow clones are handled when fetching, with variants defining how the *shallow boundary* is handled.
148///
149/// The *shallow boundary* is a set of commits whose parents are not present in the repository.
150#[derive(Default, Debug, Clone, PartialEq, Eq)]
151pub enum Shallow {
152    /// Fetch all changes from the remote without affecting the shallow boundary at all.
153    ///
154    /// This also means that repositories that aren't shallow will remain like that.
155    #[default]
156    NoChange,
157    /// Receive update to `depth` commits in the history of the refs to fetch (from the viewpoint of the remote),
158    /// with the value of `1` meaning to receive only the commit a ref is pointing to.
159    ///
160    /// This may update the shallow boundary to increase or decrease the amount of available history.
161    DepthAtRemote(std::num::NonZeroU32),
162    /// Increase the number of commits and thus expand the shallow boundary by `depth` commits as seen from our local
163    /// shallow boundary, with a value of `0` having no effect.
164    Deepen(u32),
165    /// Set the shallow boundary at the `cutoff` time, meaning that there will be no commits beyond that time.
166    Since {
167        /// The date beyond which there will be no history.
168        cutoff: gix_date::Time,
169    },
170    /// Receive all history excluding all commits reachable from `remote_refs`. These can be long or short
171    /// ref names or tag names.
172    Exclude {
173        /// The ref names to exclude, short or long. Note that ambiguous short names will cause the remote to abort
174        /// without an error message being transferred (because the protocol does not support it)
175        remote_refs: Vec<gix_ref::PartialName>,
176        /// If some, this field has the same meaning as [`Shallow::Since`] which can be used in combination
177        /// with excluded references.
178        since_cutoff: Option<gix_date::Time>,
179    },
180}
181
182impl Shallow {
183    /// Produce a variant that causes the repository to loose its shallow boundary, effectively by extending it
184    /// beyond all limits.
185    pub fn undo() -> Self {
186        Shallow::DepthAtRemote((i32::MAX as u32).try_into().expect("valid at compile time"))
187    }
188}
189
190/// Describe how to handle tags when fetching
191#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
192pub enum Tags {
193    /// Fetch all tags from the remote, even if these are not reachable from objects referred to by our refspecs.
194    All,
195    /// Fetch only the tags that point to the objects being sent.
196    /// That way, annotated tags that point to an object we receive are automatically transmitted and their refs are created.
197    /// The same goes for lightweight tags.
198    #[default]
199    Included,
200    /// Do not fetch any tags.
201    None,
202}
203
204impl Tags {
205    /// Obtain a refspec that determines whether or not to fetch all tags, depending on this variant.
206    ///
207    /// The returned refspec is the default refspec for tags, but won't overwrite local tags ever.
208    #[cfg(feature = "fetch")]
209    pub fn to_refspec(&self) -> Option<gix_refspec::RefSpecRef<'static>> {
210        match self {
211            Tags::All | Tags::Included => Some(
212                gix_refspec::parse("refs/tags/*:refs/tags/*".into(), gix_refspec::parse::Operation::Fetch)
213                    .expect("valid"),
214            ),
215            Tags::None => None,
216        }
217    }
218}
219
220/// A representation of a complete fetch response
221#[derive(Debug, Clone)]
222pub struct Response {
223    pub(crate) acks: Vec<Acknowledgement>,
224    pub(crate) shallows: Vec<ShallowUpdate>,
225    pub(crate) wanted_refs: Vec<WantedRef>,
226    pub(crate) has_pack: bool,
227}
228
229/// The progress ids used in during various steps of the fetch operation.
230///
231/// Note that tagged progress isn't very widely available yet, but support can be improved as needed.
232///
233/// Use this information to selectively extract the progress of interest in case the parent application has custom visualization.
234#[derive(Debug, Copy, Clone)]
235pub enum ProgressId {
236    /// The progress name is defined by the remote and the progress messages it sets, along with their progress values and limits.
237    RemoteProgress,
238}
239
240impl From<ProgressId> for gix_features::progress::Id {
241    fn from(v: ProgressId) -> Self {
242        match v {
243            ProgressId::RemoteProgress => *b"FERP",
244        }
245    }
246}