Skip to content

Commit

Permalink
feat: gix config with section and sub-section filtering. (#331)
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Jul 21, 2022
1 parent 6570808 commit eda39ec
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 4 deletions.
85 changes: 82 additions & 3 deletions gitoxide-core/src/repository/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,94 @@ use git_repository as git;

pub fn list(
repo: git::Repository,
_filters: Vec<String>,
filters: Vec<String>,
format: OutputFormat,
out: impl std::io::Write,
mut out: impl std::io::Write,
) -> Result<()> {
if format != OutputFormat::Human {
bail!("Only human output format is supported at the moment");
}
let config = repo.config_snapshot();
let config = config.plumbing();
config.write_to(out)?;
if let Some(frontmatter) = config.frontmatter() {
for event in frontmatter {
event.write_to(&mut out)?;
}
}
let filters: Vec<_> = filters.into_iter().map(Filter::new).collect();
let mut last_meta = None;
for (section, matter) in config.sections_and_postmatter() {
if !filters.is_empty() && !filters.iter().any(|filter| filter.matches_section(section)) {
continue;
}

let meta = section.meta();
if last_meta.map_or(true, |last| last != meta) {
write_meta(meta, &mut out)?;
}
last_meta = Some(meta);

section.write_to(&mut out)?;
for event in matter {
event.write_to(&mut out)?;
}
writeln!(&mut out)?;
}
Ok(())
}

struct Filter {
name: String,
subsection: Option<String>,
}

impl Filter {
fn new(input: String) -> Self {
match git::config::parse::key(&input) {
Some(key) => Filter {
name: key.section_name.into(),
subsection: key.subsection_name.map(ToOwned::to_owned),
},
None => Filter {
name: input,
subsection: None,
},
}
}

fn matches_section(&self, section: &git::config::file::Section<'_>) -> bool {
let ignore_case = git::glob::wildmatch::Mode::IGNORE_CASE;

if !git::glob::wildmatch(self.name.as_bytes().into(), section.header().name(), ignore_case) {
return false;
}
match (self.subsection.as_deref(), section.header().subsection_name()) {
(Some(filter), Some(name)) => {
if !git::glob::wildmatch(filter.as_bytes().into(), name, ignore_case) {
return false;
}
}
(None, None) | (None, Some(_)) => {}
_ => return false,
};
true
}
}

fn write_meta(meta: &git::config::file::Metadata, out: &mut impl std::io::Write) -> std::io::Result<()> {
writeln!(
out,
"# From '{}' ({:?}{}{})",
meta.path
.as_deref()
.map(|p| p.display().to_string())
.unwrap_or_else(|| "memory".into()),
meta.source,
(meta.level != 0)
.then(|| format!(", include level {}", meta.level))
.unwrap_or_default(),
(meta.trust != git::sec::Trust::Full)
.then(|| "untrusted")
.unwrap_or_default()
)
}
5 changes: 4 additions & 1 deletion src/plumbing/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ pub mod config {
#[derive(Debug, clap::Parser)]
#[clap(subcommand_required(false))]
pub struct Platform {
/// The filter terms to limit the output to matching sections and values only.
/// The filter terms to limit the output to matching sections and subsections only.
///
/// Typical filters are `branch` or `remote.origin` or `remote.or*` - git-style globs are supported
/// and comparisons are case-insensitive.
pub filter: Vec<String>,
}
}
Expand Down

0 comments on commit eda39ec

Please sign in to comment.