Struct git_config::File

source ·
pub struct File<'event> { /* private fields */ }
Expand description

High level git-config reader and writer.

This is the full-featured implementation that can deserialize, serialize, and edit git-config files without loss of whitespace or comments.

‘multivar’ behavior

git is flexible enough to allow users to set a key multiple times in any number of identically named sections. When this is the case, the key is known as a “multivar”. In this case, raw_value() follows the “last one wins”.

Concretely, the following config has a multivar, a, with the values of b, c, and d, while e is a single variable with the value f g h.

[core]
    a = b
    a = c
[core]
    a = d
    e = f g h

Calling methods that fetch or set only one value (such as raw_value()) key a with the above config will fetch d or replace d, since the last valid config key/value pair is a = d:

Filtering

All methods exist in a *_filter(…, filter) version to allow skipping sections by their metadata. That way it’s possible to select values based on their git_sec::Trust for example, or by their location.

Note that the filter may be executed even on sections that don’t contain the key in question, even though the section will have matched the name and subsection_name respectively.

assert_eq!(git_config.raw_value("core", None, "a").unwrap().as_ref(), "d");

Consider the multi variants of the methods instead, if you want to work with all values.

Equality

In order to make it useful, equality will ignore all non-value bearing information, hence compare only sections and their names, as well as all of their values. The ordering matters, of course.

Implementations§

Easy-instantiation of typical non-repository git configuration files with all configuration defaulting to typical values.

Limitations

Note that includeIf conditions in global files will cause failure as the required information to resolve them isn’t present without a repository.

Also note that relevant information to interpolate paths will be obtained from the environment or other source on unix.

Open all global configuration files which involves the following sources:

which excludes repository local configuration, as well as override-configuration from environment variables.

Note that the file might be empty in case no configuration file was found.

Examples found in repository?
src/file/init/comfort.rs (line 128)
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
131
132
133
134
135
136
137
138
139
140
    pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> {
        let (mut local, git_dir) = {
            let source = Source::Local;
            let mut path = dir.into();
            path.push(
                source
                    .storage_location(&mut |n| std::env::var_os(n))
                    .expect("location available for local"),
            );
            let local = Self::from_path_no_includes(&path, source)?;
            path.pop();
            (local, path)
        };

        let worktree = match local.boolean("extensions", None, "worktreeConfig") {
            Some(Ok(worktree_config)) => worktree_config.then(|| {
                let source = Source::Worktree;
                let path = git_dir.join(
                    source
                        .storage_location(&mut |n| std::env::var_os(n))
                        .expect("location available for worktree"),
                );
                Self::from_path_no_includes(path, source)
            }),
            _ => None,
        }
        .transpose()?;

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow(
                path::interpolate::Context {
                    home_dir: home.as_deref(),
                    ..Default::default()
                },
                init::includes::conditional::Context {
                    git_dir: Some(git_dir.as_ref()),
                    branch_name: None,
                },
            ),
            lossy: false,
        };

        let mut globals = Self::from_globals()?;
        globals.resolve_includes(options)?;
        local.resolve_includes(options)?;

        globals.append(local);
        if let Some(mut worktree) = worktree {
            worktree.resolve_includes(options)?;
            globals.append(worktree);
        }
        globals.append(Self::from_environment_overrides()?);

        Ok(globals)
    }

Generates a config from GIT_CONFIG_* environment variables and return a possibly empty File. A typical use of this is to append this configuration to another one with lower precedence to obtain overrides.

See git-config’s documentation for more information on the environment variables in question.

Examples found in repository?
src/file/init/comfort.rs (line 137)
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
131
132
133
134
135
136
137
138
139
140
    pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> {
        let (mut local, git_dir) = {
            let source = Source::Local;
            let mut path = dir.into();
            path.push(
                source
                    .storage_location(&mut |n| std::env::var_os(n))
                    .expect("location available for local"),
            );
            let local = Self::from_path_no_includes(&path, source)?;
            path.pop();
            (local, path)
        };

        let worktree = match local.boolean("extensions", None, "worktreeConfig") {
            Some(Ok(worktree_config)) => worktree_config.then(|| {
                let source = Source::Worktree;
                let path = git_dir.join(
                    source
                        .storage_location(&mut |n| std::env::var_os(n))
                        .expect("location available for worktree"),
                );
                Self::from_path_no_includes(path, source)
            }),
            _ => None,
        }
        .transpose()?;

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow(
                path::interpolate::Context {
                    home_dir: home.as_deref(),
                    ..Default::default()
                },
                init::includes::conditional::Context {
                    git_dir: Some(git_dir.as_ref()),
                    branch_name: None,
                },
            ),
            lossy: false,
        };

        let mut globals = Self::from_globals()?;
        globals.resolve_includes(options)?;
        local.resolve_includes(options)?;

        globals.append(local);
        if let Some(mut worktree) = worktree {
            worktree.resolve_includes(options)?;
            globals.append(worktree);
        }
        globals.append(Self::from_environment_overrides()?);

        Ok(globals)
    }

An easy way to provide complete configuration for a repository.

This configuration type includes the following sources, in order of precedence:

  • globals
  • repository-local by loading dir/config
  • worktree by loading dir/config.worktree
  • environment

Note that dir is the .git dir to load the configuration from, not the configuration file.

Includes will be resolved within limits as some information like the git installation directory is missing to interpolate paths with as well as git repository information like the branch name.

Instantiation from environment variables

Generates a config from GIT_CONFIG_* environment variables or returns Ok(None) if no configuration was found. See git-config’s documentation for more information on the environment variables in question.

With options configured, it’s possible to resolve include.path or includeIf.<condition>.path directives as well.

Examples found in repository?
src/file/init/comfort.rs (line 68)
61
62
63
64
65
66
67
68
69
    pub fn from_environment_overrides() -> Result<File<'static>, init::from_env::Error> {
        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow_without_conditional(home.as_deref()),
            ..Default::default()
        };

        File::from_env(options).map(Option::unwrap_or_default)
    }

Instantiation from one or more paths

Load the single file at path with source without following include directives.

Note that the path will be checked for ownership to derive trust.

Examples found in repository?
src/file/init/comfort.rs (line 94)
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
131
132
133
134
135
136
137
138
139
140
    pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> {
        let (mut local, git_dir) = {
            let source = Source::Local;
            let mut path = dir.into();
            path.push(
                source
                    .storage_location(&mut |n| std::env::var_os(n))
                    .expect("location available for local"),
            );
            let local = Self::from_path_no_includes(&path, source)?;
            path.pop();
            (local, path)
        };

        let worktree = match local.boolean("extensions", None, "worktreeConfig") {
            Some(Ok(worktree_config)) => worktree_config.then(|| {
                let source = Source::Worktree;
                let path = git_dir.join(
                    source
                        .storage_location(&mut |n| std::env::var_os(n))
                        .expect("location available for worktree"),
                );
                Self::from_path_no_includes(path, source)
            }),
            _ => None,
        }
        .transpose()?;

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow(
                path::interpolate::Context {
                    home_dir: home.as_deref(),
                    ..Default::default()
                },
                init::includes::conditional::Context {
                    git_dir: Some(git_dir.as_ref()),
                    branch_name: None,
                },
            ),
            lossy: false,
        };

        let mut globals = Self::from_globals()?;
        globals.resolve_includes(options)?;
        local.resolve_includes(options)?;

        globals.append(local);
        if let Some(mut worktree) = worktree {
            worktree.resolve_includes(options)?;
            globals.append(worktree);
        }
        globals.append(Self::from_environment_overrides()?);

        Ok(globals)
    }

Constructs a git-config file from the provided metadata, which must include a path to read from or be ignored. Returns Ok(None) if there was not a single input path provided, which is a possibility due to Metadata::path being an Option. If an input path doesn’t exist, the entire operation will abort. See from_paths_metadata_buf() for a more powerful version of this method.

Examples found in repository?
src/file/init/comfort.rs (line 51)
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
    pub fn from_globals() -> Result<File<'static>, init::from_paths::Error> {
        let metas = [source::Kind::System, source::Kind::Global]
            .iter()
            .flat_map(|kind| kind.sources())
            .filter_map(|source| {
                let path = source
                    .storage_location(&mut |name| std::env::var_os(name))
                    .and_then(|p| p.is_file().then(|| p))
                    .map(|p| p.into_owned());

                Metadata {
                    path,
                    source: *source,
                    level: 0,
                    trust: git_sec::Trust::Full,
                }
                .into()
            });

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow_without_conditional(home.as_deref()),
            ..Default::default()
        };
        File::from_paths_metadata(metas, options).map(Option::unwrap_or_default)
    }

