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