Skip to main content

git_filter_tree/
exe.rs

1use crate::FilterTree;
2use crate::cli::{FilterTreeArgs, OutputFormat};
3use git2 as git;
4
5/// Core filter-tree operation: resolve the treeish, filter by patterns, and
6/// return the OID of the resulting tree.  This is the reusable building-block
7/// that both the plumbing binary and the porcelain CLI can call.
8pub 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
21/// Print a tree according to the requested output format.
22pub 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
57/// Run the full plumbing command: filter and print.
58pub 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}