Like from_paths_metadata(), but will use buf to temporarily store the config file contents for parsing instead of allocating an own buffer.

If err_on_nonexisting_paths is false, instead of aborting with error, we will continue to the next path instead.

Examples found in repository?
src/file/init/from_paths.rs (line 48)
42
43
44
45
46
47
48
49
    pub fn from_paths_metadata(
        path_meta: impl IntoIterator<Item = impl Into<Metadata>>,
        options: Options<'_>,
    ) -> Result<Option<Self>, Error> {
        let mut buf = Vec::with_capacity(512);
        let err_on_nonexisting_paths = true;
        Self::from_paths_metadata_buf(path_meta, &mut buf, err_on_nonexisting_paths, options)
    }

Return an empty File with the given meta-data to be attached to all new sections.

Examples found in repository?
src/file/init/mod.rs (line 52)
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    pub fn from_parse_events_no_includes(
        parse::Events { frontmatter, sections }: parse::Events<'a>,
        meta: impl Into<OwnShared<Metadata>>,
    ) -> Self {
        let meta = meta.into();
        let mut this = File::new(OwnShared::clone(&meta));

        this.frontmatter_events = frontmatter;

        for section in sections {
            this.push_section_internal(crate::file::Section {
                header: section.header,
                body: section::Body(section.events),
                meta: OwnShared::clone(&meta),
                id: Default::default(),
            });
        }

        this
    }
More examples
Hide additional examples
src/file/init/from_env.rs (line 56)
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
    pub fn from_env(options: init::Options<'_>) -> Result<Option<File<'static>>, Error> {
        use std::env;
        let count: usize = match env::var("GIT_CONFIG_COUNT") {
            Ok(v) => v.parse().map_err(|_| Error::InvalidConfigCount { input: v })?,
            Err(_) => return Ok(None),
        };

        if count == 0 {
            return Ok(None);
        }

        let meta = file::Metadata {
            path: None,
            source: crate::Source::Env,
            level: 0,
            trust: git_sec::Trust::Full,
        };
        let mut config = File::new(meta);
        for i in 0..count {
            let key = git_path::os_string_into_bstring(
                env::var_os(format!("GIT_CONFIG_KEY_{}", i)).ok_or(Error::InvalidKeyId { key_id: i })?,
            )
            .map_err(|_| Error::IllformedUtf8 { index: i, kind: "key" })?;
            let value = env::var_os(format!("GIT_CONFIG_VALUE_{}", i)).ok_or(Error::InvalidValueId { value_id: i })?;
            let key = parse::key(<_ as AsRef<BStr>>::as_ref(&key)).ok_or_else(|| Error::InvalidKeyValue {
                key_id: i,
                key_val: key.to_string(),
            })?;

            config
                .section_mut_or_create_new(key.section_name, key.subsection_name)?
                .push(
                    section::Key::try_from(key.value_name.to_owned())?,
                    Some(
                        git_path::os_str_into_bstr(&value)
                            .map_err(|_| Error::IllformedUtf8 {
                                index: i,
                                kind: "value",
                            })?
                            .as_ref()
                            .into(),
                    ),
                );
        }

        let mut buf = Vec::new();
        init::includes::resolve(&mut config, &mut buf, options)?;
        Ok(Some(config))
    }

Instantiate a new File from given input, associating each section and their values with meta-data, while respecting options.

Instantiate a new File from given events, associating each section and their values with meta-data.

Examples found in repository?
src/file/impls.rs (line 18)
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
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        parse::Events::from_bytes_owned(s.as_bytes(), None)
            .map(|events| File::from_parse_events_no_includes(events, Metadata::api()))
    }
}

impl<'a> TryFrom<&'a str> for File<'a> {
    type Error = parse::Error;

    /// Convenience constructor. Attempts to parse the provided string into a
    /// [`File`]. See [`Events::from_str()`][crate::parse::Events::from_str()] for more information.
    fn try_from(s: &'a str) -> Result<File<'a>, Self::Error> {
        parse::Events::from_str(s).map(|events| Self::from_parse_events_no_includes(events, Metadata::api()))
    }
}

impl<'a> TryFrom<&'a BStr> for File<'a> {
    type Error = parse::Error;

    /// Convenience constructor. Attempts to parse the provided byte string into
    /// a [`File`]. See [`Events::from_bytes()`][parse::Events::from_bytes()] for more information.
    fn try_from(value: &'a BStr) -> Result<File<'a>, Self::Error> {
        parse::Events::from_bytes(value, None)
            .map(|events| Self::from_parse_events_no_includes(events, Metadata::api()))
    }
More examples
Hide additional examples
src/file/init/mod.rs (lines 39-42)
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
    pub fn from_bytes_no_includes(
        input: &'a [u8],
        meta: impl Into<OwnShared<Metadata>>,
        options: Options<'_>,
    ) -> Result<Self, Error> {
        let meta = meta.into();
        Ok(Self::from_parse_events_no_includes(
            parse::Events::from_bytes(input, options.to_event_filter())?,
            meta,
        ))
    }

    /// Instantiate a new `File` from given `events`, associating each section and their values with
    /// `meta`-data.
    pub fn from_parse_events_no_includes(
        parse::Events { frontmatter, sections }: parse::Events<'a>,
        meta: impl Into<OwnShared<Metadata>>,
    ) -> Self {
        let meta = meta.into();
        let mut this = File::new(OwnShared::clone(&meta));

        this.frontmatter_events = frontmatter;

        for section in sections {
            this.push_section_internal(crate::file::Section {
                header: section.header,
                body: section::Body(section.events),
                meta: OwnShared::clone(&meta),
                id: Default::default(),
            });
        }

        this
    }
}

impl File<'static> {
    /// Instantiate a new fully-owned `File` from given `input` (later reused as buffer when resolving includes),
    /// associating each section and their values with `meta`-data, while respecting `options`, and
    /// following includes as configured there.
    pub fn from_bytes_owned(
        input_and_buf: &mut Vec<u8>,
        meta: impl Into<OwnShared<Metadata>>,
        options: Options<'_>,
    ) -> Result<Self, Error> {
        let mut config = Self::from_parse_events_no_includes(
            parse::Events::from_bytes_owned(input_and_buf, options.to_event_filter()).map_err(Error::from)?,
            meta,
        );

        includes::resolve(&mut config, input_and_buf, options).map_err(Error::from)?;
        Ok(config)
    }

Instantiate a new fully-owned File from given input (later reused as buffer when resolving includes), associating each section and their values with meta-data, while respecting options, and following includes as configured there.

Examples found in repository?
src/file/init/from_paths.rs (lines 30-34)
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
    pub fn from_path_no_includes(path: impl Into<std::path::PathBuf>, source: crate::Source) -> Result<Self, Error> {
        let path = path.into();
        let trust = git_sec::Trust::from_path_ownership(&path)?;

        let mut buf = Vec::new();
        std::io::copy(&mut std::fs::File::open(&path)?, &mut buf)?;

        Ok(File::from_bytes_owned(
            &mut buf,
            Metadata::from(source).at(path).with(trust),
            Default::default(),
        )?)
    }

    /// Constructs a `git-config` file from the provided metadata, which must include a path to read from or be ignored.
    /// Returns `Ok(None)` if there was not a single input path provided, which is a possibility due to
    /// [`Metadata::path`] being an `Option`.
    /// If an input path doesn't exist, the entire operation will abort. See [`from_paths_metadata_buf()`][Self::from_paths_metadata_buf()]
    /// for a more powerful version of this method.
    pub fn from_paths_metadata(
        path_meta: impl IntoIterator<Item = impl Into<Metadata>>,
        options: Options<'_>,
    ) -> Result<Option<Self>, Error> {
        let mut buf = Vec::with_capacity(512);
        let err_on_nonexisting_paths = true;
        Self::from_paths_metadata_buf(path_meta, &mut buf, err_on_nonexisting_paths, options)
    }

    /// Like [from_paths_metadata()][Self::from_paths_metadata()], but will use `buf` to temporarily store the config file
    /// contents for parsing instead of allocating an own buffer.
    ///
    /// If `err_on_nonexisting_paths` is false, instead of aborting with error, we will continue to the next path instead.
    pub fn from_paths_metadata_buf(
        path_meta: impl IntoIterator<Item = impl Into<Metadata>>,
        buf: &mut Vec<u8>,
        err_on_non_existing_paths: bool,
        options: Options<'_>,
    ) -> Result<Option<Self>, Error> {
        let mut target = None;
        let mut seen = BTreeSet::default();
        for (path, mut meta) in path_meta.into_iter().filter_map(|meta| {
            let mut meta = meta.into();
            meta.path.take().map(|p| (p, meta))
        }) {
            if !seen.insert(path.clone()) {
                continue;
            }

            buf.clear();
            std::io::copy(
                &mut match std::fs::File::open(&path) {
                    Ok(f) => f,
                    Err(err) if !err_on_non_existing_paths && err.kind() == std::io::ErrorKind::NotFound => continue,
                    Err(err) => return Err(err.into()),
                },
                buf,
            )?;
            meta.path = Some(path);

            let config = Self::from_bytes_owned(buf, meta, options)?;
            match &mut target {
                None => {
                    target = Some(config);
                }
                Some(target) => {
                    target.append(config);
                }
            }
        }
        Ok(target)
    }
