pyc_shell/shell/prompt/modules/git.rs
1//! ## Git
2//!
3//! `Git` is the module which provides git repository information
4
5/*
6*
7* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
8*
9* This file is part of "Pyc"
10*
11* Pyc is free software: you can redistribute it and/or modify
12* it under the terms of the GNU General Public License as published by
13* the Free Software Foundation, either version 3 of the License, or
14* (at your option) any later version.
15*
16* Pyc is distributed in the hope that it will be useful,
17* but WITHOUT ANY WARRANTY; without even the implied warranty of
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19* GNU General Public License for more details.
20*
21* You should have received a copy of the GNU General Public License
22* along with Pyc. If not, see <http://www.gnu.org/licenses/>.
23*
24*/
25
26extern crate git2;
27
28use git2::Repository;
29use std::path::{Path, PathBuf};
30
31//Keys
32pub(crate) const PROMPT_GIT_BRANCH: &str = "${GIT_BRANCH}";
33pub(crate) const PROMPT_GIT_COMMIT: &str = "${GIT_COMMIT}";
34
35/// ### find_repository
36///
37/// Find repository in the current path
38pub fn find_repository(wrkdir: &PathBuf) -> Option<Repository> {
39 let wrkdir_path: &Path = wrkdir.as_path();
40 //Find repository
41 match Repository::discover(wrkdir_path) {
42 Ok(repo) => Some(repo),
43 Err(_) => None,
44 }
45}
46
47/// ### get_branch
48///
49/// Get current branch from provided repository
50pub fn get_branch(repository: &Repository) -> Option<String> {
51 let git_head = match repository.head() {
52 Ok(head) => head,
53 Err(_) => return None,
54 };
55 let shorthand = git_head.shorthand();
56 shorthand.map(std::string::ToString::to_string)
57}
58
59/// ### get_commit
60///
61/// Get current commit
62pub fn get_commit(repository: &Repository, hashlen: usize) -> Option<String> {
63 let git_head = match repository.head() {
64 Ok(head) => head,
65 Err(_) => return None,
66 };
67 let head_commit = match git_head.peel_to_commit() {
68 Ok(cmt_res) => cmt_res,
69 Err(_) => return None,
70 };
71 let commit_oid = head_commit.id();
72 Some(bytes_to_hexstr(commit_oid.as_bytes(), hashlen))
73}
74
75/// ### bytes_to_hexstr
76///
77/// Convert bytes to hex string representation
78fn bytes_to_hexstr(bytes: &[u8], len: usize) -> String {
79 bytes
80 .iter()
81 .map(|b| format!("{:02x}", b))
82 .collect::<Vec<String>>()
83 .join("")
84 .chars()
85 .take(len)
86 .collect()
87}
88
89//@! Tests
90
91#[cfg(test)]
92mod tests {
93
94 use super::*;
95
96 #[test]
97 fn test_prompt_git_module_empty() {
98 //Create temp directory
99 let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
100 Repository::init(tmpdir.path()).unwrap();
101 //Initialize module
102 let path_str: PathBuf = PathBuf::from(tmpdir.path());
103 let repo: Repository = find_repository(&path_str).unwrap();
104 //Branch should be none
105 assert!(get_branch(&repo).is_none());
106 //Commit should be None
107 assert!(get_commit(&repo, 8).is_none());
108 }
109
110 #[test]
111 fn test_prompt_git_module_with_commits() {
112 /*
113 //Create temp directory
114 let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
115 let repo: Repository = Repository::init(tmpdir.path()).unwrap();
116 //Write a file
117 let path_str: String = String::from(tmpdir.path().to_str().unwrap());
118 let readme: String = String::from(format!("{}/README.md", path_str.clone()));
119 let mut file = File::create(readme.clone()).unwrap();
120 assert!(file.write_all(b"# Test repository\n\nThis is a test repository\n").is_ok());
121 //Add file
122 repo.
123 */
124 //Initialize module
125 let repo: Repository = find_repository(&PathBuf::from("./")).unwrap();
126 //Branch should be none
127 let branch = get_branch(&repo);
128 assert!(branch.is_some());
129 println!("Current branch {}", branch.unwrap());
130 //Commit should be None
131 let commit = get_commit(&repo, 8);
132 assert!(commit.is_some());
133 println!("Current commit {}", commit.as_ref().unwrap());
134 assert_eq!(commit.unwrap().len(), 8);
135 }
136
137 #[test]
138 fn test_prompt_git_repo_not_found() {
139 assert!(find_repository(&PathBuf::from("/")).is_none());
140 }
141}