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}