Recursively build tree objects for `entries` rooted at `prefix`. Returns the sha1 of the root tree.
(
git_dir: &std::path::Path,
entries: &HashMap<String, String>,
prefix: &str,
)
| 88 | /// Recursively build tree objects for `entries` rooted at `prefix`. |
| 89 | /// Returns the sha1 of the root tree. |
| 90 | fn build_tree( |
| 91 | git_dir: &std::path::Path, |
| 92 | entries: &HashMap<String, String>, |
| 93 | prefix: &str, |
| 94 | ) -> Result<String> { |
| 95 | let mut blobs: Vec<(String, String)> = Vec::new(); |
| 96 | let mut dirs: std::collections::BTreeMap<String, HashMap<String, String>> = |
| 97 | std::collections::BTreeMap::new(); |
| 98 | |
| 99 | for (path, sha1) in entries { |
| 100 | let rel = if prefix.is_empty() { |
| 101 | path.as_str() |
| 102 | } else { |
| 103 | path.strip_prefix(&format!("{prefix}/")).unwrap_or(path) |
| 104 | }; |
| 105 | if let Some((dir, _rest)) = rel.split_once('/') { |
| 106 | dirs.entry(dir.to_string()) |
| 107 | .or_default() |
| 108 | .insert(path.clone(), sha1.clone()); |
| 109 | } else { |
| 110 | blobs.push((rel.to_string(), sha1.clone())); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | let mut dir_shas: Vec<(String, String)> = dirs |
| 115 | .into_par_iter() |
| 116 | .map(|(name, sub_entries)| { |
| 117 | let sub_prefix = if prefix.is_empty() { |
| 118 | name.clone() |
| 119 | } else { |
| 120 | format!("{prefix}/{name}") |
| 121 | }; |
| 122 | let sub_sha = build_tree(git_dir, &sub_entries, &sub_prefix)?; |
| 123 | Ok((name, sub_sha)) |
| 124 | }) |
| 125 | .collect::<Result<_>>()?; |
| 126 | dir_shas.sort_unstable_by(|a, b| a.0.cmp(&b.0)); |
| 127 | |
| 128 | let mut mktree_input = String::new(); |
| 129 | for (name, sub_sha) in &dir_shas { |
| 130 | mktree_input.push_str(&format!("040000 tree {sub_sha}\t{name}\n")); |
| 131 | } |
| 132 | for (name, sha1) in &blobs { |
| 133 | mktree_input.push_str(&format!("100644 blob {sha1}\t{name}\n")); |
| 134 | } |
| 135 | |
| 136 | let cmd = git_cmd(git_dir, ["mktree"]); |
| 137 | Ok(exec(cmd, Some(mktree_input)) |
| 138 | .context("failed to run mktree")? |
| 139 | .trim() |
| 140 | .to_string()) |
| 141 | } |
| 142 | |
| 143 | /// Build a path → oid map for a commit using `git ls-tree -r`. |
| 144 | fn build_path_to_oid( |