1use crate::FilterTree;
2use crate::cli::{FilterTreeArgs, OutputFormat};
3use git2 as git;
4
5pub fn filter_tree(
9 repo: &git::Repository,
10 treeish: &str,
11 patterns: &[String],
12) -> Result<git::Oid, Box<dyn std::error::Error>> {
13 let obj = repo.revparse_single(treeish)?;
14 let tree = obj.peel_to_tree()?;
15
16 let pattern_refs: Vec<&str> = patterns.iter().map(|s| s.as_str()).collect();
17 let filtered = repo.filter_by_patterns(&tree, &pattern_refs)?;
18 Ok(filtered.id())
19}
20
21pub fn print_tree(
23 repo: &git::Repository,
24 tree_oid: git::Oid,
25 format: OutputFormat,
26) -> Result<(), Box<dyn std::error::Error>> {
27 let tree = repo.find_tree(tree_oid)?;
28
29 match format {
30 OutputFormat::TreeSha => {
31 println!("{}", tree.id());
32 }
33 OutputFormat::Entries => {
34 for entry in tree.iter() {
35 let name = entry.name().unwrap_or("<invalid-utf8>");
36 let kind = kind_label(entry.kind());
37 println!("{}\t{}", kind, name);
38 }
39 }
40 OutputFormat::Detailed => {
41 println!("Tree: {}", tree.id());
42 println!("Entries: {}", tree.len());
43 println!();
44 for entry in tree.iter() {
45 let name = entry.name().unwrap_or("<invalid-utf8>");
46 let kind = kind_label(entry.kind());
47 let mode = entry.filemode();
48 let id = entry.id();
49 println!("{:06o} {} {}\t{}", mode, kind, id, name);
50 }
51 }
52 }
53
54 Ok(())
55}
56
57pub fn run(args: &FilterTreeArgs) -> Result<(), Box<dyn std::error::Error>> {
59 let repo = git::Repository::open_from_env()?;
60 let tree_oid = filter_tree(&repo, &args.treeish, &args.patterns)?;
61 print_tree(&repo, tree_oid, args.format)?;
62 Ok(())
63}
64
65fn kind_label(kind: Option<git::ObjectType>) -> &'static str {
66 match kind {
67 Some(git::ObjectType::Blob) => "blob",
68 Some(git::ObjectType::Tree) => "tree",
69 Some(git::ObjectType::Commit) => "commit",
70 _ => "unknown",
71 }
72}