Skip to main content

sley_remote/
capabilities.rs

1//! Capability probes for downstream consumers (e.g. heddle).
2//!
3//! These flags describe what the *library* can do today so embedders can fail
4//! loudly instead of silently falling back to another implementation.
5
6/// Transport and remote-operation capabilities exposed by `sley-remote`.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct TransportCapabilities {
9    /// `fetch` / `clone` over HTTP(S) smart transport.
10    pub http_fetch: bool,
11    /// `push` over HTTP(S) receive-pack.
12    pub http_push: bool,
13    /// Protocol v2 service discovery + `ls-refs` ref advertisements.
14    pub http_protocol_v2_discovery: bool,
15    /// Protocol v2 `fetch` command (pack negotiation over v2 RPC).
16    pub http_protocol_v2_fetch: bool,
17    /// Shallow clone/fetch via `--depth` / `deepen`.
18    pub shallow_fetch: bool,
19    pub http_partial_clone: bool,
20    pub http_deepen_since_not: bool,
21    /// `fetch` / `push` / `ls-remote` over SSH upload-pack/receive-pack.
22    pub ssh_fetch: bool,
23    pub ssh_protocol_v2: bool,
24    pub ssh_push: bool,
25    /// `clone` over SSH (bare mirror / checkout destination).
26    pub ssh_clone: bool,
27    /// `fetch` / `push` / `clone` / `ls-remote` over native `git://`.
28    pub git_fetch: bool,
29    pub git_push: bool,
30    pub git_clone: bool,
31    /// `fetch` from `.bundle` files (git bundle protocol).
32    pub bundle_fetch: bool,
33    /// In-process `file://` upload-pack / receive-pack.
34    pub local_fetch: bool,
35    pub local_push: bool,
36    /// Credential-helper subprocess provider ([`CredentialHelperProvider`]).
37    pub credential_helper: bool,
38    /// Thin-pack generation on push (delta bases omitted from pack body).
39    pub thin_pack_push: bool,
40    /// SHA-256 object format over smart HTTP (negotiated via `object-format`).
41    pub sha256_http: bool,
42    /// SHA-256 object format over SSH.
43    pub sha256_ssh: bool,
44}
45
46impl TransportCapabilities {
47    /// Capabilities of the currently linked `sley-remote` build.
48    pub const fn current() -> Self {
49        Self {
50            http_fetch: cfg!(feature = "http"),
51            http_push: cfg!(feature = "http"),
52            http_protocol_v2_discovery: cfg!(feature = "http"),
53            http_protocol_v2_fetch: cfg!(feature = "http"),
54            shallow_fetch: true,
55            http_partial_clone: cfg!(feature = "http"),
56            http_deepen_since_not: cfg!(feature = "http"),
57            ssh_fetch: true,
58            ssh_protocol_v2: false,
59            ssh_push: true,
60            ssh_clone: true,
61            git_fetch: true,
62            git_push: true,
63            git_clone: true,
64            bundle_fetch: true,
65            local_fetch: true,
66            local_push: true,
67            credential_helper: true,
68            thin_pack_push: true,
69            sha256_http: cfg!(feature = "http"),
70            sha256_ssh: true,
71        }
72    }
73
74    /// Whether native push is available for the given transport class.
75    pub fn supports_native_push(&self, transport: RemoteTransportKind) -> bool {
76        match transport {
77            RemoteTransportKind::Http => self.http_push,
78            RemoteTransportKind::Ssh => self.ssh_push,
79            RemoteTransportKind::Git => self.git_push,
80            RemoteTransportKind::Local => self.local_push,
81            RemoteTransportKind::Bundle => false,
82        }
83    }
84
85    /// Whether shallow fetch/clone is available for the given transport class.
86    pub fn supports_shallow(&self, transport: RemoteTransportKind) -> bool {
87        match transport {
88            RemoteTransportKind::Http | RemoteTransportKind::Ssh | RemoteTransportKind::Git => {
89                self.shallow_fetch
90            }
91            RemoteTransportKind::Local | RemoteTransportKind::Bundle => false,
92        }
93    }
94}
95
96/// Coarse transport classification for capability lookups.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum RemoteTransportKind {
99    Http,
100    Ssh,
101    Git,
102    Local,
103    Bundle,
104}
105
106#[cfg(all(test, not(feature = "http")))]
107mod tests {
108    use super::TransportCapabilities;
109
110    #[test]
111    fn ssh_only_build_disables_http_fetch_capability() {
112        let caps = TransportCapabilities::current();
113        assert!(!caps.http_fetch);
114        assert!(!caps.http_push);
115        assert!(!caps.http_protocol_v2_discovery);
116        assert!(!caps.http_protocol_v2_fetch);
117        assert!(!caps.sha256_http);
118        assert!(caps.ssh_fetch);
119    }
120}
121
122impl RemoteTransportKind {
123    pub fn from_url_scheme(url: &str) -> Option<Self> {
124        if url.starts_with("http://") || url.starts_with("https://") {
125            return Some(Self::Http);
126        }
127        if url.starts_with("git://") {
128            return Some(Self::Git);
129        }
130        if url.starts_with("ssh://")
131            || url.starts_with("git@")
132            || url.contains(':') && !url.contains("://")
133        {
134            return Some(Self::Ssh);
135        }
136        if url.starts_with("file://") || url.starts_with('/') || url.starts_with("./") {
137            return Some(Self::Local);
138        }
139        if url.ends_with(".bundle") {
140            return Some(Self::Bundle);
141        }
142        None
143    }
144}