summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/remote/connect.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/remote/connect.rs')
-rw-r--r--vendor/gix/src/remote/connect.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/vendor/gix/src/remote/connect.rs b/vendor/gix/src/remote/connect.rs
new file mode 100644
index 000000000..8e656975e
--- /dev/null
+++ b/vendor/gix/src/remote/connect.rs
@@ -0,0 +1,166 @@
+#![allow(clippy::result_large_err)]
+use gix_protocol::transport::client::Transport;
+
+use crate::{remote::Connection, Progress, Remote};
+
+mod error {
+ use crate::{bstr::BString, config, remote};
+
+ /// The error returned by [connect()][crate::Remote::connect()].
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Could not obtain options for connecting via ssh")]
+ SshOptions(#[from] config::ssh_connect_options::Error),
+ #[error("Could not obtain the current directory")]
+ CurrentDir(#[from] std::io::Error),
+ #[error("Could not access remote repository at \"{}\"", directory.display())]
+ InvalidRemoteRepositoryPath { directory: std::path::PathBuf },
+ #[error(transparent)]
+ SchemePermission(#[from] config::protocol::allow::Error),
+ #[error("Protocol {scheme:?} of url {url:?} is denied per configuration")]
+ ProtocolDenied { url: BString, scheme: gix_url::Scheme },
+ #[error(transparent)]
+ Connect(#[from] gix_protocol::transport::client::connect::Error),
+ #[error("The {} url was missing - don't know where to establish a connection to", direction.as_str())]
+ MissingUrl { direction: remote::Direction },
+ #[error("Protocol named {given:?} is not a valid protocol. Choose between 1 and 2")]
+ UnknownProtocol { given: BString },
+ #[error("Could not verify that \"{}\" url is a valid git directory before attempting to use it", url.to_bstring())]
+ FileUrl {
+ source: Box<gix_discover::is_git::Error>,
+ url: gix_url::Url,
+ },
+ }
+
+ impl gix_protocol::transport::IsSpuriousError for Error {
+ /// Return `true` if retrying might result in a different outcome due to IO working out differently.
+ fn is_spurious(&self) -> bool {
+ match self {
+ Error::Connect(err) => err.is_spurious(),
+ _ => false,
+ }
+ }
+ }
+}
+pub use error::Error;
+
+/// Establishing connections to remote hosts (without performing a git-handshake).
+impl<'repo> Remote<'repo> {
+ /// Create a new connection using `transport` to communicate, with `progress` to indicate changes.
+ ///
+ /// Note that this method expects the `transport` to be created by the user, which would involve the [`url()`][Self::url()].
+ /// It's meant to be used when async operation is needed with runtimes of the user's choice.
+ pub fn to_connection_with_transport<T, P>(&self, transport: T, progress: P) -> Connection<'_, 'repo, T, P>
+ where
+ T: Transport,
+ P: Progress,
+ {
+ Connection {
+ remote: self,
+ authenticate: None,
+ transport_options: None,
+ transport,
+ progress,
+ }
+ }
+
+ /// Connect to the url suitable for `direction` and return a handle through which operations can be performed.
+ ///
+ /// Note that the `protocol.version` configuration key affects the transport protocol used to connect,
+ /// with `2` being the default.
+ ///
+ /// The transport used for connection can be configured via `transport_mut().configure()` assuming the actually
+ /// used transport is well known. If that's not the case, the transport can be created by hand and passed to
+ /// [to_connection_with_transport()][Self::to_connection_with_transport()].
+ #[cfg(any(feature = "blocking-network-client", feature = "async-network-client-async-std"))]
+ #[gix_protocol::maybe_async::maybe_async]
+ pub async fn connect<P>(
+ &self,
+ direction: crate::remote::Direction,
+ progress: P,
+ ) -> Result<Connection<'_, 'repo, Box<dyn Transport + Send>, P>, Error>
+ where
+ P: Progress,
+ {
+ let (url, version) = self.sanitized_url_and_version(direction)?;
+ #[cfg(feature = "blocking-network-client")]
+ let scheme_is_ssh = url.scheme == gix_url::Scheme::Ssh;
+ let transport = gix_protocol::transport::connect(
+ url,
+ gix_protocol::transport::client::connect::Options {
+ version,
+ #[cfg(feature = "blocking-network-client")]
+ ssh: scheme_is_ssh
+ .then(|| self.repo.ssh_connect_options())
+ .transpose()?
+ .unwrap_or_default(),
+ },
+ )
+ .await?;
+ Ok(self.to_connection_with_transport(transport, progress))
+ }
+
+ /// Produce the sanitized URL and protocol version to use as obtained by querying the repository configuration.
+ ///
+ /// This can be useful when using custom transports to allow additional configuration.
+ pub fn sanitized_url_and_version(
+ &self,
+ direction: crate::remote::Direction,
+ ) -> Result<(gix_url::Url, gix_protocol::transport::Protocol), Error> {
+ fn sanitize(mut url: gix_url::Url) -> Result<gix_url::Url, Error> {
+ if url.scheme == gix_url::Scheme::File {
+ let mut dir = gix_path::to_native_path_on_windows(url.path.as_ref());
+ let kind = gix_discover::is_git(dir.as_ref())
+ .or_else(|_| {
+ dir.to_mut().push(gix_discover::DOT_GIT_DIR);
+ gix_discover::is_git(dir.as_ref())
+ })
+ .map_err(|err| Error::FileUrl {
+ source: err.into(),
+ url: url.clone(),
+ })?;
+ let (git_dir, _work_dir) = gix_discover::repository::Path::from_dot_git_dir(
+ dir.clone().into_owned(),
+ kind,
+ std::env::current_dir()?,
+ )
+ .ok_or_else(|| Error::InvalidRemoteRepositoryPath {
+ directory: dir.into_owned(),
+ })?
+ .into_repository_and_work_tree_directories();
+ url.path = gix_path::into_bstr(git_dir).into_owned();
+ }
+ Ok(url)
+ }
+
+ use gix_protocol::transport::Protocol;
+ let version = self
+ .repo
+ .config
+ .resolved
+ .integer("protocol", None, "version")
+ .unwrap_or(Ok(2))
+ .map_err(|err| Error::UnknownProtocol { given: err.input })
+ .and_then(|num| {
+ Ok(match num {
+ 1 => Protocol::V1,
+ 2 => Protocol::V2,
+ num => {
+ return Err(Error::UnknownProtocol {
+ given: num.to_string().into(),
+ })
+ }
+ })
+ })?;
+
+ let url = self.url(direction).ok_or(Error::MissingUrl { direction })?.to_owned();
+ if !self.repo.config.url_scheme()?.allow(&url.scheme) {
+ return Err(Error::ProtocolDenied {
+ url: url.to_bstring(),
+ scheme: url.scheme,
+ });
+ }
+ Ok((sanitize(url)?, version))
+ }
+}