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
|
//! 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 { .. },
) => true,
_ => false,
}
}
}
}
}
|