crate_seq_git/
checkout.rs1use gix::bstr::ByteSlice;
4use gix::object::tree::EntryKind;
5use std::path::Path;
6
7use crate::Error;
8
9pub fn checkout_tag(
20 repo_path: &Path,
21 tag_name: &str,
22) -> Result<tempfile::TempDir, Error> {
23 let repo = gix::discover(repo_path).map_err(|e| Error::OpenRepo {
24 path: repo_path.to_owned(),
25 source: Box::new(e),
26 })?;
27
28 let ref_name = format!("refs/tags/{tag_name}");
29 let mut tag_ref = repo
30 .try_find_reference(&ref_name)
31 .map_err(|e| Error::Object(e.to_string()))?
32 .ok_or_else(|| Error::TagNotFound(tag_name.to_owned()))?;
33
34 let tree = tag_ref
35 .peel_to_tree()
36 .map_err(|e| Error::Peel(e.to_string()))?;
37
38 let tmp = tempfile::TempDir::new()?;
39 write_tree_to_dir(&tree, tmp.path())?;
40 Ok(tmp)
41}
42
43fn write_tree_to_dir(tree: &gix::Tree<'_>, base: &Path) -> Result<(), Error> {
48 for entry_result in tree.iter() {
49 let entry = entry_result.map_err(|e| Error::TreeTraversal(e.to_string()))?;
50 let raw_name = entry.filename().to_str_lossy();
51 let path = base.join(Path::new(raw_name.as_ref()));
52
53 match entry.kind() {
54 EntryKind::Tree => {
55 std::fs::create_dir_all(&path)?;
56 let obj = entry.object().map_err(|e| Error::Object(e.to_string()))?;
57 let subtree = obj
58 .try_into_tree()
59 .map_err(|e| Error::Object(e.to_string()))?;
60 write_tree_to_dir(&subtree, &path)?;
61 }
62 EntryKind::Blob | EntryKind::BlobExecutable => {
63 let obj = entry.object().map_err(|e| Error::Object(e.to_string()))?;
64 let blob = obj
65 .try_into_blob()
66 .map_err(|e| Error::Object(e.to_string()))?;
67 std::fs::write(&path, &blob.data)?;
68 }
69 EntryKind::Link | EntryKind::Commit => {}
70 }
71 }
72 Ok(())
73}