core_lib/git/
remote.rs

1#![allow(dead_code)]
2use std::path::PathBuf;
3
4use dirs::home_dir;
5use git2::{BranchType, Cred, Error, Remote, RemoteCallbacks, Repository};
6
7pub fn find_ssh_key() -> Result<PathBuf, Error> {
8    let keys_name = vec![String::from("id_ed25519"), String::from("id_rsa")];
9    for k in keys_name {
10        let ssh_key_path = home_dir()
11            .map(|h| h.join(".ssh/").join(k))
12            .expect("Failed to find HOME directory");
13        if ssh_key_path.exists() {
14            return Ok(ssh_key_path);
15        }
16    }
17    Err(git2::Error::from_str(
18        "Failed to find ssh_key on your machine :/",
19    ))
20}
21
22pub fn get_remote_branch_hash(url: &str, branch: &str) -> Result<String, Error> {
23    let mut callbacks = RemoteCallbacks::new();
24
25    callbacks.credentials(|_url, username_from_url, allowed_types| {
26        let username = username_from_url.unwrap_or("git");
27        let ssh_key_path = find_ssh_key()?;
28
29        if allowed_types.contains(git2::CredentialType::SSH_KEY)
30            && let Ok(cred) = Cred::ssh_key(username, None, &ssh_key_path, None)
31        {
32            return Ok(cred);
33        }
34
35        // Try default credentials
36        if allowed_types.contains(git2::CredentialType::DEFAULT)
37            && let Ok(cred) = Cred::default()
38        {
39            return Ok(cred);
40        }
41
42        // Try ssh-agent
43        if allowed_types.contains(git2::CredentialType::SSH_KEY)
44            && let Ok(cred) = Cred::ssh_key_from_agent(username)
45        {
46            return Ok(cred);
47        }
48
49        Err(git2::Error::from_str("No authentication methods available"))
50    });
51
52    let mut remote = Remote::create_detached(url)?;
53    remote.connect_auth(git2::Direction::Fetch, Some(callbacks), None)?;
54
55    let refs = remote.list()?;
56    // let ref_to_find = format!("refs/heads/{branch}");
57
58    // for r in refs {
59    //     if r.name() == ref_to_find {
60    //         return Ok(r.oid().to_string());
61    //     }
62    // }
63
64    let branch_name = if let Some(end) = branch.strip_prefix("origin/") {
65        end
66    } else {
67        branch
68    };
69
70    for r in refs {
71        let name = r.name();
72        if name.ends_with(branch_name) {
73            return Ok(r.oid().to_string());
74        }
75    }
76
77    Err(git2::Error::from_str(&format!("Branch {branch} not found")))
78}
79
80/// search in current repository all remotes branches and store it in Vec<String>
81pub fn branch_wildcard() -> anyhow::Result<Vec<String>> {
82    let repo = Repository::open(".")?;
83    branch_wildcard_from_repo(&repo)
84}
85
86// search in the repo provided in argument all remotes branches and store it in Vec<String>
87pub fn branch_wildcard_from_repo(repo: &Repository) -> anyhow::Result<Vec<String>> {
88    let branches = repo.branches(Some(BranchType::Remote))?;
89
90    let names: Vec<_> = branches
91        .into_iter()
92        .map(|b| {
93            let (branche, _) = b?;
94            let name = branche.name()?;
95            Ok(name.unwrap_or("").to_string())
96        })
97        .collect::<Result<Vec<_>, git2::Error>>()?;
98
99    Ok(names)
100}