#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
mod ssh;
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
pub use ssh::{receive_ssh, receive_ssh_with_depth, receive_ssh_with_progress};
#[cfg(any(
feature = "http",
all(feature = "ssh", any(target_os = "macos", target_os = "linux"))
))]
mod live_progress;
#[cfg(feature = "http")]
mod http;
#[cfg(feature = "http")]
pub use http::{
receive_http, receive_http_with_depth, receive_http_with_depth_and_progress,
receive_http_with_progress,
};
#[cfg(any(
feature = "http",
all(feature = "ssh", any(target_os = "macos", target_os = "linux"))
))]
mod download;
#[cfg(any(
feature = "http",
all(feature = "ssh", any(target_os = "macos", target_os = "linux"))
))]
pub use download::DownloadedFetch;
#[cfg(any(
feature = "http",
all(feature = "ssh", any(target_os = "macos", target_os = "linux"))
))]
mod workflow_network;
#[cfg(any(
feature = "http",
all(feature = "ssh", any(target_os = "macos", target_os = "linux"))
))]
pub use workflow_network::FetchDownload;
mod update;
mod verified;
pub use update::{FetchUpdateError, FetchUpdateLimits};
mod workflow;
mod worktree;
pub use workflow::{
FetchFinishError, FetchFinishFailure, FetchPlanError, FetchReady, FetchReport, FetchRequest,
FetchUpdate, FetchUpdateKind, FetchWorkflowError, RetainedFetchFinishError, RetainedFetchReady,
};
mod bytes;
mod connectivity;
mod discovery;
#[cfg(feature = "http")]
pub use discovery::discover_http;
pub(crate) use discovery::interpret_head;
pub use discovery::{
ProtocolVersion, RemoteDiscovery, RemoteHead, discover, discover_local, discover_session,
};
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
pub use discovery::{discover_ssh, discover_ssh_with_diagnostics};
mod progress;
pub use progress::{LocalFetchProgress, ValidationProgress};
mod import;
pub(crate) use import::index_self_contained;
mod install;
mod retention;
pub use retention::{FetchRetention, RetainedFetchError};
mod shallow;
pub use shallow::FetchShallowError;
mod known;
mod local;
mod local_native;
mod protocol;
use std::num::NonZeroU32;
use std::sync::atomic::{AtomicBool, Ordering};
pub(crate) use bytes::Bytes;
pub(crate) use install::NativeContents;
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
pub(crate) use install::PackInput;
pub use install::{FetchInstalled, ReceivedFetch};
pub use known::KnownHistory;
pub use local::{
receive_local, receive_local_with_control, receive_local_with_known,
receive_local_with_known_and_progress, receive_local_with_validation_progress,
};
pub(crate) use progress::ValidationObserver;
pub use protocol::{
AdvertisedRef, Advertisement, receive, receive_with_known, receive_with_known_depth,
};
#[derive(Debug, Clone, Copy)]
pub struct FetchOptions {
pub limits: FetchLimits,
pub depth: Option<NonZeroU32>,
}
#[derive(Debug, Clone, Copy)]
pub struct FetchLimits {
pub max_wire_bytes: usize,
pub max_advertisement_bytes: usize,
pub max_refs: usize,
pub max_wants: usize,
pub max_haves: usize,
pub max_shallow_roots: usize,
pub max_known_objects: usize,
pub max_known_bytes: usize,
pub max_known_edges: usize,
pub known_read: crate::ReadLimits,
pub max_pack_bytes: usize,
pub max_objects: usize,
pub max_object_bytes: usize,
pub max_delta_bytes: usize,
pub max_decode_bytes: usize,
pub max_delta_depth: usize,
pub max_resolution_steps: usize,
pub max_connectivity_edges: usize,
}
impl Default for FetchLimits {
fn default() -> Self {
Self {
max_wire_bytes: 512 * 1024 * 1024,
max_advertisement_bytes: 4 * 1024 * 1024,
max_refs: 100_000,
max_wants: 100_000,
max_haves: 256,
max_shallow_roots: 100_000,
max_known_objects: 1_000_000,
max_known_bytes: 256 * 1024 * 1024,
max_known_edges: 4_000_000,
known_read: crate::ReadLimits::default(),
max_pack_bytes: 256 * 1024 * 1024,
max_objects: 1_000_000,
max_object_bytes: 64 * 1024 * 1024,
max_delta_bytes: 64 * 1024 * 1024,
max_decode_bytes: 512 * 1024 * 1024,
max_delta_depth: 64,
max_resolution_steps: 10_000_000,
max_connectivity_edges: 4_000_000,
}
}
}
impl FetchLimits {
pub const fn trusted() -> Self {
const UNBOUNDED: usize = usize::MAX / 4;
Self {
max_wire_bytes: UNBOUNDED,
max_advertisement_bytes: UNBOUNDED,
max_refs: UNBOUNDED,
max_wants: UNBOUNDED,
max_haves: 256,
max_shallow_roots: UNBOUNDED,
max_known_objects: UNBOUNDED,
max_known_bytes: UNBOUNDED,
max_known_edges: UNBOUNDED,
known_read: crate::ReadLimits::trusted(),
max_pack_bytes: UNBOUNDED,
max_objects: UNBOUNDED,
max_object_bytes: UNBOUNDED,
max_delta_bytes: UNBOUNDED,
max_decode_bytes: UNBOUNDED,
max_delta_depth: 10_000,
max_resolution_steps: UNBOUNDED,
max_connectivity_edges: UNBOUNDED,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum FetchError {
#[error(transparent)]
ObjectFormat(#[from] crate::ObjectFormatError),
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
#[error(transparent)]
Ssh(crate::transport::ssh::SshError),
#[cfg(feature = "http")]
#[error(transparent)]
Http(crate::transport::http::HttpError),
#[error("fetch I/O")]
Io(#[source] std::io::Error),
#[error("invalid upload-pack response: {0}")]
Protocol(&'static str),
#[error("unsupported upload-pack feature: {0}")]
Unsupported(&'static str),
#[error("upload-pack reported an error: {0:?}")]
Remote(Vec<u8>),
#[error("unadvertised want {0}")]
Unadvertised(ObjectId),
#[error("fetch limit exceeded: {0}")]
Limit(&'static str),
#[error("fetch cancelled")]
Cancelled,
#[error("transport deadline expired")]
Deadline,
#[error("received pack")]
Pack(#[from] crate::ObjectReadError),
#[error("local pack construction")]
PackWrite(#[source] crate::PackWriteError),
#[error("local tag peeling")]
Peel(#[source] Box<crate::PeelError>),
#[error("destination object snapshot")]
Destination(#[source] crate::ObjectReadError),
#[error("the remote repository uses {remote} object IDs but this repository uses {local}")]
FormatMismatch {
remote: crate::ObjectFormat,
local: crate::ObjectFormat,
},
#[error("cannot open source repository")]
Source(#[source] Box<crate::OpenError>),
#[error("local fetch dependency {id}")]
LocalRead {
id: ObjectId,
#[source]
source: crate::ObjectReadError,
},
#[error("received pack/index construction")]
Index(#[from] crate::PackWriteError),
#[error("missing reachable object {0}")]
Missing(ObjectId),
#[error("reachable object {0} has the wrong kind")]
Kind(ObjectId),
#[error("reachable commit {id}")]
Commit {
id: ObjectId,
#[source]
source: crate::CommitError,
},
#[error("reachable tree {id}")]
Tree {
id: ObjectId,
#[source]
source: crate::TreeError,
},
#[error("reachable tag {id}")]
Tag {
id: ObjectId,
#[source]
source: crate::TagError,
},
#[error("local upload-pack exited unsuccessfully: {0}")]
Process(std::process::ExitStatus),
#[error("existing pack artifact differs: {0}")]
Existing(std::path::PathBuf),
}
use crate::ObjectId;
pub(crate) fn check_cancelled(cancel: &AtomicBool) -> Result<(), FetchError> {
if cancel.load(Ordering::Relaxed) {
Err(FetchError::Cancelled)
} else {
Ok(())
}
}
#[cfg(test)]
mod tests;
impl From<crate::packet::Error> for FetchError {
fn from(error: crate::packet::Error) -> Self {
match error {
crate::packet::Error::Io(e) => Self::from(e),
crate::packet::Error::Protocol(e) => Self::Protocol(e),
crate::packet::Error::Limit(e) => Self::Limit(e),
crate::packet::Error::Cancelled => Self::Cancelled,
crate::packet::Error::Remote(e) => Self::Remote(e),
}
}
}
impl From<std::io::Error> for FetchError {
fn from(error: std::io::Error) -> Self {
match crate::transport::interruption(&error) {
Some(crate::transport::Interruption::Cancelled) => Self::Cancelled,
Some(crate::transport::Interruption::Deadline) => Self::Deadline,
None => Self::Io(error),
}
}
}
#[cfg(feature = "http")]
impl From<crate::transport::http::HttpError> for FetchError {
fn from(error: crate::transport::http::HttpError) -> Self {
match error {
crate::transport::http::HttpError::Cancelled => Self::Cancelled,
crate::transport::http::HttpError::Deadline => Self::Deadline,
error => Self::Http(error),
}
}
}
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
impl From<crate::transport::ssh::SshError> for FetchError {
fn from(error: crate::transport::ssh::SshError) -> Self {
match error {
crate::transport::ssh::SshError::Cancelled => Self::Cancelled,
crate::transport::ssh::SshError::Deadline => Self::Deadline,
error => Self::Ssh(error),
}
}
}
impl From<crate::edges::Error> for FetchError {
fn from(error: crate::edges::Error) -> Self {
match error {
crate::edges::Error::Commit { id, source } => Self::Commit { id, source },
crate::edges::Error::Tree { id, source } => Self::Tree { id, source },
crate::edges::Error::Tag { id, source } => Self::Tag { id, source },
}
}
}