Skip to main content

walk_tree/
walk_tree.rs

1//! Recursively walk a tree object with [`objects::parse_tree`] (a minimal tree walker).
2//!
3//! Run: `cargo run -p grit-lib --example walk_tree`
4
5use grit_lib::index::MODE_TREE;
6use grit_lib::objects::{parse_tree, serialize_commit, CommitData, ObjectKind};
7use grit_lib::refs;
8use grit_lib::repo::init_repository;
9use grit_lib::rev_parse::resolve_revision;
10use grit_lib::write_tree::write_tree_from_index;
11
12fn walk_tree(
13    repo: &grit_lib::repo::Repository,
14    tree_oid: grit_lib::objects::ObjectId,
15    prefix: &str,
16) -> grit_lib::error::Result<()> {
17    let obj = repo.odb.read(&tree_oid)?;
18    let entries = parse_tree(&obj.data)?;
19    for e in entries {
20        let name = String::from_utf8_lossy(&e.name);
21        let path = if prefix.is_empty() {
22            name.into_owned()
23        } else {
24            format!("{prefix}/{name}")
25        };
26        if e.mode == MODE_TREE {
27            println!("{path}/ (tree {})", e.oid);
28            walk_tree(repo, e.oid, &path)?;
29        } else {
30            println!("{path} -> {}", e.oid);
31        }
32    }
33    Ok(())
34}
35
36fn main() -> grit_lib::error::Result<()> {
37    let root = tempfile::tempdir()?;
38    let repo = init_repository(root.path(), false, "main", None, "files")?;
39
40    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
41
42    let blob_a = repo.odb.write(ObjectKind::Blob, b"a\n")?;
43    let blob_b = repo.odb.write(ObjectKind::Blob, b"b\n")?;
44
45    let mut index = Index::new();
46    for (rel, oid) in [
47        (b"a.txt".as_slice(), blob_a),
48        (b"sub/b.txt".as_slice(), blob_b),
49    ] {
50        let entry = IndexEntry {
51            ctime_sec: 0,
52            ctime_nsec: 0,
53            mtime_sec: 0,
54            mtime_nsec: 0,
55            dev: 0,
56            ino: 0,
57            mode: MODE_REGULAR,
58            uid: 0,
59            gid: 0,
60            size: 0,
61            oid,
62            flags: (rel.len().min(0xfff)) as u16,
63            flags_extended: None,
64            path: rel.to_vec(),
65            base_index_pos: 0,
66        };
67        index.add_or_replace(entry);
68    }
69    repo.write_index(&mut index)?;
70    let index = repo.load_index()?;
71    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
72
73    let commit = CommitData {
74        tree: tree_oid,
75        parents: Vec::new(),
76        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
77        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
78        author_raw: Vec::new(),
79        committer_raw: Vec::new(),
80        encoding: None,
81        message: "tree walk\n".to_owned(),
82        raw_message: None,
83    };
84    let commit_oid = repo
85        .odb
86        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
87    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_oid)?;
88
89    let head_commit = resolve_revision(&repo, "HEAD")?;
90    let commit_obj = repo.odb.read(&head_commit)?;
91    let parsed = grit_lib::objects::parse_commit(&commit_obj.data)?;
92    println!("walking tree at {}", parsed.tree);
93    walk_tree(&repo, parsed.tree, "")?;
94
95    Ok(())
96}