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    /// `fetch` / `push` / `ls-remote` over SSH upload-pack/receive-pack.
20    pub ssh_fetch: bool,
21    pub ssh_push: bool,
22    /// `clone` over SSH (bare mirror / checkout destination).
23    pub ssh_clone: bool,
24    /// `fetch` / `push` / `clone` / `ls-remote` over native `git://`.
25    pub git_fetch: bool,
26    pub git_push: bool,
27    pub git_clone: bool,
28    /// `fetch` from `.bundle` files (git bundle protocol).
29    pub bundle_fetch: bool,
30    /// In-process `file://` upload-pack / receive-pack.
31    pub local_fetch: bool,
32    pub local_push: bool,
33    /// Credential-helper subprocess provider ([`CredentialHelperProvider`]).
34    pub credential_helper: bool,
35    /// Thin-pack generation on push (delta bases omitted from pack body).
36    pub thin_pack_push: bool,
37    /// SHA-256 object format over smart HTTP (negotiated via `object-format`).
38    pub sha256_http: bool,
39    /// SHA-256 object format over SSH.
40    pub sha256_ssh: bool,
41}
42
43/// Flip to `true` once HTTP v2 `fetch` RPC is wired (see `http.rs`).
44pub const HTTP_PROTOCOL_V2_FETCH: bool = true;
45/// Flip to `true` once `CloneSource::Ssh` lands.
46pub const SSH_CLONE_SUPPORTED: bool = true;
47/// Flip to `true` once bundle fetch is lifted from the CLI.
48pub const BUNDLE_FETCH_SUPPORTED: bool = true;
49/// Thin-pack push via [`crate::pack::build_push_packfile`] (`PushPackRequest::thin`).
50pub const THIN_PACK_PUSH_SUPPORTED: bool = true;
51
52impl TransportCapabilities {
53    /// Capabilities of the currently linked `sley-remote` build.
54    pub const fn current() -> Self {
55        Self {
56            http_fetch: cfg!(feature = "http"),
57            http_push: cfg!(feature = "http"),
58            http_protocol_v2_discovery: cfg!(feature = "http"),
59            http_protocol_v2_fetch: cfg!(feature = "http") && HTTP_PROTOCOL_V2_FETCH,
60            shallow_fetch: true,
61            ssh_fetch: true,
62            ssh_push: true,
63            ssh_clone: SSH_CLONE_SUPPORTED,
64            git_fetch: true,
65            git_push: true,
66            git_clone: true,
67            bundle_fetch: BUNDLE_FETCH_SUPPORTED,
68            local_fetch: true,
69            local_push: true,
70            credential_helper: true,
71            thin_pack_push: THIN_PACK_PUSH_SUPPORTED,
72            sha256_http: cfg!(feature = "http"),
73            sha256_ssh: true,
74        }
75    }
76
77    /// Whether native push is available for the given transport class.
78    pub fn supports_native_push(&self, transport: RemoteTransportKind) -> bool {
79        match transport {
80            RemoteTransportKind::Http => self.http_push,
81            RemoteTransportKind::Ssh => self.ssh_push,
82            RemoteTransportKind::Git => self.git_push,
83            RemoteTransportKind::Local => self.local_push,
84            RemoteTransportKind::Bundle => false,
85        }
86    }
87
88    /// Whether shallow fetch/clone is available for the given transport class.
89    pub fn supports_shallow(&self, transport: RemoteTransportKind) -> bool {
90        match transport {
91            RemoteTransportKind::Http | RemoteTransportKind::Ssh | RemoteTransportKind::Git => {
92                self.shallow_fetch
93            }
94            RemoteTransportKind::Local | RemoteTransportKind::Bundle => false,
95        }
96    }
97}
98
99/// Coarse transport classification for capability lookups.
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum RemoteTransportKind {
102    Http,
103    Ssh,
104    Git,
105    Local,
106    Bundle,
107}
108
109#[cfg(all(test, not(feature = "http")))]
110mod tests {
111    use super::TransportCapabilities;
112
113    #[test]
114    fn ssh_only_build_disables_http_fetch_capability() {
115        let caps = TransportCapabilities::current();
116        assert!(!caps.http_fetch);
117        assert!(!caps.http_push);
118        assert!(!caps.http_protocol_v2_discovery);
119        assert!(!caps.http_protocol_v2_fetch);
120        assert!(!caps.sha256_http);
121        assert!(caps.ssh_fetch);
122    }
123}
124
125impl RemoteTransportKind {
126    pub fn from_url_scheme(url: &str) -> Option<Self> {
127        if url.starts_with("http://") || url.starts_with("https://") {
128            return Some(Self::Http);
129        }
130        if url.starts_with("git://") {
131            return Some(Self::Git);
132        }
133        if url.starts_with("ssh://")
134            || url.starts_with("git@")
135            || url.contains(':') && !url.contains("://")
136        {
137            return Some(Self::Ssh);
138        }
139        if url.starts_with("file://") || url.starts_with('/') || url.starts_with("./") {
140            return Some(Self::Local);
141        }
142        if url.ends_with(".bundle") {
143            return Some(Self::Bundle);
144        }
145        None
146    }
147}