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 tracing::trace!(%url, %branch, "fetching remote branch hash");
24 let mut callbacks = RemoteCallbacks::new();
25
26 callbacks.credentials(|_url, username_from_url, allowed_types| {
27 let username = username_from_url.unwrap_or("git");
28 let ssh_key_path = find_ssh_key()?;
29
30 if allowed_types.contains(git2::CredentialType::SSH_KEY)
31 && let Ok(cred) = Cred::ssh_key(username, None, &ssh_key_path, None)
32 {
33 return Ok(cred);
34 }
35
36 if allowed_types.contains(git2::CredentialType::DEFAULT)
38 && let Ok(cred) = Cred::default()
39 {
40 return Ok(cred);
41 }
42
43 if allowed_types.contains(git2::CredentialType::SSH_KEY)
45 && let Ok(cred) = Cred::ssh_key_from_agent(username)
46 {
47 return Ok(cred);
48 }
49
50 Err(git2::Error::from_str("No authentication methods available"))
51 });
52
53 let mut remote = Remote::create_detached(url)?;
54 remote.connect_auth(git2::Direction::Fetch, Some(callbacks), None)?;
55 tracing::debug!(%url, %branch, "remote connected");
56
57 let refs = remote.list()?;
58 tracing::debug!(%url, %branch, refs = refs.len(), "listing remote refs");
59
60 let branch_name = if let Some(end) = branch.strip_prefix("origin/") {
61 end
62 } else {
63 branch
64 };
65
66 for r in refs {
67 let name = r.name();
68 if name.ends_with(branch_name) {
69 return Ok(r.oid().to_string());
70 }
71 }
72
73 Err(git2::Error::from_str(&format!("Branch {branch} not found")))
74}
75
76pub fn branch_wildcard() -> anyhow::Result<Vec<String>> {
78 let repo = Repository::open(".")?;
79 branch_wildcard_from_repo(&repo)
80}
81
82pub fn branch_wildcard_from_repo(repo: &Repository) -> anyhow::Result<Vec<String>> {
84 let branches = repo.branches(Some(BranchType::Remote))?;
85
86 let names: Vec<_> = branches
87 .into_iter()
88 .map(|b| {
89 let (branche, _) = b?;
90 let name = branche.name()?;
91 Ok(name.unwrap_or("").to_string())
92 })
93 .collect::<Result<Vec<_>, git2::Error>>()?;
94
95 Ok(names)
96}