1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! Utilities to handle program arguments and other values of interest.
use std::ffi::{OsStr, OsString};
use crate::bstr::{BString, ByteVec};
/// Returns the name of the agent for identification towards a remote server as statically known when compiling the crate.
/// Suitable for both `git` servers and HTTP servers, and used unless configured otherwise.
///
/// Note that it's meant to be used in conjunction with [`protocol::agent()`][crate::protocol::agent()] which
/// prepends `git/`.
pub fn agent() -> &'static str {
concat!("oxide-", env!("CARGO_PKG_VERSION"))
}
/// Equivalent to `std::env::args_os()`, but with precomposed unicode on `MacOS` and other apple platforms.
#[cfg(not(target_vendor = "apple"))]
pub fn args_os() -> impl Iterator<Item = OsString> {
std::env::args_os()
}
/// Equivalent to `std::env::args_os()`, but with precomposed unicode on MacOS and other apple platforms.
///
/// Note that this ignores `core.precomposeUnicode` as gix-config isn't available yet. It's default enabled in modern git though.
#[cfg(target_vendor = "apple")]
pub fn args_os() -> impl Iterator<Item = OsString> {
use unicode_normalization::UnicodeNormalization;
std::env::args_os().map(|arg| match arg.to_str() {
Some(arg) => arg.nfc().collect::<String>().into(),
None => arg,
})
}
/// Convert the given `input` into a `BString`, useful for usage in `clap`.
pub fn os_str_to_bstring(input: &OsStr) -> Option<BString> {
Vec::from_os_string(input.into()).map(Into::into).ok()
}
/// Utilities to collate errors of common operations into one error type.
///
/// This is useful as this type can present an API to answer common questions, like whether a network request seems to have failed
/// spuriously or if the underlying repository seems to be corrupted.
/// Error collation supports all operations, including opening the repository.
///
/// ### Usage
///
/// The caller may define a function that specifies the result type as `Result<T, gix::env::collate::{operation}::Error>` to collect
/// errors into a well-known error type which provides an API for simple queries.
pub mod collate {
///
pub mod fetch {
/// An error which combines all possible errors when opening a repository, finding remotes and using them to fetch.
///
/// It can be used to detect if the repository is likely be corrupted in some way, or if the fetch failed spuriously
/// and thus can be retried.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error<E: std::error::Error + Send + Sync + 'static = std::convert::Infallible> {
#[error(transparent)]
Open(#[from] crate::open::Error),
#[error(transparent)]
FindExistingReference(#[from] crate::reference::find::existing::Error),
#[error(transparent)]
RemoteInit(#[from] crate::remote::init::Error),
#[error(transparent)]
FindExistingRemote(#[from] crate::remote::find::existing::Error),
#[error(transparent)]
CredentialHelperConfig(#[from] crate::config::credential_helpers::Error),
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
#[error(transparent)]
Connect(#[from] crate::remote::connect::Error),
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
#[error(transparent)]
PrepareFetch(#[from] crate::remote::fetch::prepare::Error),
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
#[error(transparent)]
Fetch(#[from] crate::remote::fetch::Error),
#[error(transparent)]
Other(E),
}
#[cfg(any(feature = "async-network-client", feature = "blocking-network-client"))]
impl<E> crate::protocol::transport::IsSpuriousError for Error<E>
where
E: std::error::Error + Send + Sync + 'static,
{
fn is_spurious(&self) -> bool {
match self {
Error::Open(_)
| Error::CredentialHelperConfig(_)
| Error::RemoteInit(_)
| Error::FindExistingReference(_)
| Error::FindExistingRemote(_)
| Error::Other(_) => false,
Error::Connect(err) => err.is_spurious(),
Error::PrepareFetch(err) => err.is_spurious(),
Error::Fetch(err) => err.is_spurious(),
}
}
}
/// Queries
impl<E> Error<E>
where
E: std::error::Error + Send + Sync + 'static,
{
/// Return true if repository corruption caused the failure.
pub fn is_corrupted(&self) -> bool {
match self {
Error::Open(crate::open::Error::NotARepository { .. } | crate::open::Error::Config(_)) => true,
#[cfg(any(feature = "async-network-client", feature = "blocking-network-client"))]
Error::PrepareFetch(crate::remote::fetch::prepare::Error::RefMap(
// Configuration couldn't be accessed or was incomplete.
crate::remote::ref_map::Error::GatherTransportConfig { .. }
| crate::remote::ref_map::Error::ConfigureCredentials(_),
)) => true,
// Maybe the value of the configuration was corrupted, or a file couldn't be removed.
#[cfg(any(feature = "async-network-client", feature = "blocking-network-client"))]
Error::Fetch(
crate::remote::fetch::Error::PackThreads(_)
| crate::remote::fetch::Error::PackIndexVersion(_)
| crate::remote::fetch::Error::RemovePackKeepFile { .. }
| crate::remote::fetch::Error::Negotiate(_),
) => true,
_ => false,
}
}
}
}
}