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
use std::ffi::OsString;
use crate::{Defaults, MagicSignature, SearchMode};
///
#[allow(clippy::empty_docs)]
pub mod from_environment {
/// The error returned by [Defaults::from_environment()](super::Defaults::from_environment()).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
ParseValue(#[from] gix_config_value::Error),
#[error("Glob and no-glob settings are mutually exclusive")]
MixedGlobAndNoGlob,
}
}
impl Defaults {
/// Initialize this instance using information from the environment as
/// [per the official documentation](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables) *(look for `PATHSPECS`)*,
/// calling `var(variable_name)` for each variable that should be obtained.
///
/// Used environment variables are `GIT_GLOB_PATHSPECS`, `GIT_NOGLOB_PATHSPECS`, `GIT_LITERAL_PATHSPECS` and `GIT_ICASE_PATHSPECS`.
/// Note that there are lot of failure modes, and instead of offering lenient parsing, the caller may ignore errors and
/// use other defaults instead.
///
/// ### Deviation
///
/// Instead of failing if `GIT_LITERAL_PATHSPECS` is used with glob globals, we ignore these. Also our implementation allows global
/// `icase` settings in combination with this setting.
pub fn from_environment(var: &mut dyn FnMut(&str) -> Option<OsString>) -> Result<Self, from_environment::Error> {
let mut env_bool = |name: &str| -> Result<Option<bool>, gix_config_value::Error> {
var(name)
.map(|val| gix_config_value::Boolean::try_from(val).map(|b| b.0))
.transpose()
};
let literal = env_bool("GIT_LITERAL_PATHSPECS")?.unwrap_or_default();
let signature = env_bool("GIT_ICASE_PATHSPECS")?
.and_then(|val| val.then_some(MagicSignature::ICASE))
.unwrap_or_default();
if literal {
return Ok(Defaults {
signature,
search_mode: SearchMode::Literal,
literal,
});
}
let glob = env_bool("GIT_GLOB_PATHSPECS")?;
let mut search_mode = glob
.and_then(|glob| glob.then_some(SearchMode::PathAwareGlob))
.unwrap_or_default();
search_mode = env_bool("GIT_NOGLOB_PATHSPECS")?
.map(|no_glob| {
if glob.unwrap_or_default() && no_glob {
Err(from_environment::Error::MixedGlobAndNoGlob)
} else {
Ok(SearchMode::Literal)
}
})
.transpose()?
.unwrap_or(search_mode);
Ok(Defaults {
signature,
search_mode,
literal,
})
}
}