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§
source§impl File<'static>
impl File<'static>
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.
sourcepub fn from_globals() -> Result<File<'static>, Error>
pub fn from_globals() -> Result<File<'static>, Error>
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?
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)
}
sourcepub fn from_environment_overrides() -> Result<File<'static>, Error>
pub fn from_environment_overrides() -> Result<File<'static>, Error>
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?
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)
}
source§impl File<'static>
impl File<'static>
An easy way to provide complete configuration for a repository.
sourcepub fn from_git_dir(dir: impl Into<PathBuf>) -> Result<File<'static>, Error>
pub fn from_git_dir(dir: impl Into<PathBuf>) -> Result<File<'static>, Error>
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.
source§impl File<'static>
impl File<'static>
Instantiation from environment variables
sourcepub fn from_env(options: Options<'_>) -> Result<Option<File<'static>>, Error>
pub fn from_env(options: Options<'_>) -> Result<Option<File<'static>>, Error>
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.
source§impl File<'static>
impl File<'static>
Instantiation from one or more paths
sourcepub fn from_path_no_includes(
path: impl Into<PathBuf>,
source: Source
) -> Result<Self, Error>
pub fn from_path_no_includes(
path: impl Into<PathBuf>,
source: Source
) -> Result<Self, Error>
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?
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)
}
sourcepub fn from_paths_metadata(
path_meta: impl IntoIterator<Item = impl Into<Metadata>>,
options: Options<'_>
) -> Result<Option<Self>, Error>
pub fn from_paths_metadata(
path_meta: impl IntoIterator<Item = impl Into<Metadata>>,
options: Options<'_>
) -> Result<Option<Self>, Error>
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?
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)
}
sourcepub 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>
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>
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.
source§impl<'a> File<'a>
impl<'a> File<'a>
sourcepub fn new(meta: impl Into<OwnShared<Metadata>>) -> Self
pub fn new(meta: impl Into<OwnShared<Metadata>>) -> Self
Return an empty File
with the given meta
-data to be attached to all new sections.
Examples found in repository?
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
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))
}
sourcepub fn from_bytes_no_includes(
input: &'a [u8],
meta: impl Into<OwnShared<Metadata>>,
options: Options<'_>
) -> Result<Self, Error>
pub fn from_bytes_no_includes(
input: &'a [u8],
meta: impl Into<OwnShared<Metadata>>,
options: Options<'_>
) -> Result<Self, Error>
Instantiate a new File
from given input
, associating each section and their values with
meta
-data, while respecting options
.
sourcepub fn from_parse_events_no_includes(
_: Events<'a>,
meta: impl Into<OwnShared<Metadata>>
) -> Self
pub fn from_parse_events_no_includes(
_: Events<'a>,
meta: impl Into<OwnShared<Metadata>>
) -> Self
Instantiate a new File
from given events
, associating each section and their values with
meta
-data.
Examples found in repository?
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
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)
}
source§impl File<'static>
impl File<'static>
sourcepub fn from_bytes_owned(
input_and_buf: &mut Vec<u8>,
meta: impl Into<OwnShared<Metadata>>,
options: Options<'_>
) -> Result<Self, Error>
pub fn from_bytes_owned(
input_and_buf: &mut Vec<u8>,
meta: impl Into<OwnShared<Metadata>>,
options: Options<'_>
) -> Result<Self, Error>
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?
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
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[§ion_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(())
}
source§impl<'event> File<'event>
impl<'event> File<'event>
Comfortable API for accessing values
sourcepub fn string(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Cow<'_, BStr>>
pub fn string(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Cow<'_, BStr>>
Like value()
, but returning None
if the string wasn’t found.
As strings perform no conversions, this will never fail.
sourcepub fn string_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Cow<'_, BStr>>
pub fn string_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Cow<'_, BStr>>
Like string()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn string_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Cow<'_, BStr>>
pub fn string_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Cow<'_, BStr>>
Like string()
, but the section containing the returned value must pass filter
as well.
sourcepub fn string_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Cow<'_, BStr>>
pub fn string_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Cow<'_, BStr>>
Like string_filter()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn path(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Path<'_>>
pub fn path(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Path<'_>>
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.
sourcepub fn path_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Path<'_>>
pub fn path_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option<Path<'_>>
Like path()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn path_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Path<'_>>
pub fn path_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Path<'_>>
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?
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)
}
sourcepub fn path_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Path<'_>>
pub fn path_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Path<'_>>
Like path_filter()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn boolean(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Result<bool, Error>>
pub fn boolean(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Result<bool, Error>>
Like value()
, but returning None
if the boolean value wasn’t found.
Examples found in repository?
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)
}
sourcepub fn boolean_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Result<bool, Error>>
pub fn boolean_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Result<bool, Error>>
Like boolean()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn boolean_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Result<bool, Error>>
pub fn boolean_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Result<bool, Error>>
Like boolean()
, but the section containing the returned value must pass filter
as well.
Examples found in repository?
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(§ion_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)
}
sourcepub fn boolean_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Result<bool, Error>>
pub fn boolean_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Result<bool, Error>>
Like boolean_filter()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn integer(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Result<i64, Error>>
pub fn integer(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Result<i64, Error>>
Like value()
, but returning an Option
if the integer wasn’t found.
sourcepub fn integer_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Result<i64, Error>>
pub fn integer_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Result<i64, Error>>
Like integer()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn integer_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Result<i64, Error>>
pub fn integer_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Result<i64, Error>>
Like integer()
, but the section containing the returned value must pass filter
as well.
Examples found in repository?
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)
}
sourcepub fn integer_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Result<i64, Error>>
pub fn integer_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Result<i64, Error>>
Like integer_filter()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn strings(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Vec<Cow<'_, BStr>>>
pub fn strings(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Vec<Cow<'_, BStr>>>
Similar to values(…)
but returning strings if at least one of them was found.
sourcepub fn strings_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Vec<Cow<'_, BStr>>>
pub fn strings_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Vec<Cow<'_, BStr>>>
Like strings()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn strings_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Vec<Cow<'_, BStr>>>
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>>>
Similar to strings(…)
, but all values are in sections that passed filter
.
sourcepub fn strings_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Vec<Cow<'_, BStr>>>
pub fn strings_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Vec<Cow<'_, BStr>>>
Like strings_filter()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn integers(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Result<Vec<i64>, Error>>
pub fn integers(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Option<Result<Vec<i64>, Error>>
Similar to values(…)
but returning integers if at least one of them was found
and if none of them overflows.
sourcepub fn integers_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Result<Vec<i64>, Error>>
pub fn integers_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Option<Result<Vec<i64>, Error>>
Like integers()
, but suitable for statically known key
s like remote.origin.url
.
sourcepub fn integers_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Option<Result<Vec<i64>, Error>>
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>, Error>>
Similar to integers(…)
but all integers are in sections that passed filter
and that are not overflowing.
Examples found in repository?
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)
}
sourcepub fn integers_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Result<Vec<i64>, Error>>
pub fn integers_filter_by_key<'a>(
&self,
key: impl Into<&'a BStr>,
filter: &mut MetadataFilter
) -> Option<Result<Vec<i64>, Error>>
Like integers_filter()
, but suitable for statically known key
s like remote.origin.url
.
source§impl<'event> File<'event>
impl<'event> File<'event>
Mutating low-level access methods.
sourcepub fn section_mut<'a>(
&'a mut self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>
) -> Result<SectionMut<'a, 'event>, Error>
pub fn section_mut<'a>(
&'a mut self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>
) -> Result<SectionMut<'a, 'event>, Error>
Returns the last mutable section with a given name
and optional subsection_name
, if it exists.
sourcepub fn section_mut_by_key<'a, 'b>(
&'a mut self,
key: impl Into<&'b BStr>
) -> Result<SectionMut<'a, 'event>, Error>
pub fn section_mut_by_key<'a, 'b>(
&'a mut self,
key: impl Into<&'b BStr>
) -> Result<SectionMut<'a, 'event>, Error>
Returns the last found mutable section with a given key
, identifying the name and subsection name like core
or remote.origin
.
sourcepub fn section_mut_by_id<'a>(
&'a mut self,
id: SectionId
) -> Option<SectionMut<'a, 'event>>
pub fn section_mut_by_id<'a>(
&'a mut self,
id: SectionId
) -> Option<SectionMut<'a, 'event>>
Return the mutable section identified by id
, or None
if it didn’t exist.
Note that id
is stable across deletions and insertions.
sourcepub fn section_mut_or_create_new<'a>(
&'a mut self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>
) -> Result<SectionMut<'a, 'event>, Error>
pub fn section_mut_or_create_new<'a>(
&'a mut self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>
) -> Result<SectionMut<'a, 'event>, Error>
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?
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))
}
sourcepub 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>, Error>
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>, Error>
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?
More examples
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))
}
sourcepub fn section_mut_filter<'a>(
&'a mut self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>,
filter: &mut MetadataFilter
) -> Result<Option<SectionMut<'a, 'event>>, Error>
pub fn section_mut_filter<'a>(
&'a mut self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>,
filter: &mut MetadataFilter
) -> Result<Option<SectionMut<'a, 'event>>, Error>
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.
sourcepub fn section_mut_filter_by_key<'a, 'b>(
&'a mut self,
key: impl Into<&'b BStr>,
filter: &mut MetadataFilter
) -> Result<Option<SectionMut<'a, 'event>>, Error>
pub fn section_mut_filter_by_key<'a, 'b>(
&'a mut self,
key: impl Into<&'b BStr>,
filter: &mut MetadataFilter
) -> Result<Option<SectionMut<'a, 'event>>, Error>
Like section_mut_filter()
, but identifies the with a given key
,
like core
or remote.origin
.
sourcepub fn new_section(
&mut self,
name: impl Into<Cow<'event, str>>,
subsection: impl Into<Option<Cow<'event, BStr>>>
) -> Result<SectionMut<'_, 'event>, Error>
pub fn new_section(
&mut self,
name: impl Into<Cow<'event, str>>,
subsection: impl Into<Option<Cow<'event, BStr>>>
) -> Result<SectionMut<'_, 'event>, Error>
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?
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()))),
}
}
sourcepub fn remove_section<'a>(
&mut self,
name: &str,
subsection_name: impl Into<Option<&'a BStr>>
) -> Option<Section<'event>>
pub fn remove_section<'a>(
&mut self,
name: &str,
subsection_name: impl Into<Option<&'a BStr>>
) -> Option<Section<'event>>
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");
sourcepub fn remove_section_by_id(&mut self, id: SectionId) -> Option<Section<'event>>
pub fn remove_section_by_id(&mut self, id: SectionId) -> Option<Section<'event>>
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?
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)
}
sourcepub fn remove_section_filter<'a>(
&mut self,
name: &str,
subsection_name: impl Into<Option<&'a BStr>>,
filter: &mut MetadataFilter
) -> Option<Section<'event>>
pub fn remove_section_filter<'a>(
&mut self,
name: &str,
subsection_name: impl Into<Option<&'a BStr>>,
filter: &mut MetadataFilter
) -> Option<Section<'event>>
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.
sourcepub fn push_section(
&mut self,
section: Section<'event>
) -> Result<SectionMut<'_, 'event>, Error>
pub fn push_section(
&mut self,
section: Section<'event>
) -> Result<SectionMut<'_, 'event>, Error>
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.
sourcepub fn rename_section<'a>(
&mut self,
name: impl AsRef<str>,
subsection_name: impl Into<Option<&'a BStr>>,
new_name: impl Into<Cow<'event, str>>,
new_subsection_name: impl Into<Option<Cow<'event, BStr>>>
) -> Result<(), Error>
pub fn rename_section<'a>(
&mut self,
name: impl AsRef<str>,
subsection_name: impl Into<Option<&'a BStr>>,
new_name: impl Into<Cow<'event, str>>,
new_subsection_name: impl Into<Option<Cow<'event, BStr>>>
) -> Result<(), Error>
Renames the section with name
and subsection_name
, modifying the last matching section
to use new_name
and new_subsection_name
.
sourcepub fn rename_section_filter<'a>(
&mut self,
name: impl AsRef<str>,
subsection_name: impl Into<Option<&'a BStr>>,
new_name: impl Into<Cow<'event, str>>,
new_subsection_name: impl Into<Option<Cow<'event, BStr>>>,
filter: &mut MetadataFilter
) -> Result<(), Error>
pub fn rename_section_filter<'a>(
&mut self,
name: impl AsRef<str>,
subsection_name: impl Into<Option<&'a BStr>>,
new_name: impl Into<Cow<'event, str>>,
new_subsection_name: impl Into<Option<Cow<'event, BStr>>>,
filter: &mut MetadataFilter
) -> Result<(), Error>
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.
sourcepub fn append(&mut self, other: Self) -> &mut Self
pub fn append(&mut self, other: Self) -> &mut Self
Append another File to the end of ourselves, without losing any information.
Examples found in repository?
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
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)
}
source§impl<'event> File<'event>
impl<'event> File<'event>
Raw value API
These functions are the raw value API, returning normalized byte strings.
sourcepub fn raw_value(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Result<Cow<'_, BStr>, Error>
pub fn raw_value(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Result<Cow<'_, BStr>, Error>
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?
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)
}
sourcepub fn raw_value_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Result<Cow<'_, BStr>, Error>
pub fn raw_value_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Result<Cow<'_, BStr>, Error>
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?
More examples
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(§ion_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()))
}))
}
sourcepub fn raw_value_mut<'lookup>(
&mut self,
section_name: impl AsRef<str>,
subsection_name: Option<&'lookup BStr>,
key: &'lookup str
) -> Result<ValueMut<'_, 'lookup, 'event>, Error>
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>, Error>
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.
sourcepub 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>, Error>
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>, Error>
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.
sourcepub fn raw_values(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Result<Vec<Cow<'_, BStr>>, Error>
pub fn raw_values(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>
) -> Result<Vec<Cow<'_, BStr>>, Error>
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?
More examples
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)
}
sourcepub fn raw_values_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Result<Vec<Cow<'_, BStr>>, Error>
pub fn raw_values_filter(
&self,
section_name: impl AsRef<str>,
subsection_name: Option<&BStr>,
key: impl AsRef<str>,
filter: &mut MetadataFilter
) -> Result<Vec<Cow<'_, BStr>>, Error>
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?
More examples
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()
})
}
sourcepub fn raw_values_mut<'lookup>(
&mut self,
section_name: impl AsRef<str>,
subsection_name: Option<&'lookup BStr>,
key: &'lookup str
) -> Result<MultiValueMut<'_, 'lookup, 'event>, Error>
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>, Error>
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?
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))
}
sourcepub fn raw_values_mut_filter<'lookup>(
&mut self,
section_name: impl AsRef<str>,
subsection_name: Option<&'lookup BStr>,
key: &'lookup str,
filter: &mut MetadataFilter
) -> Result<MultiValueMut<'_, 'lookup, 'event>, Error>
pub fn raw_values_mut_filter<'lookup>(
&mut self,
section_name: impl AsRef<str>,
subsection_name: Option<&'lookup BStr>,
key: &'lookup str,
filter: &mut MetadataFilter
) -> Result<MultiValueMut<'_, 'lookup, 'event>, Error>
Returns mutable references to all uninterpreted values given a section,
an optional subsection and key, if their sections pass filter
.
sourcepub 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<(), Error>
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<(), Error>
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())
],
);
sourcepub 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>>, Error>where
Key: TryInto<Key<'event>, Error = E>,
Error: From<E>,
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>>, Error>where
Key: TryInto<Key<'event>, Error = E>,
Error: From<E>,
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()));
sourcepub 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>>, Error>where
Key: TryInto<Key<'event>, Error = E>,
Error: From<E>,
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>>, Error>where
Key: TryInto<Key<'event>, Error = E>,
Error: From<E>,
Similar to set_raw_value()
, but only sets existing values in sections matching
filter
, creating a new section otherwise.
Examples found in repository?
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)
}
sourcepub 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<(), Error>where
Iter: IntoIterator<Item = Item>,
Item: Into<&'a BStr>,
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<(), Error>where
Iter: IntoIterator<Item = Item>,
Item: Into<&'a BStr>,
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())));
source§impl<'event> File<'event>
impl<'event> File<'event>
Read-only low-level access methods, as it requires generics for converting into
custom values defined in this crate like Integer
and
Color
.
sourcepub fn value<'a, T: TryFrom<Cow<'a, BStr>>>(
&'a self,
section_name: &str,
subsection_name: Option<&BStr>,
key: &str
) -> Result<T, Error<T::Error>>
pub fn value<'a, T: TryFrom<Cow<'a, BStr>>>(
&'a self,
section_name: &str,
subsection_name: Option<&BStr>,
key: &str
) -> Result<T, Error<T::Error>>
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")?;
sourcepub 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>>
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>>
Like value()
, but returning an None
if the value wasn’t found at section[.subsection].key
sourcepub fn values<'a, T: TryFrom<Cow<'a, BStr>>>(
&'a self,
section_name: &str,
subsection_name: Option<&BStr>,
key: &str
) -> Result<Vec<T>, Error<T::Error>>
pub fn values<'a, T: TryFrom<Cow<'a, BStr>>>(
&'a self,
section_name: &str,
subsection_name: Option<&BStr>,
key: &str
) -> Result<Vec<T>, Error<T::Error>>
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)]);
sourcepub fn section(
&self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>
) -> Result<&Section<'event>, Error>
pub fn section(
&self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>
) -> Result<&Section<'event>, Error>
Returns the last found immutable section with a given name
and optional subsection_name
.
sourcepub fn section_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Result<&Section<'event>, Error>
pub fn section_by_key<'a>(
&self,
key: impl Into<&'a BStr>
) -> Result<&Section<'event>, Error>
Returns the last found immutable section with a given key
, identifying the name and subsection name like core
or remote.origin
.
sourcepub fn section_filter<'a>(
&'a self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>,
filter: &mut MetadataFilter
) -> Result<Option<&'a Section<'event>>, Error>
pub fn section_filter<'a>(
&'a self,
name: impl AsRef<str>,
subsection_name: Option<&BStr>,
filter: &mut MetadataFilter
) -> Result<Option<&'a Section<'event>>, Error>
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?
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 = §ions[&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)
}
sourcepub fn section_filter_by_key<'a, 'b>(
&'a self,
key: impl Into<&'b BStr>,
filter: &mut MetadataFilter
) -> Result<Option<&'a Section<'event>>, Error>
pub fn section_filter_by_key<'a, 'b>(
&'a self,
key: impl Into<&'b BStr>,
filter: &mut MetadataFilter
) -> Result<Option<&'a Section<'event>>, Error>
Like section_filter()
, but identifies the section with key
like core
or remote.origin
.
sourcepub fn sections_by_name<'a>(
&'a self,
name: &'a str
) -> Option<impl Iterator<Item = &Section<'event>> + '_>
pub fn sections_by_name<'a>(
&'a self,
name: &'a str
) -> Option<impl Iterator<Item = &Section<'event>> + '_>
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);
sourcepub fn sections_and_ids_by_name<'a>(
&'a self,
name: &'a str
) -> Option<impl Iterator<Item = (&Section<'event>, SectionId)> + '_>
pub fn sections_and_ids_by_name<'a>(
&'a self,
name: &'a str
) -> Option<impl Iterator<Item = (&Section<'event>, SectionId)> + '_>
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.
sourcepub fn sections_by_name_and_filter<'a>(
&'a self,
name: &'a str,
filter: &'a mut MetadataFilter
) -> Option<impl Iterator<Item = &Section<'event>> + '_>
pub fn sections_by_name_and_filter<'a>(
&'a self,
name: &'a str,
filter: &'a mut MetadataFilter
) -> Option<impl Iterator<Item = &Section<'event>> + '_>
Gets all sections that match the provided name
, ignoring any subsections, and pass the filter
.
sourcepub fn num_values(&self) -> usize
pub fn num_values(&self) -> usize
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.
sourcepub fn is_void(&self) -> bool
pub fn is_void(&self) -> bool
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.
sourcepub fn meta(&self) -> &Metadata
pub fn meta(&self) -> &Metadata
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.
sourcepub fn meta_owned(&self) -> OwnShared<Metadata>
pub fn meta_owned(&self) -> OwnShared<Metadata>
Similar to meta()
, but with shared ownership.
sourcepub fn sections(&self) -> impl Iterator<Item = &Section<'event>> + '_
pub fn sections(&self) -> impl Iterator<Item = &Section<'event>> + '_
Return an iterator over all sections, in order of occurrence in the file itself.
sourcepub fn sections_and_ids(
&self
) -> impl Iterator<Item = (&Section<'event>, SectionId)> + '_
pub fn sections_and_ids(
&self
) -> impl Iterator<Item = (&Section<'event>, SectionId)> + '_
Return an iterator over all sections and their ids, in order of occurrence in the file itself.
sourcepub fn sections_and_postmatter(
&self
) -> impl Iterator<Item = (&Section<'event>, Vec<&Event<'event>>)>
pub fn sections_and_postmatter(
&self
) -> impl Iterator<Item = (&Section<'event>, Vec<&Event<'event>>)>
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()
.
sourcepub fn frontmatter(&self) -> Option<impl Iterator<Item = &Event<'event>>>
pub fn frontmatter(&self) -> Option<impl Iterator<Item = &Event<'event>>>
Return all events which are in front of the first of our sections, or None
if there are none.
sourcepub fn detect_newline_style(&self) -> &BStr
pub fn detect_newline_style(&self) -> &BStr
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?
More examples
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(())
}
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(§ion_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(§ion_id).expect("known section-id").to_mut(nl),
key,
index: Index(index),
size: Size(size),
});
}
Err(lookup::existing::Error::KeyMissing)
}
source§impl File<'static>
impl File<'static>
sourcepub fn resolve_includes(&mut self, options: Options<'_>) -> Result<(), Error>
pub fn resolve_includes(&mut self, options: Options<'_>) -> Result<(), Error>
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 toincludes
. 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?
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)
}