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 if allowed_types.contains(git2::CredentialType::DEFAULT)
37 && let Ok(cred) = Cred::default()
38 {
39 return Ok(cred);
40 }
41
42 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 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
80pub fn branch_wildcard() -> anyhow::Result<Vec<String>> {
82 let repo = Repository::open(".")?;
83 branch_wildcard_from_repo(&repo)
84}
85
86pub 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}