More examples
Hide additional examples
src/file/includes/mod.rs (line 115)
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
fn append_followed_includes_recursively(
    section_ids_and_include_paths: Vec<(SectionId, crate::Path<'_>)>,
    target_config: &mut File<'static>,
    depth: u8,
    options: init::Options<'_>,
    buf: &mut Vec<u8>,
) -> Result<(), Error> {
    for (section_id, config_path) in section_ids_and_include_paths {
        let meta = OwnShared::clone(&target_config.sections[&section_id].meta);
        let target_config_path = meta.path.as_deref();
        let config_path = match resolve_path(config_path, target_config_path, options.includes)? {
            Some(p) => p,
            None => continue,
        };
        if !config_path.is_file() {
            continue;
        }

        buf.clear();
        std::io::copy(&mut std::fs::File::open(&config_path)?, buf)?;
        let config_meta = Metadata {
            path: Some(config_path),
            trust: meta.trust,
            level: meta.level + 1,
            source: meta.source,
        };
        let no_follow_options = init::Options {
            includes: includes::Options::no_follow(),
            ..options
        };

        let mut include_config =
            File::from_bytes_owned(buf, config_meta, no_follow_options).map_err(|err| match err {
                init::Error::Parse(err) => Error::Parse(err),
                init::Error::Interpolate(err) => Error::Interpolate(err),
                init::Error::Includes(_) => unreachable!("BUG: {:?} not possible due to no-follow options", err),
            })?;
        resolve_includes_recursive(&mut include_config, depth + 1, buf, options)?;

        target_config.append_or_insert(include_config, Some(section_id));
    }
    Ok(())
}

Comfortable API for accessing values

Like value(), but returning None if the string wasn’t found.

As strings perform no conversions, this will never fail.

Like string(), but suitable for statically known keys like remote.origin.url.

Like string(), but the section containing the returned value must pass filter as well.

Examples found in repository?
src/file/access/comfort.rs (line 18)
12
13
14
15
16
17
18
19
    pub fn string(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Cow<'_, BStr>> {
        self.string_filter(section_name, subsection_name, key, &mut |_| true)
    }

Like string_filter(), but suitable for statically known keys like remote.origin.url.

Examples found in repository?
src/file/access/comfort.rs (line 23)
22
23
24
    pub fn string_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Cow<'_, BStr>> {
        self.string_filter_by_key(key, &mut |_| true)
    }

Like value(), but returning None if the path wasn’t found.

Note that this path is not vetted and should only point to resources which can’t be used to pose a security risk. Prefer using path_filter() instead.

As paths perform no conversions, this will never fail.

Like path(), but suitable for statically known keys like remote.origin.url.

Like path(), but the section containing the returned value must pass filter as well.

This should be the preferred way of accessing paths as those from untrusted locations can be

As paths perform no conversions, this will never fail.

Examples found in repository?
src/file/access/comfort.rs (line 60)
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
    pub fn path(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<crate::Path<'_>> {
        self.path_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`path()`][File::path()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn path_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<crate::Path<'_>> {
        self.path_filter_by_key(key, &mut |_| true)
    }

    /// Like [`path()`][File::path()], but the section containing the returned value must pass `filter` as well.
    ///
    /// This should be the preferred way of accessing paths as those from untrusted
    /// locations can be
    ///
    /// As paths perform no conversions, this will never fail.
    pub fn path_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<crate::Path<'_>> {
        self.raw_value_filter(section_name, subsection_name, key, filter)
            .ok()
            .map(crate::Path::from)
    }

    /// Like [`path_filter()`][File::path_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn path_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<crate::Path<'_>> {
        let key = crate::parse::key(key)?;
        self.path_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

Like path_filter(), but suitable for statically known keys like remote.origin.url.

Examples found in repository?
src/file/access/comfort.rs (line 65)
64
65
66
    pub fn path_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<crate::Path<'_>> {
        self.path_filter_by_key(key, &mut |_| true)
    }

Like value(), but returning None if the boolean value wasn’t found.

Examples found in repository?
src/file/init/comfort.rs (line 99)
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
131
132
133
134
135
136
137
138
139
140
    pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> {
        let (mut local, git_dir) = {
            let source = Source::Local;
            let mut path = dir.into();
            path.push(
                source
                    .storage_location(&mut |n| std::env::var_os(n))
                    .expect("location available for local"),
            );
            let local = Self::from_path_no_includes(&path, source)?;
            path.pop();
            (local, path)
        };

        let worktree = match local.boolean("extensions", None, "worktreeConfig") {
            Some(Ok(worktree_config)) => worktree_config.then(|| {
                let source = Source::Worktree;
                let path = git_dir.join(
                    source
                        .storage_location(&mut |n| std::env::var_os(n))
                        .expect("location available for worktree"),
                );
                Self::from_path_no_includes(path, source)
            }),
            _ => None,
        }
        .transpose()?;

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow(
                path::interpolate::Context {
                    home_dir: home.as_deref(),
                    ..Default::default()
                },
                init::includes::conditional::Context {
                    git_dir: Some(git_dir.as_ref()),
                    branch_name: None,
                },
            ),
            lossy: false,
        };

        let mut globals = Self::from_globals()?;
        globals.resolve_includes(options)?;
        local.resolve_includes(options)?;

        globals.append(local);
        if let Some(mut worktree) = worktree {
            worktree.resolve_includes(options)?;
            globals.append(worktree);
        }
        globals.append(Self::from_environment_overrides()?);

        Ok(globals)
    }

Like boolean(), but suitable for statically known keys like remote.origin.url.

Like boolean(), but the section containing the returned value must pass filter as well.

