Skip to main content

gix_config/file/init/
from_env.rs

1use bstr::ByteSlice;
2use gix_error::ExnResult;
3
4use crate::{File, KeyRef, file, file::init};
5
6/// Instantiation from environment variables
7impl File {
8    /// Generates a config from `GIT_CONFIG_*` environment variables or returns `Ok(None)` if no configuration was found.
9    /// See [`git-config`'s documentation] for more information on the environment variables in question.
10    ///
11    /// With `options` configured, it's possible to resolve `include.path` or `includeIf.<condition>.path` directives as well.
12    /// Integer parsing failures for `GIT_CONFIG_COUNT` and key parsing failures for `GIT_CONFIG_KEY_*` include their
13    /// bytes as `input`
14    /// [metadata](gix_error::Exn::metadata()).
15    ///
16    /// [`git-config`'s documentation]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-GITCONFIGCOUNT
17    pub fn from_env(options: init::Options<'_>) -> ExnResult<Option<File>> {
18        use gix_error::{ErrorExt, OptionExt, ResultExt, message, not_found, validation};
19        use std::env;
20        let count: usize = match env::var("GIT_CONFIG_COUNT") {
21            Ok(v) => v.parse::<usize>().or_raise_erased(|| {
22                validation("GIT_CONFIG_COUNT was not a positive integer").with("input", v.into_bytes())
23            })?,
24            Err(_) => return Ok(None),
25        };
26
27        if count == 0 {
28            return Ok(None);
29        }
30
31        let meta = file::Metadata {
32            path: None,
33            source: crate::Source::Env,
34            level: 0,
35            trust: gix_sec::Trust::Full,
36        };
37        let mut config = File::new(meta);
38        for i in 0..count {
39            let key = gix_path::os_string_into_bstring(
40                env::var_os(format!("GIT_CONFIG_KEY_{i}"))
41                    .ok_or_raise_erased(|| not_found(format!("GIT_CONFIG_KEY_{i} was not set")))?,
42            )
43            .or_raise_erased(|| validation(format!("Configuration key at index {i} contained illformed UTF-8")))?;
44            let value = env::var_os(format!("GIT_CONFIG_VALUE_{i}"))
45                .ok_or_raise_erased(|| not_found(format!("GIT_CONFIG_VALUE_{i} was not set")))?;
46            let key = KeyRef::parse_unvalidated(key.as_ref()).ok_or_else(|| {
47                validation(format!("GIT_CONFIG_KEY_{i} was set to an invalid value"))
48                    .with("input", key.as_bstr())
49                    .raise_erased()
50            })?;
51
52            config
53                .section_mut_or_create_new_inner(key.section_name, key.subsection_name)
54                .or_erased()?
55                .push(
56                    key.value_name,
57                    Some(
58                        gix_path::os_str_into_bstr(&value)
59                            .or_raise_erased(|| {
60                                validation(format!("Configuration value at index {i} contained illformed UTF-8"))
61                            })?
62                            .as_bytes()
63                            .into(),
64                    ),
65                )
66                .or_erased()?;
67        }
68
69        let mut buf = Vec::new();
70        init::includes::resolve(&mut config, &mut buf, options)
71            .or_raise_erased(|| message("Could not resolve includes in environment configuration"))?;
72        Ok(Some(config))
73    }
74}