diff --git a/src/clone.rs b/src/clone.rs index b2c63c9..b36bc64 100644 --- a/src/clone.rs +++ b/src/clone.rs @@ -2,10 +2,11 @@ use std::path::Path; use clap::{App, Arg, SubCommand}; use colored::*; +use git2::{Error as GitError, FetchOptions, RemoteCallbacks}; use git2::build::RepoBuilder; -use git2::Error as GitError; use serde::{Deserialize, Serialize}; +use crate::conf; use crate::git::GitAction; use crate::input_args::InputArgs; @@ -81,7 +82,16 @@ pub fn clone(args: InputArgs, mut clone_repos: Vec) { } for remote in remotes_from_args { - let mut clone = GitClone { remote_url: remote.remote_url.as_str(), local_path: Path::new(remote.local_path.as_str()) }; + let mut use_ssh = false; + if remote.remote_url.contains("git@") { + use_ssh = true; + } + + let mut clone = GitClone { + remote_url: remote.remote_url.as_str(), + local_path: Path::new(remote.local_path.as_str()), + use_ssh: use_ssh, + }; clone.git_action().expect(format!("Failed to clone repo {}, ", remote.remote_url).as_str()); } } @@ -89,13 +99,24 @@ pub fn clone(args: InputArgs, mut clone_repos: Vec) { pub struct GitClone<'a> { pub remote_url: &'a str, pub local_path: &'a Path, + pub use_ssh: bool, } -// Todo: Add spinner to show progress. impl<'a> GitAction for GitClone<'a> { fn git_action(&mut self) -> Result<(), GitError> { - RepoBuilder::new() - .clone(self.remote_url, self.local_path)?; + let mut builder = RepoBuilder::new(); + + if self.use_ssh { + let mut callback = RemoteCallbacks::new(); + callback.credentials(conf::ssh_auth_callback); + + let mut fetch_options = FetchOptions::new(); + fetch_options.remote_callbacks(callback); + + builder.fetch_options(fetch_options); + } + + builder.clone(self.remote_url, self.local_path)?; println!("{} - {} {} {:#?}", "Remote repo".green(), self.remote_url.blue(), "cloned locally at".green(), self.local_path.as_os_str()); diff --git a/src/conf.rs b/src/conf.rs index df51f26..6e7b579 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -2,6 +2,7 @@ use std::error::Error; use std::fs; use std::path::Path; +use git2::{Cred, CredentialType, Error as GitError}; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -67,3 +68,18 @@ fn create_filter_list(conf: &mut GGConf) -> Result<&mut GGConf, Box> conf.filter_list_regex = filter_list; Ok(conf) } + +pub fn ssh_auth_callback(_user: &str, _user_from_url: Option<&str>, _cred: CredentialType) + -> Result { + match std::env::var("HOME") { + Ok(home) => { + let path = format!("{}/.ssh/id_rsa", home); + let credentials_path = std::path::Path::new(&path); + match credentials_path.exists() { + true => Cred::ssh_key("git", None, credentials_path, None), + false => Err(GitError::from_str(&format!("unable to get key from {}", path))), + } + } + Err(_) => Err(GitError::from_str("unable to get env variable HOME")), + } +} diff --git a/src/create.rs b/src/create.rs index 4488c89..3bc606f 100644 --- a/src/create.rs +++ b/src/create.rs @@ -6,9 +6,9 @@ use clap::{App, Arg, SubCommand}; use colored::*; use reqwest::{Client, RequestBuilder}; +use crate::clone::GitClone; use crate::git::GitAction; use crate::input_args::InputArgs; -use crate::clone::GitClone; pub fn sub_command<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("create") @@ -50,7 +50,12 @@ pub fn create(args: InputArgs) { process::exit(1); }); - let mut clone = GitClone { remote_url: remote_url.as_str(), local_path: root_path.as_path() }; + let mut clone = GitClone { + remote_url: remote_url.as_str(), + local_path: root_path.as_path(), + use_ssh: false, + }; + clone.git_action().expect(format!("Failed to clone repo {}, ", remote_url).as_str()); } diff --git a/src/fetch.rs b/src/fetch.rs index 33f24a4..17b0655 100644 --- a/src/fetch.rs +++ b/src/fetch.rs @@ -66,12 +66,11 @@ fn fetch_repo<'a>(repo: Repository) -> Result<(), Box> { let remote = "origin"; print!("{} {} {} {:#?} -> ", "\nFetching".blue(), remote.blue(), "for".blue(), path); - let mut cb = RemoteCallbacks::new(); - let remote = repo .find_remote(remote) .or_else(|_| repo.remote_anonymous(remote))?; + let mut cb = RemoteCallbacks::new(); cb.credentials(git_credentials_callback); let mut fo = FetchOptions::new();