Examples found in repository?
src/file/access/comfort.rs (line 103)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    pub fn boolean(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Result<bool, value::Error>> {
        self.boolean_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`boolean()`][File::boolean()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn boolean_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<bool, value::Error>> {
        self.boolean_filter_by_key(key, &mut |_| true)
    }

    /// Like [`boolean()`][File::boolean()], but the section containing the returned value must pass `filter` as well.
    pub fn boolean_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<bool, value::Error>> {
        let section_name = section_name.as_ref();
        let section_ids = self
            .section_ids_by_name_and_subname(section_name, subsection_name)
            .ok()?;
        let key = key.as_ref();
        for section_id in section_ids.rev() {
            let section = self.sections.get(&section_id).expect("known section id");
            if !filter(section.meta()) {
                continue;
            }
            match section.value_implicit(key) {
                Some(Some(v)) => return Some(crate::Boolean::try_from(v).map(|b| b.into())),
                Some(None) => return Some(Ok(true)),
                None => continue,
            }
        }
        None
    }

    /// Like [`boolean_filter()`][File::boolean_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn boolean_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<bool, value::Error>> {
        let key = crate::parse::key(key)?;
        self.boolean_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

Like boolean_filter(), but suitable for statically known keys like remote.origin.url.

Examples found in repository?
src/file/access/comfort.rs (line 108)
107
108
109
    pub fn boolean_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<bool, value::Error>> {
        self.boolean_filter_by_key(key, &mut |_| true)
    }

Like value(), but returning an Option if the integer wasn’t found.

Like integer(), but suitable for statically known keys like remote.origin.url.

Like integer(), but the section containing the returned value must pass filter as well.

Examples found in repository?
src/file/access/comfort.rs (line 155)
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
    pub fn integer(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Result<i64, value::Error>> {
        self.integer_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`integer()`][File::integer()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn integer_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<i64, value::Error>> {
        self.integer_filter_by_key(key, &mut |_| true)
    }

    /// Like [`integer()`][File::integer()], but the section containing the returned value must pass `filter` as well.
    pub fn integer_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<i64, value::Error>> {
        let int = self.raw_value_filter(section_name, subsection_name, key, filter).ok()?;
        Some(crate::Integer::try_from(int.as_ref()).and_then(|b| {
            b.to_decimal()
                .ok_or_else(|| value::Error::new("Integer overflow", int.into_owned()))
        }))
    }

    /// Like [`integer_filter()`][File::integer_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn integer_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<i64, value::Error>> {
        let key = crate::parse::key(key)?;
        self.integer_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

Like integer_filter(), but suitable for statically known keys like remote.origin.url.

Examples found in repository?
src/file/access/comfort.rs (line 160)
159
160
161
    pub fn integer_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<i64, value::Error>> {
        self.integer_filter_by_key(key, &mut |_| true)
    }

Similar to values(…) but returning strings if at least one of them was found.

Examples found in repository?
src/file/access/comfort.rs (line 201)
199
200
201
202
    pub fn strings_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Vec<Cow<'_, BStr>>> {
        let key = crate::parse::key(key)?;
        self.strings(key.section_name, key.subsection_name, key.value_name)
    }

Like strings(), but suitable for statically known keys like remote.origin.url.

Similar to strings(…), but all values are in sections that passed filter.

Examples found in repository?
src/file/access/comfort.rs (line 222)
216
217
218
219
220
221
222
223
    pub fn strings_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Vec<Cow<'_, BStr>>> {
        let key = crate::parse::key(key)?;
        self.strings_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

Like strings_filter(), but suitable for statically known keys like remote.origin.url.

Similar to values(…) but returning integers if at least one of them was found and if none of them overflows.

Like integers(), but suitable for statically known keys like remote.origin.url.

Similar to integers(…) but all integers are in sections that passed filter and that are not overflowing.

Examples found in repository?
src/file/access/comfort.rs (line 233)
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    pub fn integers(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Result<Vec<i64>, value::Error>> {
        self.integers_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`integers()`][File::integers()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn integers_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<Vec<i64>, value::Error>> {
        self.integers_filter_by_key(key, &mut |_| true)
    }

    /// Similar to [`integers(…)`][File::integers()] but all integers are in sections that passed `filter`
    /// and that are not overflowing.
    pub fn integers_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<Vec<i64>, value::Error>> {
        self.raw_values_filter(section_name, subsection_name, key, filter)
            .ok()
            .map(|values| {
                values
                    .into_iter()
                    .map(|v| {
                        crate::Integer::try_from(v.as_ref()).and_then(|int| {
                            int.to_decimal()
                                .ok_or_else(|| value::Error::new("Integer overflow", v.into_owned()))
                        })
                    })
                    .collect()
            })
    }

    /// Like [`integers_filter()`][File::integers_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn integers_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<Vec<i64>, value::Error>> {
        let key = crate::parse::key(key)?;
        self.integers_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

Like integers_filter(), but suitable for statically known keys like remote.origin.url.

Examples found in repository?
src/file/access/comfort.rs (line 238)
237
238
239
    pub fn integers_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<Vec<i64>, value::Error>> {
        self.integers_filter_by_key(key, &mut |_| true)
    }

Mutating low-level access methods.

Returns the last mutable section with a given name and optional subsection_name, if it exists.

Examples found in repository?
src/file/access/mutate.rs (line 40)
35
36
37
38
39
40
41
    pub fn section_mut_by_key<'a, 'b>(
        &'a mut self,
        key: impl Into<&'b BStr>,
    ) -> Result<SectionMut<'a, 'event>, lookup::existing::Error> {
        let key = section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?;
        self.section_mut(key.section_name, key.subsection_name)
    }

Returns the last found mutable section with a given key, identifying the name and subsection name like core or remote.origin.

Return the mutable section identified by id, or None if it didn’t exist.

Note that id is stable across deletions and insertions.

Returns the last mutable section with a given name and optional subsection_name, if it exists, or create a new section.

Examples found in repository?
src/file/init/from_env.rs (line 69)
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
    pub fn from_env(options: init::Options<'_>) -> Result<Option<File<'static>>, Error> {
        use std::env;
        let count: usize = match env::var("GIT_CONFIG_COUNT") {
            Ok(v) => v.parse().map_err(|_| Error::InvalidConfigCount { input: v })?,
            Err(_) => return Ok(None),
        };

        if count == 0 {
            return Ok(None);
        }

        let meta = file::Metadata {
            path: None,
            source: crate::Source::Env,
            level: 0,
            trust: git_sec::Trust::Full,
        };
        let mut config = File::new(meta);
        for i in 0..count {
            let key = git_path::os_string_into_bstring(
                env::var_os(format!("GIT_CONFIG_KEY_{}", i)).ok_or(Error::InvalidKeyId { key_id: i })?,
            )
            .map_err(|_| Error::IllformedUtf8 { index: i, kind: "key" })?;
            let value = env::var_os(format!("GIT_CONFIG_VALUE_{}", i)).ok_or(Error::InvalidValueId { value_id: i })?;
            let key = parse::key(<_ as AsRef<BStr>>::as_ref(&key)).ok_or_else(|| Error::InvalidKeyValue {
                key_id: i,
                key_val: key.to_string(),
            })?;

            config
                .section_mut_or_create_new(key.section_name, key.subsection_name)?
                .push(
                    section::Key::try_from(key.value_name.to_owned())?,
                    Some(
                        git_path::os_str_into_bstr(&value)
                            .map_err(|_| Error::IllformedUtf8 {
                                index: i,
                                kind: "value",
                            })?
                            .as_ref()
                            .into(),
                    ),
                );
        }

        let mut buf = Vec::new();
        init::includes::resolve(&mut config, &mut buf, options)?;
        Ok(Some(config))
    }

Returns an mutable section with a given name and optional subsection_name, if it exists and passes filter, or create a new section.

Examples found in repository?
src/file/access/mutate.rs (line 57)
52
53
54
55
56
57
58
    pub fn section_mut_or_create_new<'a>(
        &'a mut self,
        name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
    ) -> Result<SectionMut<'a, 'event>, section::header::Error> {
        self.section_mut_or_create_new_filter(name, subsection_name, &mut |_| true)
    }
More examples
Hide additional examples
src/file/access/raw.rs (line 434)
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
    pub fn set_raw_value_filter<'b, Key, E>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: Key,
        new_value: impl Into<&'b BStr>,
        filter: &mut MetadataFilter,
    ) -> Result<Option<Cow<'event, BStr>>, crate::file::set_raw_value::Error>
    where
        Key: TryInto<section::Key<'event>, Error = E>,
        section::key::Error: From<E>,
    {
        let mut section = self.section_mut_or_create_new_filter(section_name, subsection_name, filter)?;
        Ok(section.set(key.try_into().map_err(section::key::Error::from)?, new_value))
    }

Returns the last found mutable section with a given name and optional subsection_name, that matches filter, if it exists.

If there are sections matching section_name and subsection_name but the filter rejects all of them, Ok(None) is returned.

Examples found in repository?
src/file/access/mutate.rs (line 119)
113
114
115
116
117
118
119
120
    pub fn section_mut_filter_by_key<'a, 'b>(
        &'a mut self,
        key: impl Into<&'b BStr>,
        filter: &mut MetadataFilter,
    ) -> Result<Option<file::SectionMut<'a, 'event>>, lookup::existing::Error> {
        let key = section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?;
        self.section_mut_filter(key.section_name, key.subsection_name, filter)
    }

Like section_mut_filter(), but identifies the with a given key, like core or remote.origin.

Adds a new section. If a subsection name was provided, then the generated header will use the modern subsection syntax. Returns a reference to the new section for immediate editing.

Examples

Creating a new empty section:

let mut git_config = git_config::File::default();
let section = git_config.new_section("hello", Some(Cow::Borrowed("world".into())))?;
let nl = section.newline().to_owned();
assert_eq!(git_config.to_string(), format!("[hello \"world\"]{nl}"));

Creating a new empty section and adding values to it:

let mut git_config = git_config::File::default();
let mut section = git_config.new_section("hello", Some(Cow::Borrowed("world".into())))?;
section.push(section::Key::try_from("a")?, Some("b".into()));
let nl = section.newline().to_owned();
assert_eq!(git_config.to_string(), format!("[hello \"world\"]{nl}\ta = b{nl}"));
let _section = git_config.new_section("core", None);
assert_eq!(git_config.to_string(), format!("[hello \"world\"]{nl}\ta = b{nl}[core]{nl}"));
Examples found in repository?
src/file/access/mutate.rs (line 86)
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
    pub fn section_mut_or_create_new_filter<'a>(
        &'a mut self,
        name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        filter: &mut MetadataFilter,
    ) -> Result<SectionMut<'a, 'event>, section::header::Error> {
        let name = name.as_ref();
        match self
            .section_ids_by_name_and_subname(name.as_ref(), subsection_name)
            .ok()
            .and_then(|it| {
                it.rev().find(|id| {
                    let s = &self.sections[id];
                    filter(s.meta())
                })
            }) {
            Some(id) => {
                let nl = self.detect_newline_style_smallvec();
                Ok(self
                    .sections
                    .get_mut(&id)
                    .expect("BUG: Section did not have id from lookup")
                    .to_mut(nl))
            }
            None => self.new_section(name.to_owned(), subsection_name.map(|n| Cow::Owned(n.to_owned()))),
        }
    }

Removes the section with name and subsection_name , returning it if there was a matching section. If multiple sections have the same name, then the last one is returned. Note that later sections with the same name have precedent over earlier ones.

Examples

Creating and removing a section:

let mut git_config = git_config::File::try_from(
r#"[hello "world"]
    some-value = 4
"#)?;

let section = git_config.remove_section("hello", Some("world".into()));
assert_eq!(git_config.to_string(), "");

Precedence example for removing sections with the same name:

let mut git_config = git_config::File::try_from(
r#"[hello "world"]
    some-value = 4
[hello "world"]
    some-value = 5
"#)?;

let section = git_config.remove_section("hello", Some("world".into()));
assert_eq!(git_config.to_string(), "[hello \"world\"]\n    some-value = 4\n");

Remove the section identified by id if it exists and return it, or return None if no such section was present.

Note that section ids are unambiguous even in the face of removals and additions of sections.

Examples found in repository?
src/file/access/mutate.rs (line 217)
207
208
209
210
211
212
213
214
215
216
217
218
    pub fn remove_section<'a>(
        &mut self,
        name: &str,
        subsection_name: impl Into<Option<&'a BStr>>,
    ) -> Option<file::Section<'event>> {
        let id = self
            .section_ids_by_name_and_subname(name, subsection_name.into())
            .ok()?
            .rev()
            .next()?;
        self.remove_section_by_id(id)
    }

Removes the section with name and subsection_name that passed filter, returning the removed section if at least one section matched the filter. If multiple sections have the same name, then the last one is returned. Note that later sections with the same name have precedent over earlier ones.

Adds the provided section to the config, returning a mutable reference to it for immediate editing. Note that its meta-data will remain as is.

Renames the section with name and subsection_name, modifying the last matching section to use new_name and new_subsection_name.

Renames the section with name and subsection_name, modifying the last matching section that also passes filter to use new_name and new_subsection_name.

Note that the otherwise unused lookup::existing::Error::KeyMissing variant is used to indicate that the filter rejected all candidates, leading to no section being renamed after all.

Append another File to the end of ourselves, without losing any information.

Examples found in repository?
src/file/init/from_paths.rs (line 88)
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
    pub fn from_paths_metadata_buf(
        path_meta: impl IntoIterator<Item = impl Into<Metadata>>,
        buf: &mut Vec<u8>,
        err_on_non_existing_paths: bool,
        options: Options<'_>,
    ) -> Result<Option<Self>, Error> {
        let mut target = None;
        let mut seen = BTreeSet::default();
        for (path, mut meta) in path_meta.into_iter().filter_map(|meta| {
            let mut meta = meta.into();
            meta.path.take().map(|p| (p, meta))
        }) {
            if !seen.insert(path.clone()) {
                continue;
            }

            buf.clear();
            std::io::copy(
                &mut match std::fs::File::open(&path) {
                    Ok(f) => f,
                    Err(err) if !err_on_non_existing_paths && err.kind() == std::io::ErrorKind::NotFound => continue,
                    Err(err) => return Err(err.into()),
                },
                buf,
            )?;
            meta.path = Some(path);

            let config = Self::from_bytes_owned(buf, meta, options)?;
            match &mut target {
                None => {
                    target = Some(config);
                }
                Some(target) => {
                    target.append(config);
                }
            }
        }
        Ok(target)
    }
More examples
Hide additional examples
src/file/init/comfort.rs (line 132)
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
131
132
133
134
135
136
137
138
139
140
    pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> {
        let (mut local, git_dir) = {
            let source = Source::Local;
            let mut path = dir.into();
            path.push(
                source
                    .storage_location(&mut |n| std::env::var_os(n))
                    .expect("location available for local"),
            );
            let local = Self::from_path_no_includes(&path, source)?;
            path.pop();
            (local, path)
        };

        let worktree = match local.boolean("extensions", None, "worktreeConfig") {
            Some(Ok(worktree_config)) => worktree_config.then(|| {
                let source = Source::Worktree;
                let path = git_dir.join(
                    source
                        .storage_location(&mut |n| std::env::var_os(n))
                        .expect("location available for worktree"),
                );
                Self::from_path_no_includes(path, source)
            }),
            _ => None,
        }
        .transpose()?;

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow(
                path::interpolate::Context {
                    home_dir: home.as_deref(),
                    ..Default::default()
                },
                init::includes::conditional::Context {
                    git_dir: Some(git_dir.as_ref()),
                    branch_name: None,
                },
            ),
            lossy: false,
        };

        let mut globals = Self::from_globals()?;
        globals.resolve_includes(options)?;
        local.resolve_includes(options)?;

        globals.append(local);
        if let Some(mut worktree) = worktree {
            worktree.resolve_includes(options)?;
            globals.append(worktree);
        }
        globals.append(Self::from_environment_overrides()?);

        Ok(globals)
    }

Raw value API

These functions are the raw value API, returning normalized byte strings.

Returns an uninterpreted value given a section, an optional subsection and key.

Consider Self::raw_values() if you want to get all values of a multivar instead.

Examples found in repository?
src/file/access/read_only.rs (line 58)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    pub fn value<'a, T: TryFrom<Cow<'a, BStr>>>(
        &'a self,
        section_name: &str,
        subsection_name: Option<&BStr>,
        key: &str,
    ) -> Result<T, lookup::Error<T::Error>> {
        T::try_from(self.raw_value(section_name, subsection_name, key)?).map_err(lookup::Error::FailedConversion)
    }

    /// Like [`value()`][File::value()], but returning an `None` if the value wasn't found at `section[.subsection].key`
    pub fn try_value<'a, T: TryFrom<Cow<'a, BStr>>>(
        &'a self,
        section_name: &str,
        subsection_name: Option<&BStr>,
        key: &str,
    ) -> Option<Result<T, T::Error>> {
        self.raw_value(section_name, subsection_name, key).ok().map(T::try_from)
    }

Returns an uninterpreted value given a section, an optional subsection and key, if it passes the filter.

Consider Self::raw_values() if you want to get all values of a multivar instead.

Examples found in repository?
src/file/access/raw.rs (line 28)
22
23
24
25
26
27
28
29
    pub fn raw_value(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Result<Cow<'_, BStr>, lookup::existing::Error> {
        self.raw_value_filter(section_name, subsection_name, key, &mut |_| true)
    }
More examples
Hide additional examples
src/file/access/comfort.rs (line 34)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    pub fn string_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Cow<'_, BStr>> {
        self.raw_value_filter(section_name, subsection_name, key, filter).ok()
    }

    /// Like [`string_filter()`][File::string_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn string_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Cow<'_, BStr>> {
        let key = crate::parse::key(key)?;
        self.raw_value_filter(key.section_name, key.subsection_name, key.value_name, filter)
            .ok()
    }

    /// Like [`value()`][File::value()], but returning `None` if the path wasn't found.
    ///
    /// Note that this path is not vetted and should only point to resources which can't be used
    /// to pose a security risk. Prefer using [`path_filter()`][File::path_filter()] instead.
    ///
    /// As paths perform no conversions, this will never fail.
    pub fn path(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<crate::Path<'_>> {
        self.path_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`path()`][File::path()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn path_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<crate::Path<'_>> {
        self.path_filter_by_key(key, &mut |_| true)
    }

    /// Like [`path()`][File::path()], but the section containing the returned value must pass `filter` as well.
    ///
    /// This should be the preferred way of accessing paths as those from untrusted
    /// locations can be
    ///
    /// As paths perform no conversions, this will never fail.
    pub fn path_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<crate::Path<'_>> {
        self.raw_value_filter(section_name, subsection_name, key, filter)
            .ok()
            .map(crate::Path::from)
    }

    /// Like [`path_filter()`][File::path_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn path_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<crate::Path<'_>> {
        let key = crate::parse::key(key)?;
        self.path_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

    /// Like [`value()`][File::value()], but returning `None` if the boolean value wasn't found.
    pub fn boolean(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Result<bool, value::Error>> {
        self.boolean_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`boolean()`][File::boolean()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn boolean_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<bool, value::Error>> {
        self.boolean_filter_by_key(key, &mut |_| true)
    }

    /// Like [`boolean()`][File::boolean()], but the section containing the returned value must pass `filter` as well.
    pub fn boolean_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<bool, value::Error>> {
        let section_name = section_name.as_ref();
        let section_ids = self
            .section_ids_by_name_and_subname(section_name, subsection_name)
            .ok()?;
        let key = key.as_ref();
        for section_id in section_ids.rev() {
            let section = self.sections.get(&section_id).expect("known section id");
            if !filter(section.meta()) {
                continue;
            }
            match section.value_implicit(key) {
                Some(Some(v)) => return Some(crate::Boolean::try_from(v).map(|b| b.into())),
                Some(None) => return Some(Ok(true)),
                None => continue,
            }
        }
        None
    }

    /// Like [`boolean_filter()`][File::boolean_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn boolean_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<bool, value::Error>> {
        let key = crate::parse::key(key)?;
        self.boolean_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

    /// Like [`value()`][File::value()], but returning an `Option` if the integer wasn't found.
    pub fn integer(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Result<i64, value::Error>> {
        self.integer_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`integer()`][File::integer()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn integer_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<i64, value::Error>> {
        self.integer_filter_by_key(key, &mut |_| true)
    }

    /// Like [`integer()`][File::integer()], but the section containing the returned value must pass `filter` as well.
    pub fn integer_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<i64, value::Error>> {
        let int = self.raw_value_filter(section_name, subsection_name, key, filter).ok()?;
        Some(crate::Integer::try_from(int.as_ref()).and_then(|b| {
            b.to_decimal()
                .ok_or_else(|| value::Error::new("Integer overflow", int.into_owned()))
        }))
    }

Returns a mutable reference to an uninterpreted value given a section, an optional subsection and key.

Consider Self::raw_values_mut if you want to get mutable references to all values of a multivar instead.

Examples found in repository?
src/file/access/raw.rs (line 375)
368
369
370
371
372
373
374
375
376
377
    pub fn set_existing_raw_value<'b>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        new_value: impl Into<&'b BStr>,
    ) -> Result<(), lookup::existing::Error> {
        self.raw_value_mut(section_name, subsection_name, key.as_ref())
            .map(|mut entry| entry.set(new_value))
    }

Returns a mutable reference to an uninterpreted value given a section, an optional subsection and key, and if it passes filter.

Consider Self::raw_values_mut if you want to get mutable references to all values of a multivar instead.

Examples found in repository?
src/file/access/raw.rs (line 69)
63
64
65
66
67
68
69
70
    pub fn raw_value_mut<'lookup>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&'lookup BStr>,
        key: &'lookup str,
    ) -> Result<ValueMut<'_, 'lookup, 'event>, lookup::existing::Error> {
        self.raw_value_mut_filter(section_name, subsection_name, key, &mut |_| true)
    }

Returns all uninterpreted values given a section, an optional subsection ain order of occurrence.

The ordering means that the last of the returned values is the one that would be the value used in the single-value case.nd key.

Examples

If you have the following config:

[core]
    a = b
[core]
    a = c
    a = d

Attempting to get all values of a yields the following:

assert_eq!(
    git_config.raw_values("core", None, "a").unwrap(),
    vec![
        Cow::<BStr>::Borrowed("b".into()),
        Cow::<BStr>::Borrowed("c".into()),
        Cow::<BStr>::Borrowed("d".into()),
    ],
);

Consider Self::raw_value if you want to get the resolved single value for a given key, if your key does not support multi-valued values.

Examples found in repository?
src/file/access/comfort.rs (line 195)
189
190
191
192
193
194
195
196
    pub fn strings(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Vec<Cow<'_, BStr>>> {
        self.raw_values(section_name, subsection_name, key).ok()
    }
More examples
Hide additional examples
src/file/access/read_only.rs (line 124)
118
119
120
121
122
123
124
125
126
127
128
129
    pub fn values<'a, T: TryFrom<Cow<'a, BStr>>>(
        &'a self,
        section_name: &str,
        subsection_name: Option<&BStr>,
        key: &str,
    ) -> Result<Vec<T>, lookup::Error<T::Error>> {
        self.raw_values(section_name, subsection_name, key)?
            .into_iter()
            .map(T::try_from)
            .collect::<Result<Vec<_>, _>>()
            .map_err(lookup::Error::FailedConversion)
    }

Returns all uninterpreted values given a section, an optional subsection and key, if the value passes filter, in order of occurrence.

The ordering means that the last of the returned values is the one that would be the value used in the single-value case.

Examples found in repository?
src/file/access/raw.rs (line 179)
173
174
175
176
177
178
179
180
    pub fn raw_values(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Result<Vec<Cow<'_, BStr>>, lookup::existing::Error> {
        self.raw_values_filter(section_name, subsection_name, key, &mut |_| true)
    }
More examples
Hide additional examples
src/file/access/comfort.rs (line 212)
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
    pub fn strings_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Vec<Cow<'_, BStr>>> {
        self.raw_values_filter(section_name, subsection_name, key, filter).ok()
    }

    /// Like [`strings_filter()`][File::strings_filter()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn strings_filter_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
        filter: &mut MetadataFilter,
    ) -> Option<Vec<Cow<'_, BStr>>> {
        let key = crate::parse::key(key)?;
        self.strings_filter(key.section_name, key.subsection_name, key.value_name, filter)
    }

    /// Similar to [`values(…)`][File::values()] but returning integers if at least one of them was found
    /// and if none of them overflows.
    pub fn integers(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
    ) -> Option<Result<Vec<i64>, value::Error>> {
        self.integers_filter(section_name, subsection_name, key, &mut |_| true)
    }

    /// Like [`integers()`][File::integers()], but suitable for statically known `key`s like `remote.origin.url`.
    pub fn integers_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Result<Vec<i64>, value::Error>> {
        self.integers_filter_by_key(key, &mut |_| true)
    }

    /// Similar to [`integers(…)`][File::integers()] but all integers are in sections that passed `filter`
    /// and that are not overflowing.
    pub fn integers_filter(
        &self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        filter: &mut MetadataFilter,
    ) -> Option<Result<Vec<i64>, value::Error>> {
        self.raw_values_filter(section_name, subsection_name, key, filter)
            .ok()
            .map(|values| {
                values
                    .into_iter()
                    .map(|v| {
                        crate::Integer::try_from(v.as_ref()).and_then(|int| {
                            int.to_decimal()
                                .ok_or_else(|| value::Error::new("Integer overflow", v.into_owned()))
                        })
                    })
                    .collect()
            })
    }

