Skip to content

Commit a7258f2

Browse files
committed
[Ninan] Add support to clone using ssh
1 parent 685a1bf commit a7258f2

File tree

4 files changed

+50
-9
lines changed

4 files changed

+50
-9
lines changed

src/clone.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use std::path::Path;
22

33
use clap::{App, Arg, SubCommand};
44
use colored::*;
5+
use git2::{Error as GitError, FetchOptions, RemoteCallbacks};
56
use git2::build::RepoBuilder;
6-
use git2::Error as GitError;
77
use serde::{Deserialize, Serialize};
88

9+
use crate::conf;
910
use crate::git::GitAction;
1011
use crate::input_args::InputArgs;
1112

@@ -81,21 +82,41 @@ pub fn clone(args: InputArgs, mut clone_repos: Vec<GitRepo>) {
8182
}
8283

8384
for remote in remotes_from_args {
84-
let mut clone = GitClone { remote_url: remote.remote_url.as_str(), local_path: Path::new(remote.local_path.as_str()) };
85+
let mut use_ssh = false;
86+
if remote.remote_url.contains("git@") {
87+
use_ssh = true;
88+
}
89+
90+
let mut clone = GitClone {
91+
remote_url: remote.remote_url.as_str(),
92+
local_path: Path::new(remote.local_path.as_str()),
93+
use_ssh: use_ssh,
94+
};
8595
clone.git_action().expect(format!("Failed to clone repo {}, ", remote.remote_url).as_str());
8696
}
8797
}
8898

8999
pub struct GitClone<'a> {
90100
pub remote_url: &'a str,
91101
pub local_path: &'a Path,
102+
pub use_ssh: bool,
92103
}
93104

94-
// Todo: Add spinner to show progress.
95105
impl<'a> GitAction for GitClone<'a> {
96106
fn git_action(&mut self) -> Result<(), GitError> {
97-
RepoBuilder::new()
98-
.clone(self.remote_url, self.local_path)?;
107+
let mut builder = RepoBuilder::new();
108+
109+
if self.use_ssh {
110+
let mut callback = RemoteCallbacks::new();
111+
callback.credentials(conf::ssh_auth_callback);
112+
113+
let mut fetch_options = FetchOptions::new();
114+
fetch_options.remote_callbacks(callback);
115+
116+
builder.fetch_options(fetch_options);
117+
}
118+
119+
builder.clone(self.remote_url, self.local_path)?;
99120
println!("{} - {} {} {:#?}", "Remote repo".green(), self.remote_url.blue(), "cloned locally at".green(),
100121
self.local_path.as_os_str());
101122

src/conf.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::error::Error;
22
use std::fs;
33
use std::path::Path;
44

5+
use git2::{Cred, CredentialType, Error as GitError};
56
use regex::Regex;
67
use serde::{Deserialize, Serialize};
78

@@ -67,3 +68,18 @@ fn create_filter_list(conf: &mut GGConf) -> Result<&mut GGConf, Box<dyn Error>>
6768
conf.filter_list_regex = filter_list;
6869
Ok(conf)
6970
}
71+
72+
pub fn ssh_auth_callback(_user: &str, _user_from_url: Option<&str>, _cred: CredentialType)
73+
-> Result<Cred, GitError> {
74+
match std::env::var("HOME") {
75+
Ok(home) => {
76+
let path = format!("{}/.ssh/id_rsa", home);
77+
let credentials_path = std::path::Path::new(&path);
78+
match credentials_path.exists() {
79+
true => Cred::ssh_key("git", None, credentials_path, None),
80+
false => Err(GitError::from_str(&format!("unable to get key from {}", path))),
81+
}
82+
}
83+
Err(_) => Err(GitError::from_str("unable to get env variable HOME")),
84+
}
85+
}

src/create.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use clap::{App, Arg, SubCommand};
66
use colored::*;
77
use reqwest::{Client, RequestBuilder};
88

9+
use crate::clone::GitClone;
910
use crate::git::GitAction;
1011
use crate::input_args::InputArgs;
11-
use crate::clone::GitClone;
1212

1313
pub fn sub_command<'a, 'b>() -> App<'a, 'b> {
1414
SubCommand::with_name("create")
@@ -50,7 +50,12 @@ pub fn create(args: InputArgs) {
5050
process::exit(1);
5151
});
5252

53-
let mut clone = GitClone { remote_url: remote_url.as_str(), local_path: root_path.as_path() };
53+
let mut clone = GitClone {
54+
remote_url: remote_url.as_str(),
55+
local_path: root_path.as_path(),
56+
use_ssh: false,
57+
};
58+
5459
clone.git_action().expect(format!("Failed to clone repo {}, ", remote_url).as_str());
5560
}
5661

src/fetch.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,11 @@ fn fetch_repo<'a>(repo: Repository) -> Result<(), Box<dyn Error>> {
6666
let remote = "origin";
6767
print!("{} {} {} {:#?} -> ", "\nFetching".blue(), remote.blue(), "for".blue(), path);
6868

69-
let mut cb = RemoteCallbacks::new();
70-
7169
let remote = repo
7270
.find_remote(remote)
7371
.or_else(|_| repo.remote_anonymous(remote))?;
7472

73+
let mut cb = RemoteCallbacks::new();
7574
cb.credentials(git_credentials_callback);
7675

7776
let mut fo = FetchOptions::new();

0 commit comments

Comments
 (0)