Skip to main content

gix_pathspec/
defaults.rs

1use gix_error::Result;
2use std::ffi::OsString;
3
4use crate::{Defaults, MagicSignature, SearchMode};
5
6impl Defaults {
7    /// Initialize this instance using information from the environment as
8    /// [per the official documentation](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables) *(look for `PATHSPECS`)*,
9    /// calling `var(variable_name)` for each variable that should be obtained.
10    ///
11    /// Used environment variables are `GIT_GLOB_PATHSPECS`, `GIT_NOGLOB_PATHSPECS`, `GIT_LITERAL_PATHSPECS` and `GIT_ICASE_PATHSPECS`.
12    /// Note that there are lot of failure modes, and instead of offering lenient parsing, the caller may ignore errors and
13    /// use other defaults instead.
14    ///
15    /// ### Deviation
16    ///
17    /// Instead of failing if `GIT_LITERAL_PATHSPECS` is used with glob globals, we ignore these. Also our implementation allows global
18    /// `icase` settings in combination with this setting.
19    pub fn from_environment(var: &mut dyn FnMut(&str) -> Option<OsString>) -> Result<Self> {
20        let mut env_bool = |name: &str| -> Result<Option<bool>> {
21            var(name)
22                .map(|val| gix_config_value::Boolean::try_from(val).map(|b| b.0))
23                .transpose()
24        };
25
26        let literal = env_bool("GIT_LITERAL_PATHSPECS")?.unwrap_or_default();
27        let signature = env_bool("GIT_ICASE_PATHSPECS")?
28            .and_then(|val| val.then_some(MagicSignature::ICASE))
29            .unwrap_or_default();
30        if literal {
31            return Ok(Defaults {
32                signature,
33                search_mode: SearchMode::Literal,
34                literal,
35            });
36        }
37        let glob = env_bool("GIT_GLOB_PATHSPECS")?;
38        let mut search_mode = glob
39            .and_then(|glob| glob.then_some(SearchMode::PathAwareGlob))
40            .unwrap_or_default();
41        search_mode = env_bool("GIT_NOGLOB_PATHSPECS")?
42            .map(|no_glob| {
43                if glob.unwrap_or_default() && no_glob {
44                    Err(gix_error::message("Glob and no-glob settings are mutually exclusive").validation_error())
45                } else {
46                    Ok(SearchMode::Literal)
47                }
48            })
49            .transpose()?
50            .unwrap_or(search_mode);
51
52        Ok(Defaults {
53            signature,
54            search_mode,
55            literal,
56        })
57    }
58}