Returns mutable references to all uninterpreted values given a section, an optional subsection and key.

Examples

If you have the following config:

[core]
    a = b
[core]
    a = c
    a = d

Attempting to get all values of a yields the following:

assert_eq!(
    git_config.raw_values("core", None, "a")?,
    vec![
        Cow::<BStr>::Borrowed("b".into()),
        Cow::<BStr>::Borrowed("c".into()),
        Cow::<BStr>::Borrowed("d".into())
    ]
);

git_config.raw_values_mut("core", None, "a")?.set_all("g");

assert_eq!(
    git_config.raw_values("core", None, "a")?,
    vec![
        Cow::<BStr>::Borrowed("g".into()),
        Cow::<BStr>::Borrowed("g".into()),
        Cow::<BStr>::Borrowed("g".into())
    ],
);

Consider Self::raw_value if you want to get the resolved single value for a given key, if your key does not support multi-valued values.

Note that this operation is relatively expensive, requiring a full traversal of the config.

Examples found in repository?
src/file/access/raw.rs (line 533)
522
523
524
525
526
527
528
529
530
531
532
533
534
535
    pub fn set_existing_raw_multi_value<'a, Iter, Item>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: impl AsRef<str>,
        new_values: Iter,
    ) -> Result<(), lookup::existing::Error>
    where
        Iter: IntoIterator<Item = Item>,
        Item: Into<&'a BStr>,
    {
        self.raw_values_mut(section_name, subsection_name, key.as_ref())
            .map(|mut v| v.set_values(new_values))
    }

