ghtool/
git.rs

1use eyre::Result;
2use std::path::PathBuf;
3
4#[derive(Debug, Clone)]
5pub struct Repository {
6    pub owner: String,
7    pub name: String,
8    pub hostname: String,
9}
10
11impl std::fmt::Display for Repository {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        write!(f, "{}/{}/{}", self.hostname, self.owner, self.name)
14    }
15}
16
17pub struct Git {
18    pub directory: PathBuf,
19}
20
21const GITHUB_HOSTNAME: &str = "github.com";
22
23// Example url: git@github.com:raine/tgreddit.git
24fn parse_repository(url: &str) -> Result<Repository> {
25    let mut parts = url.trim().split(':');
26    let host = parts.next();
27    let mut parts = parts.next().unwrap().split('/');
28    let owner = parts.next().unwrap().to_string();
29    let name = parts
30        .next()
31        .unwrap()
32        .strip_suffix(".git")
33        .unwrap()
34        .to_string();
35    let hostname = host.unwrap().split('@').nth(1).unwrap().to_string();
36    Ok(Repository {
37        owner,
38        name,
39        hostname,
40    })
41}
42
43// Example input: raine/tgreddit
44pub fn parse_repository_from_github(s: &str) -> Result<Repository> {
45    let mut parts = s.trim().split('/');
46    let owner = parts.next().unwrap().to_string();
47    let name = parts.next().unwrap().to_string();
48    let hostname = GITHUB_HOSTNAME.to_string();
49
50    Ok(Repository {
51        owner,
52        name,
53        hostname,
54    })
55}
56
57impl Git {
58    pub fn new(directory: PathBuf) -> Self {
59        Self { directory }
60    }
61
62    pub fn get_branch(&self) -> Result<String> {
63        let output = std::process::Command::new("git")
64            .arg("rev-parse")
65            .arg("--abbrev-ref")
66            .arg("HEAD")
67            .current_dir(&self.directory)
68            .output()?;
69        let branch = String::from_utf8(output.stdout)?;
70        Ok(branch.trim().to_string())
71    }
72
73    pub fn get_remote(&self) -> Result<Repository> {
74        let output = std::process::Command::new("git")
75            .arg("remote")
76            .arg("get-url")
77            .arg("origin")
78            .current_dir(&self.directory)
79            .output()?;
80        let url = String::from_utf8(output.stdout)?;
81        let repository = parse_repository(&url)?;
82        Ok(repository)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use pretty_assertions::assert_eq;
90
91    #[test]
92    fn test_parse_repository() {
93        let url = "git@github.com:raine/tgreddit.git";
94        let repository = parse_repository(url).unwrap();
95        assert_eq!(repository.owner, "raine");
96        assert_eq!(repository.name, "tgreddit");
97        assert_eq!(repository.hostname, "github.com");
98    }
99}