extern crate git2;
use git2::Repository;
use std::path::{Path, PathBuf};
pub(crate) const PROMPT_GIT_BRANCH: &str = "${GIT_BRANCH}";
pub(crate) const PROMPT_GIT_COMMIT: &str = "${GIT_COMMIT}";
pub fn find_repository(wrkdir: &PathBuf) -> Option<Repository> {
let wrkdir_path: &Path = wrkdir.as_path();
match Repository::discover(wrkdir_path) {
Ok(repo) => Some(repo),
Err(_) => None,
}
}
pub fn get_branch(repository: &Repository) -> Option<String> {
let git_head = match repository.head() {
Ok(head) => head,
Err(_) => return None,
};
let shorthand = git_head.shorthand();
shorthand.map(std::string::ToString::to_string)
}
pub fn get_commit(repository: &Repository, hashlen: usize) -> Option<String> {
let git_head = match repository.head() {
Ok(head) => head,
Err(_) => return None,
};
let head_commit = match git_head.peel_to_commit() {
Ok(cmt_res) => cmt_res,
Err(_) => return None,
};
let commit_oid = head_commit.id();
Some(bytes_to_hexstr(commit_oid.as_bytes(), hashlen))
}
fn bytes_to_hexstr(bytes: &[u8], len: usize) -> String {
bytes
.iter()
.map(|b| format!("{:02x}", b))
.collect::<Vec<String>>()
.join("")
.chars()
.take(len)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_prompt_git_module_empty() {
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
Repository::init(tmpdir.path()).unwrap();
let path_str: PathBuf = PathBuf::from(tmpdir.path());
let repo: Repository = find_repository(&path_str).unwrap();
assert!(get_branch(&repo).is_none());
assert!(get_commit(&repo, 8).is_none());
}
#[test]
fn test_prompt_git_module_with_commits() {
let repo: Repository = find_repository(&PathBuf::from("./")).unwrap();
let branch = get_branch(&repo);
assert!(branch.is_some());
println!("Current branch {}", branch.unwrap());
let commit = get_commit(&repo, 8);
assert!(commit.is_some());
println!("Current commit {}", commit.as_ref().unwrap());
assert_eq!(commit.unwrap().len(), 8);
}
#[test]
fn test_prompt_git_repo_not_found() {
assert!(find_repository(&PathBuf::from("/")).is_none());
}
}