Returns mutable references to all uninterpreted values given a section, an optional subsection and key, if their sections pass filter.

Examples found in repository?
src/file/access/raw.rs (line 268)
262
263
264
265
266
267
268
269
    pub fn raw_values_mut<'lookup>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&'lookup BStr>,
        key: &'lookup str,
    ) -> Result<MultiValueMut<'_, 'lookup, 'event>, lookup::existing::Error> {
        self.raw_values_mut_filter(section_name, subsection_name, key, &mut |_| true)
    }

Sets a value in a given section_name, optional subsection_name, and key. Note sections named section_name and subsection_name (if not None) must exist for this method to work.

Examples

Given the config,

[core]
    a = b
[core]
    a = c
    a = d

Setting a new value to the key core.a will yield the following:

git_config.set_existing_raw_value("core", None, "a", "e")?;
assert_eq!(git_config.raw_value("core", None, "a")?, Cow::<BStr>::Borrowed("e".into()));
assert_eq!(
    git_config.raw_values("core", None, "a")?,
    vec![
        Cow::<BStr>::Borrowed("b".into()),
        Cow::<BStr>::Borrowed("c".into()),
        Cow::<BStr>::Borrowed("e".into())
    ],
);

Sets a value in a given section_name, optional subsection_name, and key. Creates the section if necessary and the key as well, or overwrites the last existing value otherwise.

