typst local package (tlp) manager
at dev 4.0 kB view raw
1#[cfg(feature = "git2")] 2use std::error::Error; 3use std::path::Path; 4#[cfg(not(feature = "git2"))] 5use std::process::Command; 6 7#[allow(unused)] 8use snafu::{OptionExt as _, ResultExt as _, Whatever}; 9 10#[cfg(feature = "git2")] 11type GitError = Box<dyn Error>; 12#[cfg(not(feature = "git2"))] 13type GitError = Whatever; 14 15pub fn init(at: &Path, _git: &Path) -> Result<(), GitError> { 16 #[cfg(feature = "git2")] 17 git2::Repository::init_opts( 18 at, 19 git2::RepositoryInitOptions::new() 20 .no_reinit(true) 21 .mkdir(false) 22 .mkpath(false) 23 .external_template(false), 24 )?; 25 26 #[cfg(not(feature = "git2"))] 27 run(at, _git, ["init", "-q"], []).whatever_context("failed to run `git init`")?; 28 29 Ok(()) 30} 31 32pub fn commit(at: &Path, files: &str, msg: &str, _git: &Path, _root: bool) -> Result<(), Whatever> { 33 #[cfg(feature = "git2")] 34 { 35 let repo = git2::Repository::open(at).whatever_context("failed to access repository")?; 36 let mut ind = repo.index().whatever_context("failed to get index")?; 37 ind.add_all([files].iter(), git2::IndexAddOption::DEFAULT, None) 38 .whatever_context("failed to add files to index")?; 39 ind.write().whatever_context("failed to write index")?; 40 let oid = ind 41 .write_tree() 42 .whatever_context("failed to write index tree")?; 43 let tree = repo.find_tree(oid).whatever_context("failed to get tree")?; 44 let sig = repo 45 .signature() 46 .whatever_context("failed to obtain signature")?; 47 let parent = (!_root) 48 .then(|| { 49 repo.head() 50 .whatever_context("failed to get HEAD")? 51 .peel_to_commit() 52 .whatever_context("failed to get HEAD commit") 53 }) 54 .transpose()?; 55 repo.commit( 56 Some("HEAD"), 57 &sig, 58 &sig, 59 msg, 60 &tree, 61 parent.as_ref().as_slice(), 62 ) 63 .whatever_context("failed to create commit")?; 64 } 65 66 #[cfg(not(feature = "git2"))] 67 { 68 run(at, _git, ["add", files], []).whatever_context("failed to run `git add *`")?; 69 run(at, _git, ["commit", "-qm", msg], []).whatever_context("failed to run `git commit`")?; 70 } 71 72 Ok(()) 73} 74 75pub fn tag_and_worktree( 76 source: &Path, 77 dest: &Path, 78 tag: &str, 79 _git: &Path, 80) -> Result<(), Whatever> { 81 #[cfg(feature = "git2")] 82 { 83 let repo = 84 git2::Repository::open(source).whatever_context("failed to access repository")?; 85 let head = repo 86 .head() 87 .whatever_context("failed to get HEAD")? 88 .peel(git2::ObjectType::Any) 89 .whatever_context("failed to get HEAD object")?; 90 repo.tag_lightweight(&format!("v{tag}"), &head, false) 91 .whatever_context("failed to create tag")?; 92 93 repo.worktree(tag, &dest.join(tag), None) 94 .whatever_context("failed to create worktree")?; 95 } 96 97 #[cfg(not(feature = "git2"))] 98 { 99 run(source, _git, ["tag", &format!("v{tag}")], []) 100 .whatever_context("failed to run `git tag`")?; 101 run( 102 source, 103 _git, 104 [ 105 "worktree", 106 "add", 107 "-q", 108 &format!("{}", dest.join(tag).display()), 109 &format!("v{tag}"), 110 ], 111 [], 112 ) 113 .whatever_context("failed to run `git worktree add`")?; 114 } 115 116 Ok(()) 117} 118 119#[cfg(not(feature = "git2"))] 120fn run<const N: usize, const M: usize>( 121 at: &Path, 122 git: &Path, 123 args: [&str; N], 124 other_args: [&Path; M], 125) -> Result<(), Whatever> { 126 Command::new(git) 127 .args(args) 128 .args(other_args) 129 .current_dir(at) 130 .status() 131 .whatever_context("couldn't execute command")? 132 .success() 133 .then_some(()) 134 .whatever_context("command failed")?; 135 Ok(()) 136}