Skip to content

Commit eda39ec

Browse files
committed
feat: gix config with section and sub-section filtering. (#331)
1 parent 6570808 commit eda39ec

File tree

2 files changed

+86
-4
lines changed

2 files changed

+86
-4
lines changed

Diff for: gitoxide-core/src/repository/config.rs

+82-3
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,94 @@ use git_repository as git;
44

55
pub fn list(
66
repo: git::Repository,
7-
_filters: Vec<String>,
7+
filters: Vec<String>,
88
format: OutputFormat,
9-
out: impl std::io::Write,
9+
mut out: impl std::io::Write,
1010
) -> Result<()> {
1111
if format != OutputFormat::Human {
1212
bail!("Only human output format is supported at the moment");
1313
}
1414
let config = repo.config_snapshot();
1515
let config = config.plumbing();
16-
config.write_to(out)?;
16+
if let Some(frontmatter) = config.frontmatter() {
17+
for event in frontmatter {
18+
event.write_to(&mut out)?;
19+
}
20+
}
21+
let filters: Vec<_> = filters.into_iter().map(Filter::new).collect();
22+
let mut last_meta = None;
23+
for (section, matter) in config.sections_and_postmatter() {
24+
if !filters.is_empty() && !filters.iter().any(|filter| filter.matches_section(section)) {
25+
continue;
26+
}
27+
28+
let meta = section.meta();
29+
if last_meta.map_or(true, |last| last != meta) {
30+
write_meta(meta, &mut out)?;
31+
}
32+
last_meta = Some(meta);
33+
34+
section.write_to(&mut out)?;
35+
for event in matter {
36+
event.write_to(&mut out)?;
37+
}
38+
writeln!(&mut out)?;
39+
}
1740
Ok(())
1841
}
42+
43+
struct Filter {
44+
name: String,
45+
subsection: Option<String>,
46+
}
47+
48+
impl Filter {
49+
fn new(input: String) -> Self {
50+
match git::config::parse::key(&input) {
51+
Some(key) => Filter {
52+
name: key.section_name.into(),
53+
subsection: key.subsection_name.map(ToOwned::to_owned),
54+
},
55+
None => Filter {
56+
name: input,
57+
subsection: None,
58+
},
59+
}
60+
}
61+
62+
fn matches_section(&self, section: &git::config::file::Section<'_>) -> bool {
63+
let ignore_case = git::glob::wildmatch::Mode::IGNORE_CASE;
64+
65+
if !git::glob::wildmatch(self.name.as_bytes().into(), section.header().name(), ignore_case) {
66+
return false;
67+
}
68+
match (self.subsection.as_deref(), section.header().subsection_name()) {
69+
(Some(filter), Some(name)) => {
70+
if !git::glob::wildmatch(filter.as_bytes().into(), name, ignore_case) {
71+
return false;
72+
}
73+
}
74+
(None, None) | (None, Some(_)) => {}
75+
_ => return false,
76+
};
77+
true
78+
}
79+
}
80+
81+
fn write_meta(meta: &git::config::file::Metadata, out: &mut impl std::io::Write) -> std::io::Result<()> {
82+
writeln!(
83+
out,
84+
"# From '{}' ({:?}{}{})",
85+
meta.path
86+
.as_deref()
87+
.map(|p| p.display().to_string())
88+
.unwrap_or_else(|| "memory".into()),
89+
meta.source,
90+
(meta.level != 0)
91+
.then(|| format!(", include level {}", meta.level))
92+
.unwrap_or_default(),
93+
(meta.trust != git::sec::Trust::Full)
94+
.then(|| "untrusted")
95+
.unwrap_or_default()
96+
)
97+
}

Diff for: src/plumbing/options.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ pub mod config {
8585
#[derive(Debug, clap::Parser)]
8686
#[clap(subcommand_required(false))]
8787
pub struct Platform {
88-
/// The filter terms to limit the output to matching sections and values only.
88+
/// The filter terms to limit the output to matching sections and subsections only.
89+
///
90+
/// Typical filters are `branch` or `remote.origin` or `remote.or*` - git-style globs are supported
91+
/// and comparisons are case-insensitive.
8992
pub filter: Vec<String>,
9093
}
9194
}

0 commit comments

Comments
 (0)