Examples

Given the config,

[core]
    a = b

Setting a new value to the key core.a will yield the following:

let prev = git_config.set_raw_value("core", None, "a", "e")?;
git_config.set_raw_value("core", None, "b", "f")?;
assert_eq!(prev.expect("present").as_ref(), "b");
assert_eq!(git_config.raw_value("core", None, "a")?, Cow::<BStr>::Borrowed("e".into()));
assert_eq!(git_config.raw_value("core", None, "b")?, Cow::<BStr>::Borrowed("f".into()));

Similar to set_raw_value(), but only sets existing values in sections matching filter, creating a new section otherwise.

Examples found in repository?
src/file/access/raw.rs (line 417)
406
407
408
409
410
411
412
413
414
415
416
417
418
    pub fn set_raw_value<'b, Key, E>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        key: Key,
        new_value: impl Into<&'b BStr>,
    ) -> Result<Option<Cow<'event, BStr>>, crate::file::set_raw_value::Error>
    where
        Key: TryInto<section::Key<'event>, Error = E>,
        section::key::Error: From<E>,
    {
        self.set_raw_value_filter(section_name, subsection_name, key, new_value, &mut |_| true)
    }

Sets a multivar in a given section, optional subsection, and key value.

This internally zips together the new values and the existing values. As a result, if more new values are provided than the current amount of multivars, then the latter values are not applied. If there are less new values than old ones then the remaining old values are unmodified.

Note: Mutation order is not guaranteed and is non-deterministic. If you need finer control over which values of the multivar are set, consider using raw_values_mut(), which will let you iterate and check over the values instead. This is best used as a convenience function for setting multivars whose values should be treated as an unordered set.

Examples

Let us use the follow config for all examples:

[core]
    a = b
[core]
    a = c
    a = d

Setting an equal number of values:

let new_values = vec![
    "x",
    "y",
    "z",
];
git_config.set_existing_raw_multi_value("core", None, "a", new_values.into_iter())?;
let fetched_config = git_config.raw_values("core", None, "a")?;
assert!(fetched_config.contains(&Cow::<BStr>::Borrowed("x".into())));
assert!(fetched_config.contains(&Cow::<BStr>::Borrowed("y".into())));
assert!(fetched_config.contains(&Cow::<BStr>::Borrowed("z".into())));

Setting less than the number of present values sets the first ones found:

let new_values = vec![
    "x",
    "y",
];
git_config.set_existing_raw_multi_value("core", None, "a", new_values.into_iter())?;
let fetched_config = git_config.raw_values("core", None, "a")?;
assert!(fetched_config.contains(&Cow::<BStr>::Borrowed("x".into())));
assert!(fetched_config.contains(&Cow::<BStr>::Borrowed("y".into())));

Setting more than the number of present values discards the rest:

let new_values = vec![
    "x",
    "y",
    "z",
    "discarded",
];
git_config.set_existing_raw_multi_value("core", None, "a", new_values)?;
assert!(!git_config.raw_values("core", None, "a")?.contains(&Cow::<BStr>::Borrowed("discarded".into())));

Read-only low-level access methods, as it requires generics for converting into custom values defined in this crate like Integer and Color.

Returns an interpreted value given a section, an optional subsection and key.

It’s recommended to use one of the value types provide dby this crate as they implement the conversion, but this function is flexible and will accept any type that implements TryFrom<&BStr>.

Consider Self::values if you want to get all values of a multivar instead.

If a string is desired, use the string() method instead.

Examples
let config = r#"
    [core]
        a = 10k
        c = false
"#;
let git_config = git_config::File::try_from(config)?;
// You can either use the turbofish to determine the type...
let a_value = git_config.value::<Integer>("core", None, "a")?;
// ... or explicitly declare the type to avoid the turbofish
let c_value: Boolean = git_config.value("core", None, "c")?;

Like value(), but returning an None if the value wasn’t found at section[.subsection].key

Returns all interpreted values given a section, an optional subsection and key.

It’s recommended to use one of the value types provide dby this crate as they implement the conversion, but this function is flexible and will accept any type that implements TryFrom<&BStr>.

Consider Self::value if you want to get a single value (following last-one-wins resolution) instead.

To access plain strings, use the strings() method instead.

Examples
let config = r#"
    [core]
        a = true
        c
    [core]
        a
        a = false
"#;
let git_config = git_config::File::try_from(config).unwrap();
// You can either use the turbofish to determine the type...
let a_value = git_config.values::<Boolean>("core", None, "a")?;
assert_eq!(
    a_value,
    vec![
        Boolean(true),
        Boolean(false),
        Boolean(false),
    ]
);
// ... or explicitly declare the type to avoid the turbofish
let c_value: Vec<Boolean> = git_config.values("core", None, "c").unwrap();
assert_eq!(c_value, vec![Boolean(false)]);

Returns the last found immutable section with a given name and optional subsection_name.

Examples found in repository?
src/file/access/read_only.rs (line 149)
144
145
146
147
148
149
150
    pub fn section_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
    ) -> Result<&file::Section<'event>, lookup::existing::Error> {
        let key = crate::parse::section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?;
        self.section(key.section_name, key.subsection_name)
    }

Returns the last found immutable section with a given key, identifying the name and subsection name like core or remote.origin.

Returns the last found immutable section with a given name and optional subsection_name, that matches filter.

If there are sections matching section_name and subsection_name but the filter rejects all of them, Ok(None) is returned.

Examples found in repository?
src/file/access/read_only.rs (line 138)
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
    pub fn section(
        &self,
        name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
    ) -> Result<&file::Section<'event>, lookup::existing::Error> {
        Ok(self
            .section_filter(name, subsection_name, &mut |_| true)?
            .expect("section present as we take all"))
    }

    /// Returns the last found immutable section with a given `key`, identifying the name and subsection name like `core`
    /// or `remote.origin`.
    pub fn section_by_key<'a>(
        &self,
        key: impl Into<&'a BStr>,
    ) -> Result<&file::Section<'event>, lookup::existing::Error> {
        let key = crate::parse::section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?;
        self.section(key.section_name, key.subsection_name)
    }

    /// Returns the last found immutable section with a given `name` and optional `subsection_name`, that matches `filter`.
    ///
    /// If there are sections matching `section_name` and `subsection_name` but the `filter` rejects all of them, `Ok(None)`
    /// is returned.
    pub fn section_filter<'a>(
        &'a self,
        name: impl AsRef<str>,
        subsection_name: Option<&BStr>,
        filter: &mut MetadataFilter,
    ) -> Result<Option<&'a file::Section<'event>>, lookup::existing::Error> {
        Ok(self
            .section_ids_by_name_and_subname(name.as_ref(), subsection_name)?
            .rev()
            .find_map({
                let sections = &self.sections;
                move |id| {
                    let s = &sections[&id];
                    filter(s.meta()).then(|| s)
                }
            }))
    }

    /// Like [`section_filter()`][File::section_filter()], but identifies the section with `key` like `core` or `remote.origin`.
    pub fn section_filter_by_key<'a, 'b>(
        &'a self,
        key: impl Into<&'b BStr>,
        filter: &mut MetadataFilter,
    ) -> Result<Option<&'a file::Section<'event>>, lookup::existing::Error> {
        let key = crate::parse::section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?;
        self.section_filter(key.section_name, key.subsection_name, filter)
    }

Like section_filter(), but identifies the section with key like core or remote.origin.

