#[cfg(feature = "git2")] use std::error::Error; use std::path::Path; #[cfg(not(feature = "git2"))] use std::process::Command; #[allow(unused)] use snafu::{OptionExt as _, ResultExt as _, Whatever}; #[cfg(feature = "git2")] type GitError = Box; #[cfg(not(feature = "git2"))] type GitError = Whatever; pub fn init(at: &Path, _git: &Path) -> Result<(), GitError> { #[cfg(feature = "git2")] git2::Repository::init_opts( at, git2::RepositoryInitOptions::new() .no_reinit(true) .mkdir(false) .mkpath(false) .external_template(false), )?; #[cfg(not(feature = "git2"))] run(at, _git, ["init", "-q"], []).whatever_context("failed to run `git init`")?; Ok(()) } pub fn commit(at: &Path, files: &str, msg: &str, _git: &Path, _root: bool) -> Result<(), Whatever> { #[cfg(feature = "git2")] { let repo = git2::Repository::open(at).whatever_context("failed to access repository")?; let mut ind = repo.index().whatever_context("failed to get index")?; ind.add_all([files].iter(), git2::IndexAddOption::DEFAULT, None) .whatever_context("failed to add files to index")?; ind.write().whatever_context("failed to write index")?; let oid = ind .write_tree() .whatever_context("failed to write index tree")?; let tree = repo.find_tree(oid).whatever_context("failed to get tree")?; let sig = repo .signature() .whatever_context("failed to obtain signature")?; let parent = (!_root) .then(|| { repo.head() .whatever_context("failed to get HEAD")? .peel_to_commit() .whatever_context("failed to get HEAD commit") }) .transpose()?; repo.commit( Some("HEAD"), &sig, &sig, msg, &tree, parent.as_ref().as_slice(), ) .whatever_context("failed to create commit")?; } #[cfg(not(feature = "git2"))] { run(at, _git, ["add", files], []).whatever_context("failed to run `git add *`")?; run(at, _git, ["commit", "-qm", msg], []).whatever_context("failed to run `git commit`")?; } Ok(()) } pub fn tag_and_worktree( source: &Path, dest: &Path, tag: &str, _git: &Path, ) -> Result<(), Whatever> { #[cfg(feature = "git2")] { let repo = git2::Repository::open(source).whatever_context("failed to access repository")?; let head = repo .head() .whatever_context("failed to get HEAD")? .peel(git2::ObjectType::Any) .whatever_context("failed to get HEAD object")?; repo.tag_lightweight(&format!("v{tag}"), &head, false) .whatever_context("failed to create tag")?; repo.worktree(tag, &dest.join(tag), None) .whatever_context("failed to create worktree")?; } #[cfg(not(feature = "git2"))] { run(source, _git, ["tag", &format!("v{tag}")], []) .whatever_context("failed to run `git tag`")?; run( source, _git, [ "worktree", "add", "-q", &format!("{}", dest.join(tag).display()), &format!("v{tag}"), ], [], ) .whatever_context("failed to run `git worktree add`")?; } Ok(()) } #[cfg(not(feature = "git2"))] fn run( at: &Path, git: &Path, args: [&str; N], other_args: [&Path; M], ) -> Result<(), Whatever> { Command::new(git) .args(args) .args(other_args) .current_dir(at) .status() .whatever_context("couldn't execute command")? .success() .then_some(()) .whatever_context("command failed")?; Ok(()) }