History

feat!: add `remote::Connection::with_transport_config()`, change the way `*::transport_mut()` is used.

Previously `transport_mut()` was supposed to be used for calling `configure()`, but that doesn't work anymore as `configure()` can only effectivey be called once the initialization of the Connection is complete, as it may depend on the Remote name AND the credential provider for proxy auth credential acquisition. Thus we allow callers to set the transport options they need in advance for it to be used when needed.

Sebastian Thiel committed 4 years ago

Commit db9040f1 parent b46e3bb7 files · +45 −14Browse files

Unified · Split

7 files
  1. git-repository/src/remote/connect.rs +1 −0
  2. git-repository/src/remote/connection/access.rs +16 −7
  3. git-repository/src/remote/connection/mod.rs +1 −0
  4. git-repository/src/remote/connection/ref_map.rs +23 −3
  5. git-repository/src/repository/config/transport.rs +2 −2
  6. git-repository/tests/repository/config/mod.rs +1 −1
  7. git-repository/tests/repository/config/transport_options.rs +1 −1
git-repository/src/remote/connect.rs+1−0
@@ -39,6 +39,7 @@ impl<'repo> Remote<'repo> { · 38 unmodified lines
39 Connection {39 Connection {
40 remote: self,40 remote: self,
41 authenticate: None,41 authenticate: None,
42 transport_config: None,
42 transport,43 transport,
43 progress,44 progress,
44 }45 }
git-repository/src/remote/connection/access.rs+16−7
@@ -19,6 +19,18 @@ impl<'a, 'repo, T, P> Connection<'a, 'repo, T, P> { · 18 unmodified lines
19 self.authenticate = Some(Box::new(helper));19 self.authenticate = Some(Box::new(helper));
20 self20 self
21 }21 }
22
23 /// Provide configuration to be used before the first handshake is conducted.
24 /// It's typically created by initializing it with [`Repository::transport_options()`][crate::Repository::transport_options()], which
25 /// is also the default if this isn't set explicitly. Note that all of the default configuration is created from `git`
26 /// configuration, which can also be manipulated through overrides to affect the default configuration.
27 ///
28 /// Use this method to provide transport configuration with custom backend configuration that is not configurable by other means and
29 /// custom to the application at hand.
30 pub fn with_transport_options(mut self, config: Box<dyn std::any::Any>) -> Self {
31 self.transport_config = Some(config);
32 self
33 }
22}34}
23 35
24/// Access36/// Access
@@ -41,13 +53,10 @@ impl<'a, 'repo, T, P> Connection<'a, 'repo, T, P> { · 16 unmodified lines
41 self.remote53 self.remote
42 }54 }
43 55
44 /// Provide a mutable transport to allow configuring it with [`configure()`][git_protocol::transport::client::TransportWithoutIO::configure()].56 /// Provide a mutable transport to allow interacting with it according to its actual type.
45 ///57 /// Note that the caller _should not_ call [`configure()`][git_protocol::transport::client::TransportWithoutIO::configure()]
46 /// Please note that it is pre-configured, but can be configured again right after the [`Connection`] was instantiated without58 /// as we will call it automatically before performing the handshake. Instead, to bring in custom configuration,
47 /// the previous configuration having ever been used.59 /// call [`with_transport_options()`][Connection::with_transport_options()].
48 ///
49 /// Also note that all of the default configuration is created from `git` configuration, which can also be manipulated through overrides
50 /// to affect the default configuration.
51 pub fn transport_mut(&mut self) -> &mut T {60 pub fn transport_mut(&mut self) -> &mut T {
52 &mut self.transport61 &mut self.transport
53 }62 }
git-repository/src/remote/connection/mod.rs+1−0
@@ -15,6 +15,7 @@ pub type AuthenticateFn<'a> = Box<dyn FnMut(git_credentials::helper::Action) -> · 14 unmodified lines
15pub struct Connection<'a, 'repo, T, P> {15pub struct Connection<'a, 'repo, T, P> {
16 pub(crate) remote: &'a Remote<'repo>,16 pub(crate) remote: &'a Remote<'repo>,
17 pub(crate) authenticate: Option<AuthenticateFn<'a>>,17 pub(crate) authenticate: Option<AuthenticateFn<'a>>,
18 pub(crate) transport_config: Option<Box<dyn std::any::Any>>,
18 pub(crate) transport: T,19 pub(crate) transport: T,
19 pub(crate) progress: P,20 pub(crate) progress: P,
20}21}
git-repository/src/remote/connection/ref_map.rs+23−3
@@ -13,6 +13,13 @@ use crate::{ · 12 unmodified lines
13#[derive(Debug, thiserror::Error)]13#[derive(Debug, thiserror::Error)]
14#[allow(missing_docs)]14#[allow(missing_docs)]
15pub enum Error {15pub enum Error {
16 #[error("Failed to configure the transport before connecting to {url:?}")]
17 GatherTransportConfig {
18 url: BString,
19 source: crate::config::transport::Error,
20 },
21 #[error("Failed to configure the transport layer")]
22 ConfigureTransport(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
16 #[error(transparent)]23 #[error(transparent)]
17 Handshake(#[from] git_protocol::fetch::handshake::Error),24 Handshake(#[from] git_protocol::fetch::handshake::Error),
18 #[error("The object format {format:?} as used by the remote is unsupported")]25 #[error("The object format {format:?} as used by the remote is unsupported")]
@@ -139,6 +146,7 @@ where · 120 unmodified lines
139 extra_parameters: Vec<(String, Option<String>)>,146 extra_parameters: Vec<(String, Option<String>)>,
140 ) -> Result<HandshakeWithRefs, Error> {147 ) -> Result<HandshakeWithRefs, Error> {
141 let mut credentials_storage;148 let mut credentials_storage;
149 let url = self.transport.to_url();
142 let authenticate = match self.authenticate.as_mut() {150 let authenticate = match self.authenticate.as_mut() {
143 Some(f) => f,151 Some(f) => f,
144 None => {152 None => {
@@ -146,13 +154,25 @@ where · 1 unmodified line
146 .remote154 .remote
147 .url(Direction::Fetch)155 .url(Direction::Fetch)
148 .map(ToOwned::to_owned)156 .map(ToOwned::to_owned)
149 .unwrap_or_else(|| {157 .unwrap_or_else(|| git_url::parse(url.as_ref()).expect("valid URL to be provided by transport"));
150 git_url::parse(self.transport.to_url().as_ref()).expect("valid URL to be provided by transport")
151 });
152 credentials_storage = self.configured_credentials(url)?;158 credentials_storage = self.configured_credentials(url)?;
153 &mut credentials_storage159 &mut credentials_storage
154 }160 }
155 };161 };
162
163 if self.transport_config.is_none() {
164 self.transport_config =
165 self.remote
166 .repo
167 .transport_options(url.as_ref())
168 .map_err(|err| Error::GatherTransportConfig {
169 source: err,
170 url: url.into_owned(),
171 })?;
172 }
173 if let Some(config) = self.transport_config.as_ref() {
174 self.transport.configure(&**config)?;
175 }
156 let mut outcome =176 let mut outcome =
157 git_protocol::fetch::handshake(&mut self.transport, authenticate, extra_parameters, &mut self.progress)177 git_protocol::fetch::handshake(&mut self.transport, authenticate, extra_parameters, &mut self.progress)
158 .await?;178 .await?;
git-repository/src/repository/config/transport.rs+2−2
@@ -6,11 +6,11 @@ use std::convert::{TryFrom, TryInto}; · 5 unmodified lines
6 6
7impl crate::Repository {7impl crate::Repository {
8 /// Produce configuration suitable for `url`, as differentiated by its protocol/scheme, to be passed to a transport instance via8 /// Produce configuration suitable for `url`, as differentiated by its protocol/scheme, to be passed to a transport instance via
9 /// [configure()][git_transport::client::TransportWithoutIO::configure()].9 /// [configure()][git_transport::client::TransportWithoutIO::configure()] (via `&**config` to pass the contained `Any` and not the `Box`).
10 /// `None` is returned if there is no known configuration.10 /// `None` is returned if there is no known configuration.
11 ///11 ///
12 /// Note that the caller may cast the instance themselves to modify it before passing it on.12 /// Note that the caller may cast the instance themselves to modify it before passing it on.
13 pub fn transport_config<'a>(13 pub fn transport_options<'a>(
14 &self,14 &self,
15 url: impl Into<&'a BStr>,15 url: impl Into<&'a BStr>,
16 ) -> Result<Option<Box<dyn Any>>, crate::config::transport::Error> {16 ) -> Result<Option<Box<dyn Any>>, crate::config::transport::Error> {
git-repository/tests/repository/config/mod.rs+1−1
@@ -2,4 +2,4 @@ mod config_snapshot; · 1 unmodified line
2mod identity;2mod identity;
3mod remote;3mod remote;
4#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]4#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
5mod transport_config;5mod transport_options;
git-repository/tests/repository/config/transport_options.rsrenamed from git-repository/tests/repository/config/transport_config.rs+1−1
@@ -23,7 +23,7 @@ mod http { · 22 unmodified lines
23 fn simple_configuration() {23 fn simple_configuration() {
24 let repo = repo("http-config");24 let repo = repo("http-config");
25 let http_config = repo25 let http_config = repo
26 .transport_config("https://example.com/does/not/matter")26 .transport_options("https://example.com/does/not/matter")
27 .expect("valid configuration")27 .expect("valid configuration")
28 .expect("configuration available for http");28 .expect("configuration available for http");
29 let git_transport::client::http::Options {29 let git_transport::client::http::Options {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t