use crate::OutputFormat; pub struct Options { pub format: OutputFormat, pub statistics: bool, } pub(crate) mod function { use std::io; use anyhow::bail; use gix::prelude::FindExt; use crate::{ repository::attributes::query::{attributes_cache, Options}, OutputFormat, }; pub fn query( repo: gix::Repository, pathspecs: impl Iterator, mut out: impl io::Write, mut err: impl io::Write, Options { format, statistics }: Options, ) -> anyhow::Result<()> { if format != OutputFormat::Human { bail!("JSON output isn't implemented yet"); } let mut cache = attributes_cache(&repo)?; let prefix = repo.prefix().expect("worktree - we have an index by now")?; let mut matches = cache.attribute_matches(); for mut spec in pathspecs { for path in spec.apply_prefix(&prefix).items() { let is_dir = gix::path::from_bstr(path).metadata().ok().map(|m| m.is_dir()); let entry = cache.at_entry(path, is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?; if !entry.matching_attributes(&mut matches) { continue; } for m in matches.iter() { writeln!( out, "{}:{}:{}\t{}\t{}", m.location.source.map(|p| p.to_string_lossy()).unwrap_or_default(), m.location.sequence_number, m.pattern, path, m.assignment )?; } } } if let Some(stats) = statistics.then(|| cache.take_statistics()) { out.flush()?; writeln!(err, "{stats:#?}").ok(); } Ok(()) } } pub(crate) fn attributes_cache(repo: &gix::Repository) -> anyhow::Result { let index = repo.index_or_load_from_head()?; Ok(repo.attributes( &index, if repo.is_bare() { gix::worktree::cache::state::attributes::Source::IdMapping } else { gix::worktree::cache::state::attributes::Source::WorktreeThenIdMapping }, gix::worktree::cache::state::ignore::Source::IdMapping, None, )?) }