diff --git a/gix-config/fuzz/fuzz_targets/fuzz_file.rs b/gix-config/fuzz/fuzz_targets/fuzz_file.rs index 943fea5460e..b86310491f2 100644 --- a/gix-config/fuzz/fuzz_targets/fuzz_file.rs +++ b/gix-config/fuzz/fuzz_targets/fuzz_file.rs @@ -79,7 +79,7 @@ fn fuzz_mutable_section( subsection_name, Cow::Owned(renamed_section_name.clone()), renamed_subsection_name.clone(), - &mut |_| false, + |_| false, )); Ok(()) diff --git a/gix-config/src/file/access/comfort.rs b/gix-config/src/file/access/comfort.rs index 12753891ec0..6a75188d016 100644 --- a/gix-config/src/file/access/comfort.rs +++ b/gix-config/src/file/access/comfort.rs @@ -2,13 +2,14 @@ use std::borrow::Cow; use bstr::BStr; -use crate::{file::MetadataFilter, value, AsKey, File}; +use crate::file::Metadata; +use crate::{value, AsKey, File}; /// Comfortable API for accessing values impl File<'_> { /// Like [`string_by()`](File::string_by()), but suitable for statically known `key`s like `remote.origin.url`. pub fn string(&self, key: impl AsKey) -> Option> { - self.string_filter(key, &mut |_| true) + self.string_filter(key, |_| true) } /// Like [`value()`](File::value()), but returning `None` if the string wasn't found. @@ -20,13 +21,11 @@ impl File<'_> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Option> { - self.string_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), &mut |_| { - true - }) + self.string_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true) } /// Like [`string_filter_by()`](File::string_filter_by()), but suitable for statically known `key`s like `remote.origin.url`. - pub fn string_filter(&self, key: impl AsKey, filter: &mut MetadataFilter) -> Option> { + pub fn string_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option> { let key = key.try_as_key()?; self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, filter) .ok() @@ -38,7 +37,7 @@ impl File<'_> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option> { self.raw_value_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) .ok() @@ -46,7 +45,7 @@ impl File<'_> { /// Like [`path_by()`](File::path_by()), but suitable for statically known `key`s like `remote.origin.url`. pub fn path(&self, key: impl AsKey) -> Option> { - self.path_filter(key, &mut |_| true) + self.path_filter(key, |_| true) } /// Like [`value()`](File::value()), but returning `None` if the path wasn't found. @@ -61,13 +60,11 @@ impl File<'_> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Option> { - self.path_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), &mut |_| { - true - }) + self.path_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true) } /// Like [`path_filter_by()`](File::path_filter_by()), but suitable for statically known `key`s like `remote.origin.url`. - pub fn path_filter(&self, key: impl AsKey, filter: &mut MetadataFilter) -> Option> { + pub fn path_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option> { let key = key.try_as_key()?; self.path_filter_by(key.section_name, key.subsection_name, key.value_name, filter) } @@ -83,7 +80,7 @@ impl File<'_> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option> { self.raw_value_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) .ok() @@ -92,7 +89,7 @@ impl File<'_> { /// Like [`boolean_by()`](File::boolean_by()), but suitable for statically known `key`s like `remote.origin.url`. pub fn boolean(&self, key: impl AsKey) -> Option> { - self.boolean_filter(key, &mut |_| true) + self.boolean_filter(key, |_| true) } /// Like [`value()`](File::value()), but returning `None` if the boolean value wasn't found. @@ -102,13 +99,15 @@ impl File<'_> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Option> { - self.boolean_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), &mut |_| { - true - }) + self.boolean_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true) } /// Like [`boolean_filter_by()`](File::boolean_filter_by()), but suitable for statically known `key`s like `remote.origin.url`. - pub fn boolean_filter(&self, key: impl AsKey, filter: &mut MetadataFilter) -> Option> { + pub fn boolean_filter( + &self, + key: impl AsKey, + filter: impl FnMut(&Metadata) -> bool, + ) -> Option> { let key = key.try_as_key()?; self.boolean_filter_by(key.section_name, key.subsection_name, key.value_name, filter) } @@ -119,7 +118,7 @@ impl File<'_> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Option> { let section_name = section_name.as_ref(); let section_ids = self @@ -142,7 +141,7 @@ impl File<'_> { /// Like [`integer_by()`](File::integer_by()), but suitable for statically known `key`s like `remote.origin.url`. pub fn integer(&self, key: impl AsKey) -> Option> { - self.integer_filter(key, &mut |_| true) + self.integer_filter(key, |_| true) } /// Like [`value()`](File::value()), but returning an `Option` if the integer wasn't found. @@ -152,11 +151,15 @@ impl File<'_> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Option> { - self.integer_filter_by(section_name, subsection_name, value_name, &mut |_| true) + self.integer_filter_by(section_name, subsection_name, value_name, |_| true) } /// Like [`integer_filter_by()`](File::integer_filter_by()), but suitable for statically known `key`s like `remote.origin.url`. - pub fn integer_filter(&self, key: impl AsKey, filter: &mut MetadataFilter) -> Option> { + pub fn integer_filter( + &self, + key: impl AsKey, + filter: impl FnMut(&Metadata) -> bool, + ) -> Option> { let key = key.try_as_key()?; self.integer_filter_by(key.section_name, key.subsection_name, key.value_name, filter) } @@ -167,7 +170,7 @@ impl File<'_> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option> { let int = self .raw_value_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) @@ -196,7 +199,7 @@ impl File<'_> { } /// Like [`strings_filter_by()`](File::strings_filter_by()), but suitable for statically known `key`s like `remote.origin.url`. - pub fn strings_filter(&self, key: impl AsKey, filter: &mut MetadataFilter) -> Option>> { + pub fn strings_filter(&self, key: impl AsKey, filter: impl FnMut(&Metadata) -> bool) -> Option>> { let key = key.try_as_key()?; self.strings_filter_by(key.section_name, key.subsection_name, key.value_name, filter) } @@ -207,7 +210,7 @@ impl File<'_> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option>> { self.raw_values_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) .ok() @@ -215,7 +218,7 @@ impl File<'_> { /// Like [`integers()`](File::integers()), but suitable for statically known `key`s like `remote.origin.url`. pub fn integers(&self, key: impl AsKey) -> Option, value::Error>> { - self.integers_filter(key, &mut |_| true) + self.integers_filter(key, |_| true) } /// Similar to [`values_by(…)`](File::values_by()) but returning integers if at least one of them was found @@ -226,16 +229,14 @@ impl File<'_> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Option, value::Error>> { - self.integers_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), &mut |_| { - true - }) + self.integers_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), |_| true) } /// Like [`integers_filter_by()`](File::integers_filter_by()), but suitable for statically known `key`s like `remote.origin.url`. pub fn integers_filter( &self, key: impl AsKey, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option, value::Error>> { let key = key.try_as_key()?; self.integers_filter_by(key.section_name, key.subsection_name, key.value_name, filter) @@ -248,7 +249,7 @@ impl File<'_> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option, value::Error>> { self.raw_values_filter_by(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) .ok() diff --git a/gix-config/src/file/access/mutate.rs b/gix-config/src/file/access/mutate.rs index c50de2deaf5..c43cf0271b3 100644 --- a/gix-config/src/file/access/mutate.rs +++ b/gix-config/src/file/access/mutate.rs @@ -3,8 +3,9 @@ use std::borrow::Cow; use bstr::BStr; use gix_features::threading::OwnShared; +use crate::file::Metadata; use crate::{ - file::{self, rename_section, write::ends_with_newline, MetadataFilter, SectionBodyIdsLut, SectionId, SectionMut}, + file::{self, rename_section, write::ends_with_newline, SectionBodyIdsLut, SectionId, SectionMut}, lookup, parse::{section, Event, FrontMatterEvents}, File, @@ -61,7 +62,7 @@ impl<'event> File<'event> { name: impl AsRef, subsection_name: Option<&BStr>, ) -> Result, section::header::Error> { - self.section_mut_or_create_new_filter(name, subsection_name, &mut |_| true) + self.section_mut_or_create_new_filter(name, subsection_name, |_| true) } /// Returns an mutable section with a given `name` and optional `subsection_name`, _if it exists_ **and** passes `filter`, or create @@ -70,7 +71,7 @@ impl<'event> File<'event> { &'a mut self, name: impl AsRef, subsection_name: Option<&BStr>, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result, section::header::Error> { self.section_mut_or_create_new_filter_inner(name.as_ref(), subsection_name, filter) } @@ -79,7 +80,7 @@ impl<'event> File<'event> { &'a mut self, name: &str, subsection_name: Option<&BStr>, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result, section::header::Error> { match self .section_ids_by_name_and_subname(name.as_ref(), subsection_name) @@ -110,7 +111,7 @@ impl<'event> File<'event> { &'a mut self, name: impl AsRef, subsection_name: Option<&BStr>, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { self.section_mut_filter_inner(name.as_ref(), subsection_name, filter) } @@ -119,7 +120,7 @@ impl<'event> File<'event> { &'a mut self, name: &str, subsection_name: Option<&BStr>, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { let id = self .section_ids_by_name_and_subname(name, subsection_name)? @@ -137,7 +138,7 @@ impl<'event> File<'event> { pub fn section_mut_filter_by_key<'a, 'b>( &'a mut self, key: impl Into<&'b BStr>, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, 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) @@ -289,7 +290,7 @@ impl<'event> File<'event> { &mut self, name: impl AsRef, subsection_name: impl Into>, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Option> { self.remove_section_filter_inner(name.as_ref(), subsection_name.into(), filter) } @@ -298,7 +299,7 @@ impl<'event> File<'event> { &mut self, name: &str, subsection_name: Option<&BStr>, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Option> { let id = self .section_ids_by_name_and_subname(name, subsection_name) @@ -352,7 +353,7 @@ impl<'event> File<'event> { subsection_name: impl Into>, new_name: impl Into>, new_subsection_name: impl Into>>, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result<(), rename_section::Error> { let id = self .section_ids_by_name_and_subname(name.as_ref(), subsection_name.into())? diff --git a/gix-config/src/file/access/raw.rs b/gix-config/src/file/access/raw.rs index 4013e8627df..c2b8c967f7f 100644 --- a/gix-config/src/file/access/raw.rs +++ b/gix-config/src/file/access/raw.rs @@ -3,8 +3,9 @@ use std::{borrow::Cow, collections::HashMap}; use bstr::BStr; use smallvec::ToSmallVec; +use crate::file::Metadata; use crate::{ - file::{mutable::multi_value::EntryData, Index, MetadataFilter, MultiValueMut, Size, ValueMut}, + file::{mutable::multi_value::EntryData, Index, MultiValueMut, Size, ValueMut}, lookup, parse::{section, Event}, AsKey, File, @@ -20,7 +21,7 @@ impl<'event> File<'event> { /// a multivar instead. pub fn raw_value(&self, key: impl AsKey) -> Result, lookup::existing::Error> { let key = key.as_key(); - self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, &mut |_| true) + self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, |_| true) } /// Returns an uninterpreted value given a section, an optional subsection @@ -34,7 +35,7 @@ impl<'event> File<'event> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Result, lookup::existing::Error> { - self.raw_value_filter_by(section_name, subsection_name, value_name, &mut |_| true) + self.raw_value_filter_by(section_name, subsection_name, value_name, |_| true) } /// Returns an uninterpreted value given a `key`, if it passes the `filter`. @@ -44,7 +45,7 @@ impl<'event> File<'event> { pub fn raw_value_filter( &self, key: impl AsKey, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { let key = key.as_key(); self.raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, filter) @@ -60,7 +61,7 @@ impl<'event> File<'event> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { self.raw_value_filter_inner(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) } @@ -70,7 +71,7 @@ impl<'event> File<'event> { section_name: &str, subsection_name: Option<&BStr>, value_name: &str, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?; for section_id in section_ids.rev() { @@ -110,7 +111,7 @@ impl<'event> File<'event> { subsection_name: Option<&'lookup BStr>, value_name: &'lookup str, ) -> Result, lookup::existing::Error> { - self.raw_value_mut_filter(section_name, subsection_name, value_name, &mut |_| true) + self.raw_value_mut_filter(section_name, subsection_name, value_name, |_| true) } /// Returns a mutable reference to an uninterpreted value given a section, @@ -123,7 +124,7 @@ impl<'event> File<'event> { section_name: impl AsRef, subsection_name: Option<&'lookup BStr>, value_name: &'lookup str, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { self.raw_value_mut_filter_inner(section_name.as_ref(), subsection_name, value_name, filter) } @@ -133,7 +134,7 @@ impl<'event> File<'event> { section_name: &str, subsection_name: Option<&'lookup BStr>, value_name: &'lookup str, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { let mut section_ids = self .section_ids_by_name_and_subname(section_name, subsection_name)? @@ -272,7 +273,7 @@ impl<'event> File<'event> { subsection_name: Option<&BStr>, value_name: impl AsRef, ) -> Result>, lookup::existing::Error> { - self.raw_values_filter_by(section_name, subsection_name, value_name, &mut |_| true) + self.raw_values_filter_by(section_name, subsection_name, value_name, |_| true) } /// Returns all uninterpreted values given a `key`, if the value passes `filter`, in order of occurrence. @@ -282,7 +283,7 @@ impl<'event> File<'event> { pub fn raw_values_filter( &self, key: impl AsKey, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { let key = key.as_key(); self.raw_values_filter_by(key.section_name, key.subsection_name, key.value_name, filter) @@ -298,7 +299,7 @@ impl<'event> File<'event> { section_name: impl AsRef, subsection_name: Option<&BStr>, value_name: impl AsRef, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { self.raw_values_filter_inner(section_name.as_ref(), subsection_name, value_name.as_ref(), filter) } @@ -308,7 +309,7 @@ impl<'event> File<'event> { section_name: &str, subsection_name: Option<&BStr>, value_name: &str, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { let mut values = Vec::new(); let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?; @@ -440,7 +441,7 @@ impl<'event> File<'event> { subsection_name: Option<&'lookup BStr>, value_name: &'lookup str, ) -> Result, lookup::existing::Error> { - self.raw_values_mut_filter_by(section_name, subsection_name, value_name, &mut |_| true) + self.raw_values_mut_filter_by(section_name, subsection_name, value_name, |_| true) } /// Returns mutable references to all uninterpreted values given a `key`, @@ -448,7 +449,7 @@ impl<'event> File<'event> { pub fn raw_values_mut_filter<'lookup>( &mut self, key: &'lookup impl AsKey, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { let key = key.as_key(); self.raw_values_mut_filter_by(key.section_name, key.subsection_name, key.value_name, filter) @@ -461,7 +462,7 @@ impl<'event> File<'event> { section_name: impl AsRef, subsection_name: Option<&'lookup BStr>, value_name: &'lookup str, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { self.raw_values_mut_filter_inner(section_name.as_ref(), subsection_name, value_name, filter) } @@ -471,7 +472,7 @@ impl<'event> File<'event> { section_name: &str, subsection_name: Option<&'lookup BStr>, value_name: &'lookup str, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result, lookup::existing::Error> { let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?; let key = section::ValueName(Cow::::Borrowed(value_name.into())); @@ -692,7 +693,7 @@ impl<'event> File<'event> { Key: TryInto, Error = E>, section::value_name::Error: From, { - self.set_raw_value_filter_by(section_name, subsection_name, value_name, new_value, &mut |_| true) + self.set_raw_value_filter_by(section_name, subsection_name, value_name, new_value, |_| true) } /// Similar to [`set_raw_value()`](Self::set_raw_value()), but only sets existing values in sections matching @@ -701,7 +702,7 @@ impl<'event> File<'event> { &mut self, key: &'event impl AsKey, new_value: impl Into<&'b BStr>, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, crate::file::set_raw_value::Error> { let key = key.as_key(); self.set_raw_value_filter_by(key.section_name, key.subsection_name, key.value_name, new_value, filter) @@ -715,7 +716,7 @@ impl<'event> File<'event> { subsection_name: Option<&BStr>, key: Key, new_value: impl Into<&'b BStr>, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, crate::file::set_raw_value::Error> where Key: TryInto, Error = E>, diff --git a/gix-config/src/file/access/read_only.rs b/gix-config/src/file/access/read_only.rs index c003dea974b..e433bd4d0ae 100644 --- a/gix-config/src/file/access/read_only.rs +++ b/gix-config/src/file/access/read_only.rs @@ -8,7 +8,7 @@ use crate::{ file::{ self, write::{extract_newline, platform_newline}, - Metadata, MetadataFilter, SectionId, + Metadata, SectionId, }, lookup, parse::Event, @@ -232,7 +232,7 @@ impl<'event> File<'event> { name: &str, subsection_name: Option<&BStr>, ) -> Result<&file::Section<'event>, lookup::existing::Error> { - self.section_filter(name, subsection_name, &mut |_| true)? + self.section_filter(name, subsection_name, |_| true)? .ok_or(lookup::existing::Error::SectionMissing) } @@ -252,7 +252,7 @@ impl<'event> File<'event> { &'a self, name: &str, subsection_name: Option<&BStr>, - filter: &mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { Ok(self .section_ids_by_name_and_subname(name.as_ref(), subsection_name)? @@ -270,7 +270,7 @@ impl<'event> File<'event> { pub fn section_filter_by_key<'a>( &'a self, section_key: &BStr, - filter: &mut MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, ) -> Result>, lookup::existing::Error> { let key = crate::parse::section::unvalidated::Key::parse(section_key).ok_or(lookup::existing::Error::KeyMissing)?; @@ -349,7 +349,7 @@ impl<'event> File<'event> { pub fn sections_by_name_and_filter<'a>( &'a self, name: &'a str, - filter: &'a mut MetadataFilter, + mut filter: impl FnMut(&Metadata) -> bool + 'a, ) -> Option> + 'a> { self.section_ids_by_name(name).ok().map(move |ids| { ids.filter_map(move |id| { diff --git a/gix-config/src/file/mod.rs b/gix-config/src/file/mod.rs index 196ae5b4c70..981d325b171 100644 --- a/gix-config/src/file/mod.rs +++ b/gix-config/src/file/mod.rs @@ -75,9 +75,6 @@ pub struct Section<'a> { id: SectionId, } -/// A function to filter metadata, returning `true` if the corresponding but omitted value can be used. -pub type MetadataFilter = dyn FnMut(&'_ Metadata) -> bool; - /// A strongly typed index into some range. #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Clone, Copy)] pub(crate) struct Index(pub(crate) usize); diff --git a/gix-config/src/file/write.rs b/gix-config/src/file/write.rs index 69997eb3c9c..ca5b7f07ac0 100644 --- a/gix-config/src/file/write.rs +++ b/gix-config/src/file/write.rs @@ -18,7 +18,7 @@ impl File<'_> { pub fn write_to_filter( &self, mut out: &mut dyn std::io::Write, - filter: &mut dyn FnMut(&Section<'_>) -> bool, + mut filter: impl FnMut(&Section<'_>) -> bool, ) -> std::io::Result<()> { let nl = self.detect_newline_style(); @@ -27,8 +27,7 @@ impl File<'_> { event.write_to(&mut out)?; } - if !ends_with_newline(self.frontmatter_events.as_ref(), nl, true) - && self.sections.values().any(&mut *filter) + if !ends_with_newline(self.frontmatter_events.as_ref(), nl, true) && self.sections.values().any(&mut filter) { out.write_all(nl)?; } @@ -67,7 +66,7 @@ impl File<'_> { /// Stream ourselves to the given `out`, in order to reproduce this file mostly losslessly /// as it was parsed. pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { - self.write_to_filter(out, &mut |_| true) + self.write_to_filter(out, |_| true) } } diff --git a/gix-config/tests/file/init/from_paths/mod.rs b/gix-config/tests/file/init/from_paths/mod.rs index cc8e307472d..4f333022a5e 100644 --- a/gix-config/tests/file/init/from_paths/mod.rs +++ b/gix-config/tests/file/init/from_paths/mod.rs @@ -165,21 +165,21 @@ fn multiple_paths_multi_value_and_filter() -> crate::Result { ); assert_eq!( - config.string_filter("core.key", &mut |m| m.source == Source::System), + config.string_filter("core.key", |m| m.source == Source::System), Some(cow_str("a")), "the filter discards all values with higher priority" ); assert_eq!( - config.string_filter("core.key", &mut |m| m.source == Source::System), + config.string_filter("core.key", |m| m.source == Source::System), Some(cow_str("a")), ); assert_eq!( - config.strings_filter("core.key", &mut |m| m.source == Source::Git || m.source == Source::User), + config.strings_filter("core.key", |m| m.source == Source::Git || m.source == Source::User), Some(vec![cow_str("b"), cow_str("c")]) ); assert_eq!( - config.strings_filter("core.key", &mut |m| m.source == Source::Git || m.source == Source::User), + config.strings_filter("core.key", |m| m.source == Source::Git || m.source == Source::User), Some(vec![cow_str("b"), cow_str("c")]) ); diff --git a/gix-config/tests/file/mutable/section.rs b/gix-config/tests/file/mutable/section.rs index f37d1691ce9..d272326f3ad 100644 --- a/gix-config/tests/file/mutable/section.rs +++ b/gix-config/tests/file/mutable/section.rs @@ -16,7 +16,7 @@ fn section_mut_or_create_new_is_infallible() -> crate::Result { #[test] fn section_mut_or_create_new_filter_may_reject_existing_sections() -> crate::Result { let mut config = multi_value_section(); - let section = config.section_mut_or_create_new_filter("a", None, &mut |_| false)?; + let section = config.section_mut_or_create_new_filter("a", None, |_| false)?; assert_eq!(section.header().name(), "a"); assert_eq!(section.header().subsection_name(), None); assert_eq!(section.to_bstring(), "[a]\n"); diff --git a/gix-config/tests/file/write.rs b/gix-config/tests/file/write.rs index 7247c0e207e..0ffdcdffff9 100644 --- a/gix-config/tests/file/write.rs +++ b/gix-config/tests/file/write.rs @@ -135,7 +135,7 @@ mod to_filter { .push("c".try_into()?, Some("d".into())); let mut buf = Vec::::new(); - config.write_to_filter(&mut buf, &mut |s| s.meta().source == gix_config::Source::Local)?; + config.write_to_filter(&mut buf, |s| s.meta().source == gix_config::Source::Local)?; let nl = config.detect_newline_style(); assert_eq!(buf.to_str_lossy(), format!("[a \"local\"]{nl}\tb = c{nl}\tc = d{nl}")); diff --git a/gix/src/clone/fetch/util.rs b/gix/src/clone/fetch/util.rs index 7a4347a5e9b..54458c2c9b5 100644 --- a/gix/src/clone/fetch/util.rs +++ b/gix/src/clone/fetch/util.rs @@ -50,7 +50,7 @@ fn write_to_local_config(config: &gix_config::File<'static>, mode: WriteMode) -> .append(matches!(mode, WriteMode::Append)) .open(config.meta().path.as_deref().expect("local config with path set"))?; local_config.write_all(config.detect_newline_style())?; - config.write_to_filter(&mut local_config, &mut |s| s.meta().source == gix_config::Source::Local) + config.write_to_filter(&mut local_config, |s| s.meta().source == gix_config::Source::Local) } pub fn append_config_to_repo_config(repo: &mut Repository, config: gix_config::File<'static>) { diff --git a/gix/src/config/cache/access.rs b/gix/src/config/cache/access.rs index d2aef845902..4e70fd5f178 100644 --- a/gix/src/config/cache/access.rs +++ b/gix/src/config/cache/access.rs @@ -1,7 +1,7 @@ #![allow(clippy::result_large_err)] -use std::{borrow::Cow, path::PathBuf, time::Duration}; - +use gix_config::file::Metadata; use gix_lock::acquire::Fail; +use std::{borrow::Cow, path::PathBuf, time::Duration}; use crate::{ config, @@ -510,7 +510,7 @@ impl Cache { pub(crate) fn trusted_file_path<'config>( config: &'config gix_config::File<'_>, key: impl gix_config::AsKey, - filter: &mut gix_config::file::MetadataFilter, + filter: impl FnMut(&Metadata) -> bool, lenient_config: bool, environment: crate::open::permissions::Environment, ) -> Option, gix_config::path::interpolate::Error>> { diff --git a/gix/src/config/cache/init.rs b/gix/src/config/cache/init.rs index 56eb50e7059..d5e8fb737e4 100644 --- a/gix/src/config/cache/init.rs +++ b/gix/src/config/cache/init.rs @@ -326,6 +326,15 @@ fn apply_environment_overrides( let mut env_override = gix_config::File::new(gix_config::file::Metadata::from(gix_config::Source::EnvOverride)); for (section_name, subsection_name, permission, data) in [ + ( + "core", + None, + git_prefix, + &[{ + let key = &Core::WORKTREE; + (env(key), key.name) + }][..], + ), ( "http", None, diff --git a/gix/src/config/snapshot/credential_helpers.rs b/gix/src/config/snapshot/credential_helpers.rs index bdd0e88efaf..434f37f6e70 100644 --- a/gix/src/config/snapshot/credential_helpers.rs +++ b/gix/src/config/snapshot/credential_helpers.rs @@ -90,7 +90,7 @@ pub(super) mod function { mut url: gix_url::Url, config: &gix_config::File<'_>, is_lenient_config: bool, - filter: &mut gix_config::file::MetadataFilter, + mut filter: impl FnMut(&gix_config::file::Metadata) -> bool, environment: crate::open::permissions::Environment, mut use_http_path: bool, ) -> Result< @@ -105,7 +105,7 @@ pub(super) mod function { let url_had_user_initially = url.user().is_some(); normalize(&mut url); - if let Some(credential_sections) = config.sections_by_name_and_filter("credential", filter) { + if let Some(credential_sections) = config.sections_by_name_and_filter("credential", &mut filter) { for section in credential_sections { let section = match section.header().subsection_name() { Some(pattern) => gix_url::parse(pattern).ok().and_then(|mut pattern| { @@ -181,7 +181,7 @@ pub(super) mod function { askpass: crate::config::cache::access::trusted_file_path( config, &Core::ASKPASS, - filter, + &mut filter, is_lenient_config, environment, ) diff --git a/gix/src/config/tree/sections/core.rs b/gix/src/config/tree/sections/core.rs index d847b4ed75f..44d46317f08 100644 --- a/gix/src/config/tree/sections/core.rs +++ b/gix/src/config/tree/sections/core.rs @@ -58,7 +58,7 @@ impl Core { /// The `core.worktree` key. pub const WORKTREE: keys::Any = keys::Any::new("worktree", &config::Tree::CORE) .with_environment_override("GIT_WORK_TREE") - .with_deviation("Overriding the worktree with environment variables is supported using `ThreadSafeRepository::open_with_environment_overrides()"); + .with_deviation("Command-line overrides also work, and they act lie an environment override. If set in the git configuration file, relative paths are relative to it."); /// The `core.askPass` key. pub const ASKPASS: keys::Executable = keys::Executable::new_executable("askPass", &config::Tree::CORE) .with_environment_override("GIT_ASKPASS") diff --git a/gix/src/open/repository.rs b/gix/src/open/repository.rs index 7e369ffa6b9..e22ac6114cf 100644 --- a/gix/src/open/repository.rs +++ b/gix/src/open/repository.rs @@ -99,7 +99,7 @@ impl ThreadSafeRepository { } /// Try to open a git repository in `fallback_directory` (can be worktree or `.git` directory) only if there is no override - /// from of the `gitdir` using git environment variables. + /// of the `gitdir` using git environment variables. /// /// Use the `trust_map` to apply options depending in the trust level for `directory` or the directory it's overridden with. /// The `.git` directory whether given or computed is used for trust checks. @@ -135,7 +135,7 @@ impl ThreadSafeRepository { } }; - // The be altered later based on `core.precomposeUnicode`. + // To be altered later based on `core.precomposeUnicode`. let cwd = gix_fs::current_dir(false)?; let (git_dir, worktree_dir) = gix_discover::repository::Path::from_dot_git_dir(path, path_kind, &cwd) .expect("we have sanitized path with is_git()") @@ -258,7 +258,20 @@ impl ThreadSafeRepository { // core.worktree might be used to overwrite the worktree directory if !config.is_bare { - if let Some(wt) = config.resolved.path_filter(Core::WORKTREE, &mut filter_config_section) { + let mut key_source = None; + let worktree_path = config + .resolved + .path_filter(Core::WORKTREE, { + |section| { + let res = filter_config_section(section); + if res { + key_source = Some(section.source); + } + res + } + }) + .zip(key_source); + if let Some((wt, key_source)) = worktree_path { let wt_clone = wt.clone(); let wt_path = wt .interpolate(interpolate_context(git_install_dir.as_deref(), home.as_deref())) @@ -266,7 +279,14 @@ impl ThreadSafeRepository { path: wt_clone.value.into_owned(), source: err, })?; - worktree_dir = gix_path::normalize(git_dir.join(wt_path).into(), current_dir).map(Cow::into_owned); + let wt_path = match key_source { + gix_config::Source::Env + | gix_config::Source::Cli + | gix_config::Source::Api + | gix_config::Source::EnvOverride => wt_path, + _ => git_dir.join(wt_path).into(), + }; + worktree_dir = gix_path::normalize(wt_path, current_dir).map(Cow::into_owned); #[allow(unused_variables)] if let Some(worktree_path) = worktree_dir.as_deref().filter(|wtd| !wtd.is_dir()) { gix_trace::warn!("The configured worktree path '{}' is not a directory or doesn't exist - `core.worktree` may be misleading", worktree_path.display()); @@ -284,7 +304,7 @@ impl ThreadSafeRepository { } match worktree_dir { - None if !config.is_bare && refs.git_dir().extension() == Some(OsStr::new(gix_discover::DOT_GIT_DIR)) => { + None if !config.is_bare && refs.git_dir().file_name() == Some(OsStr::new(gix_discover::DOT_GIT_DIR)) => { worktree_dir = Some(git_dir.parent().expect("parent is always available").to_owned()); } Some(_) => { diff --git a/gix/tests/gix/repository/worktree.rs b/gix/tests/gix/repository/worktree.rs index a77eb357e86..4c66b452b97 100644 --- a/gix/tests/gix/repository/worktree.rs +++ b/gix/tests/gix/repository/worktree.rs @@ -44,7 +44,7 @@ mod with_core_worktree_config { assert_eq!( repo.work_dir().unwrap(), repo.git_dir().parent().unwrap().parent().unwrap().join("worktree"), - "work_dir is set to core.worktree config value, relative paths are appended to `git_dir() and made absolute`" + "{name}|{is_relative}: work_dir is set to core.worktree config value, relative paths are appended to `git_dir() and made absolute`" ); } else { assert_eq!( diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 59df7c431e2..944c7c9022f 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -106,8 +106,12 @@ pub fn main() -> Result<()> { }; mapping.full.modify(to_match_settings); mapping.reduced.modify(to_match_settings); - let mut repo = gix::ThreadSafeRepository::discover_opts(repository, Default::default(), mapping) - .map(gix::Repository::from)?; + let mut repo = gix::ThreadSafeRepository::discover_with_environment_overrides_opts( + repository, + Default::default(), + mapping, + ) + .map(gix::Repository::from)?; if !config.is_empty() { repo.config_snapshot_mut() .append_config(config.iter(), gix::config::Source::Cli)