History

feat: add `Handshake::ref_map()` to produce a ref-map from a V1 or V2 handshake.

Sebastian Thiel committed 1 year ago

Commit aeee9821 parent a61b2ab5 files · +72 −36Browse files

Unified · Split

5 files
  1. gitoxide-core/src/pack/receive.rs +12 −18
  2. gix-protocol/src/fetch/refmap/init.rs +1 −0
  3. gix-protocol/src/fetch/response/mod.rs +1 −1
  4. gix-protocol/src/handshake/mod.rs +46 −0
  5. gix/src/remote/connection/ref_map.rs +12 −17
gitoxide-core/src/pack/receive.rs+12−18
@@ -4,6 +4,7 @@ use std::{ · 3 unmodified lines
4 sync::{atomic::AtomicBool, Arc},4 sync::{atomic::AtomicBool, Arc},
5};5};
6 6
7use crate::{net, pack::receive::protocol::fetch::negotiate, OutputFormat};
7#[cfg(feature = "async-client")]8#[cfg(feature = "async-client")]
8use gix::protocol::transport::client::async_io::connect;9use gix::protocol::transport::client::async_io::connect;
9#[cfg(feature = "blocking-client")]10#[cfg(feature = "blocking-client")]
@@ -23,8 +24,6 @@ pub use gix::{ · 13 unmodified lines
23 NestedProgress, Progress,24 NestedProgress, Progress,
24};25};
25 26
26use crate::{net, pack::receive::protocol::fetch::negotiate, OutputFormat};
27
28pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;27pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;
29pub struct Context<W> {28pub struct Context<W> {
30 pub thread_limit: Option<usize>,29 pub thread_limit: Option<usize>,
@@ -65,7 +64,7 @@ where · 34 unmodified lines
65 .is_some();64 .is_some();
66 65
67 let agent = gix::protocol::agent(gix::env::agent());66 let agent = gix::protocol::agent(gix::env::agent());
68 let mut handshake = gix::protocol::fetch::handshake(67 let mut handshake: gix::protocol::Handshake = gix::protocol::fetch::handshake(
69 &mut transport.inner,68 &mut transport.inner,
70 gix::protocol::credentials::builtin,69 gix::protocol::credentials::builtin,
71 vec![("agent".into(), Some(agent.clone()))],70 vec![("agent".into(), Some(agent.clone()))],
@@ -87,21 +86,16 @@ where · 15 unmodified lines
87 fetch_refspecs: fetch_refspecs.clone(),86 fetch_refspecs: fetch_refspecs.clone(),
88 extra_refspecs: vec![],87 extra_refspecs: vec![],
89 };88 };
90 let refmap = match handshake.refs.take() {89 let refmap = handshake
91 Some(refs) => gix::protocol::fetch::RefMap::from_refs(refs, &handshake.capabilities, context)?,90 .fetch_or_extract_refmap(
92 None => {91 &mut progress,
93 gix::protocol::fetch::RefMap::fetch(92 &mut transport.inner,
94 &mut progress,93 user_agent.clone(),
95 &handshake.capabilities,94 trace_packetlines,
96 &mut transport.inner,95 true,
97 user_agent.clone(),96 context,
98 trace_packetlines,97 )
99 true,98 .await?;
100 context,
101 )
102 .await?
103 }
104 };
105 99
106 if refmap.mappings.is_empty() && !refmap.remote_refs.is_empty() {100 if refmap.mappings.is_empty() && !refmap.remote_refs.is_empty() {
107 return Err(Error::NoMapping {101 return Err(Error::NoMapping {
gix-protocol/src/fetch/refmap/init.rs+1−0
@@ -94,6 +94,7 @@ impl RefMap { · 93 unmodified lines
94 }94 }
95 95
96 /// Create a ref-map from already obtained `remote_refs`. Use `context` to pass in refspecs.96 /// Create a ref-map from already obtained `remote_refs`. Use `context` to pass in refspecs.
97 /// `capabilities` are used to determine the object format.
97 pub fn from_refs(remote_refs: Vec<Ref>, capabilities: &Capabilities, context: Context) -> Result<RefMap, Error> {98 pub fn from_refs(remote_refs: Vec<Ref>, capabilities: &Capabilities, context: Context) -> Result<RefMap, Error> {
98 let all_refspecs = context.aggregate_refspecs();99 let all_refspecs = context.aggregate_refspecs();
99 let Context {100 let Context {
gix-protocol/src/fetch/response/mod.rs+1−1
@@ -185,7 +185,7 @@ impl Response { · 184 unmodified lines
185 }185 }
186 186
187 /// Append the given `updates` which may have been obtained from a187 /// Append the given `updates` which may have been obtained from a
188 /// (handshake::Outcome)[crate::handshake::Handshake::v1_shallow_updates].188 /// (handshake::Outcome)[crate::Handshake::v1_shallow_updates].
189 ///189 ///
190 /// In V2, these are received as part of the pack, but V1 sends them early, so we190 /// In V2, these are received as part of the pack, but V1 sends them early, so we
191 /// offer to re-integrate them here.191 /// offer to re-integrate them here.
gix-protocol/src/handshake/mod.rs+46−0
@@ -68,6 +68,52 @@ pub(crate) mod hero { · 67 unmodified lines
68 /// The server capabilities.68 /// The server capabilities.
69 pub capabilities: gix_transport::client::Capabilities,69 pub capabilities: gix_transport::client::Capabilities,
70 }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 }
71}117}
72 118
73#[cfg(feature = "handshake")]119#[cfg(feature = "handshake")]
gix/src/remote/connection/ref_map.rs+12−17
@@ -143,7 +143,7 @@ where · 142 unmodified lines
143 if let Some(config) = self.transport_options.as_ref() {143 if let Some(config) = self.transport_options.as_ref() {
144 self.transport.inner.configure(&**config)?;144 self.transport.inner.configure(&**config)?;
145 }145 }
146 let mut handshake = gix_protocol::fetch::handshake(146 let mut handshake: gix_protocol::Handshake = gix_protocol::fetch::handshake(
147 &mut self.transport.inner,147 &mut self.transport.inner,
148 authenticate,148 authenticate,
149 handshake_parameters,149 handshake_parameters,
@@ -151,25 +151,20 @@ where · 1 unmodified line
151 )151 )
152 .await?;152 .await?;
153 153
154 let context = gix_protocol::fetch::refmap::init::Context {154 let context = fetch::refmap::init::Context {
155 fetch_refspecs: self.remote.fetch_specs.clone(),155 fetch_refspecs: self.remote.fetch_specs.clone(),
156 extra_refspecs,156 extra_refspecs,
157 };157 };
158 let ref_map = match handshake.refs.take() {158 let ref_map = handshake
159 Some(refs) => fetch::RefMap::from_refs(refs, &handshake.capabilities, context)?,159 .fetch_or_extract_refmap(
160 None => {160 progress,
161 gix_protocol::fetch::RefMap::fetch(161 &mut self.transport.inner,
162 progress,162 self.remote.repo.config.user_agent_tuple(),
163 &handshake.capabilities,163 self.trace,
164 &mut self.transport.inner,164 prefix_from_spec_as_filter_on_remote,
165 self.remote.repo.config.user_agent_tuple(),165 context,
166 self.trace,166 )
167 prefix_from_spec_as_filter_on_remote,167 .await?;
168 context,
169 )
170 .await?
171 }
172 };
173 self.handshake = Some(handshake);168 self.handshake = Some(handshake);
174 Ok(ref_map)169 Ok(ref_map)
175 }170 }