Gets all sections that match the provided name, ignoring any subsections.

Examples

Provided the following config:

[core]
    a = b
[core ""]
    c = d
[core "apple"]
    e = f

Calling this method will yield all sections:

let config = r#"
    [core]
        a = b
    [core ""]
        c = d
    [core "apple"]
        e = f
"#;
let git_config = git_config::File::try_from(config)?;
assert_eq!(git_config.sections_by_name("core").map_or(0, |s|s.count()), 3);

Similar to sections_by_name(), but returns an identifier for this section as well to allow referring to it unambiguously even in the light of deletions.

Gets all sections that match the provided name, ignoring any subsections, and pass the filter.

Returns the number of values in the config, no matter in which section.

For example, a config with multiple empty sections will return 0. This ignores any comments.

Returns if there are no entries in the config. This will return true if there are only empty sections, with whitespace and comments not being considered void.

Return the file’s metadata to guide filtering of all values upon retrieval.

This is the metadata the file was instantiated with for use in all newly created sections.

Similar to meta(), but with shared ownership.

Return an iterator over all sections, in order of occurrence in the file itself.

Examples found in repository?
src/file/access/read_only.rs (line 336)
331
332
333
334
335
336
337
338
339
340
    pub fn detect_newline_style(&self) -> &BStr {
        self.frontmatter_events
            .iter()
            .find_map(extract_newline)
            .or_else(|| {
                self.sections()
                    .find_map(|s| s.body.as_ref().iter().find_map(extract_newline))
            })
            .unwrap_or_else(|| platform_newline())
    }

Return an iterator over all sections and their ids, in order of occurrence in the file itself.

Return an iterator over all sections along with non-section events that are placed right after them, in order of occurrence in the file itself.

This allows to reproduce the look of sections perfectly when serializing them with write_to().

Return all events which are in front of the first of our sections, or None if there are none.

Return the newline characters that have been detected in this config file or the default ones for the current platform.

Note that the first found newline is the one we use in the assumption of consistency.

Examples found in repository?
src/file/access/read_only.rs (line 343)
342
343
344
    pub(crate) fn detect_newline_style_smallvec(&self) -> SmallVec<[u8; 2]> {
        self.detect_newline_style().as_ref().into()
    }
More examples
Hide additional examples
src/file/write.rs (line 19)
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
    pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> {
        let nl = self.detect_newline_style();

        {
            for event in self.frontmatter_events.as_ref() {
                event.write_to(&mut out)?;
            }

            if !ends_with_newline(self.frontmatter_events.as_ref(), nl, true) && self.sections.iter().next().is_some() {
                out.write_all(nl)?;
            }
        }

        let mut prev_section_ended_with_newline = true;
        for section_id in &self.section_order {
            if !prev_section_ended_with_newline {
                out.write_all(nl)?;
            }
            let section = self.sections.get(section_id).expect("known section-id");
            section.write_to(&mut out)?;

            prev_section_ended_with_newline = ends_with_newline(section.body.0.as_ref(), nl, false);
            if let Some(post_matter) = self.frontmatter_post_section.get(section_id) {
                if !prev_section_ended_with_newline {
                    out.write_all(nl)?;
                }
                for event in post_matter {
                    event.write_to(&mut out)?;
                }
                prev_section_ended_with_newline = ends_with_newline(post_matter, nl, prev_section_ended_with_newline);
            }
        }

        if !prev_section_ended_with_newline {
            out.write_all(nl)?;
        }

        Ok(())
    }
src/file/access/raw.rs (line 123)
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
131
132
133
    pub fn raw_value_mut_filter<'lookup>(
        &mut self,
        section_name: impl AsRef<str>,
        subsection_name: Option<&'lookup BStr>,
        key: &'lookup str,
        filter: &mut MetadataFilter,
    ) -> Result<ValueMut<'_, 'lookup, 'event>, lookup::existing::Error> {
        let mut section_ids = self
            .section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?
            .rev();
        let key = section::Key(Cow::<BStr>::Borrowed(key.into()));

        while let Some(section_id) = section_ids.next() {
            let mut index = 0;
            let mut size = 0;
            let mut found_key = false;
            let section = self.sections.get(&section_id).expect("known section id");
            if !filter(section.meta()) {
                continue;
            }
            for (i, event) in section.as_ref().iter().enumerate() {
                match event {
                    Event::SectionKey(event_key) if *event_key == key => {
                        found_key = true;
                        index = i;
                        size = 1;
                    }
                    Event::Newline(_) | Event::Whitespace(_) | Event::ValueNotDone(_) if found_key => {
                        size += 1;
                    }
                    Event::ValueDone(_) | Event::Value(_) if found_key => {
                        found_key = false;
                        size += 1;
                    }
                    Event::KeyValueSeparator if found_key => {
                        size += 1;
                    }
                    _ => {}
                }
            }

            if size == 0 {
                continue;
            }

            drop(section_ids);
            let nl = self.detect_newline_style().to_smallvec();
            return Ok(ValueMut {
                section: self.sections.get_mut(&section_id).expect("known section-id").to_mut(nl),
                key,
                index: Index(index),
                size: Size(size),
            });
        }

        Err(lookup::existing::Error::KeyMissing)
    }

Traverse all include and includeIf directives found in this instance and follow them, loading the referenced files from their location and adding their content right past the value that included them.

Limitations
  • Note that this method is not idempotent and calling it multiple times will resolve includes multiple times. It’s recommended use is as part of a multi-step bootstrapping which needs fine-grained control, and unless that’s given one should prefer one of the other ways of initialization that resolve includes at the right time.
  • included values are added after the section that included them, not directly after the value. This is a deviation from how git does it, as it technically adds new value right after the include path itself, technically ‘splitting’ the section. This can only make a difference if the include section also has values which later overwrite portions of the included file, which seems unusual as these would be related to includes. We can fix this by ‘splitting’ the include section if needed so the included sections are put into the right place.
Examples found in repository?
src/file/init/comfort.rs (line 129)
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
131
132
133
134
135
136
137
138
139
140
    pub fn from_git_dir(dir: impl Into<std::path::PathBuf>) -> Result<File<'static>, from_git_dir::Error> {
        let (mut local, git_dir) = {
            let source = Source::Local;
            let mut path = dir.into();
            path.push(
                source
                    .storage_location(&mut |n| std::env::var_os(n))
                    .expect("location available for local"),
            );
            let local = Self::from_path_no_includes(&path, source)?;
            path.pop();
            (local, path)
        };

        let worktree = match local.boolean("extensions", None, "worktreeConfig") {
            Some(Ok(worktree_config)) => worktree_config.then(|| {
                let source = Source::Worktree;
                let path = git_dir.join(
                    source
                        .storage_location(&mut |n| std::env::var_os(n))
                        .expect("location available for worktree"),
                );
                Self::from_path_no_includes(path, source)
            }),
            _ => None,
        }
        .transpose()?;

        let home = std::env::var("HOME").ok().map(PathBuf::from);
        let options = init::Options {
            includes: init::includes::Options::follow(
                path::interpolate::Context {
                    home_dir: home.as_deref(),
                    ..Default::default()
                },
                init::includes::conditional::Context {
                    git_dir: Some(git_dir.as_ref()),
                    branch_name: None,
                },
            ),
            lossy: false,
        };

        let mut globals = Self::from_globals()?;
        globals.resolve_includes(options)?;
        local.resolve_includes(options)?;

        globals.append(local);
        if let Some(mut worktree) = worktree {
            worktree.resolve_includes(options)?;
            globals.append(worktree);
        }
        globals.append(Self::from_environment_overrides()?);

        Ok(globals)
    }

Serialize this type into a BString for convenience.

Note that to_string() can also be used, but might not be lossless.

Examples found in repository?
src/file/impls.rs (line 51)
50
51
52
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Display::fmt(&self.to_bstring(), f)
    }

Stream ourselves to the given out, in order to reproduce this file mostly losslessly as it was parsed.

Examples found in repository?
src/file/write.rs (line 12)
10
11
12
13
14
    pub fn to_bstring(&self) -> BString {
        let mut buf = Vec::new();
        self.write_to(&mut buf).expect("io error impossible");
        buf.into()
    }

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
The associated error which can be returned from parsing.
Parses a string s to return a value of this type. Read more
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Convenience constructor. Attempts to parse the provided byte string into a File. See Events::from_bytes() for more information.

The type returned in the event of a conversion error.

Convenience constructor. Attempts to parse the provided string into a File. See Events::from_str() for more information.

The type returned in the event of a conversion error.

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.