gix_transport/
lib.rs

1//! An implementation of the `git` transport layer, abstracting over all of its [versions][Protocol], providing
2//! [`connect()`] to establish a connection given a repository URL.
3//!
4//! All git transports are supported, including `ssh`, `git`, `http` and `https`, as well as local repository paths.
5//! ## Feature Flags
6#![cfg_attr(
7    all(doc, feature = "document-features"),
8    doc = ::document_features::document_features!()
9)]
10#![cfg_attr(all(doc, feature = "document-features"), feature(doc_cfg, doc_auto_cfg))]
11#![deny(missing_docs, rust_2018_idioms)]
12#![forbid(unsafe_code)]
13
14#[cfg(feature = "async-trait")]
15pub use async_trait;
16pub use bstr;
17#[cfg(feature = "futures-io")]
18pub use futures_io;
19pub use gix_packetline as packetline;
20
21/// The version of the way client and server communicate.
22#[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub enum Protocol {
25    /// Version 0 is like V1, but doesn't show capabilities at all, at least when hosted without `git-daemon`.
26    V0 = 0,
27    /// Version 1 was the first one conceived, is stateful, and our implementation was seen to cause deadlocks. Prefer V2
28    V1 = 1,
29    /// A command-based and stateless protocol with clear semantics, and the one to use assuming the server isn't very old.
30    /// This is the default.
31    #[default]
32    V2 = 2,
33}
34
35/// The kind of service to invoke on the client or the server side.
36#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub enum Service {
39    /// The service sending packs from a server to the client. Used for fetching pack data.
40    UploadPack,
41    /// The service receiving packs produced by the client, who sends a pack to the server.
42    ReceivePack,
43}
44
45impl Service {
46    /// Render this instance as string recognized by the git transport layer.
47    pub fn as_str(&self) -> &'static str {
48        match self {
49            Service::ReceivePack => "git-receive-pack",
50            Service::UploadPack => "git-upload-pack",
51        }
52    }
53}
54
55mod traits {
56    use std::convert::Infallible;
57
58    /// An error which can tell whether it's worth retrying to maybe succeed next time.
59    pub trait IsSpuriousError: std::error::Error {
60        /// Return `true` if retrying might result in a different outcome due to IO working out differently.
61        fn is_spurious(&self) -> bool {
62            false
63        }
64    }
65
66    impl IsSpuriousError for Infallible {}
67
68    impl IsSpuriousError for std::io::Error {
69        fn is_spurious(&self) -> bool {
70            // TODO: also include the new special Kinds (currently unstable)
71            use std::io::ErrorKind::*;
72            match self.kind() {
73                Unsupported | WriteZero | InvalidInput | InvalidData | WouldBlock | AlreadyExists
74                | AddrNotAvailable | NotConnected | Other | PermissionDenied | NotFound => false,
75                Interrupted | UnexpectedEof | OutOfMemory | TimedOut | BrokenPipe | AddrInUse | ConnectionAborted
76                | ConnectionReset | ConnectionRefused => true,
77                _ => false,
78            }
79        }
80    }
81}
82pub use traits::IsSpuriousError;
83
84///
85pub mod client;
86
87#[doc(inline)]
88#[cfg(any(feature = "blocking-client", all(feature = "async-client", feature = "async-std")))]
89pub use client::connect;
90
91#[cfg(all(feature = "async-client", feature = "blocking-client"))]
92compile_error!("Cannot set both 'blocking-client' and 'async-client' features as they are mutually exclusive");