2019-02-12 14:51:45 +01:00
|
|
|
//! This module contains the utility functions to manage git repository.
|
|
|
|
|
|
|
|
use std::env;
|
|
|
|
use std::fs::{create_dir_all, remove_dir_all};
|
|
|
|
use std::path::Path;
|
2019-02-21 15:21:27 +01:00
|
|
|
use std::process::{exit, Command, Stdio};
|
2019-02-12 14:51:45 +01:00
|
|
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
|
|
|
use crate::{Error, Result};
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
/// The directory in which the repositories will be cloned and searched.
|
|
|
|
pub static ref GCLONE_PATH: String = {
|
|
|
|
match env::var("GCLONE_PATH") {
|
|
|
|
Ok(d) => d,
|
|
|
|
Err(e) => {
|
|
|
|
let e: Error = e.into();
|
|
|
|
eprintln!("{}", e);
|
|
|
|
exit(1);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! unwrap {
|
|
|
|
($e: expr) => {
|
|
|
|
match $e {
|
|
|
|
Some(e) => e,
|
|
|
|
None => return Err(Error::GitUrlParseError),
|
|
|
|
}
|
2019-02-21 15:21:27 +01:00
|
|
|
};
|
2019-02-12 14:51:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Transforms a git url to a (server, owner, repository) tuple.
|
|
|
|
///
|
|
|
|
/// Returns none if it failed.
|
|
|
|
pub fn parse_url(input: &str) -> Result<(String, String, String)> {
|
|
|
|
if input.starts_with("http") {
|
|
|
|
parse_http_url(input)
|
|
|
|
} else {
|
|
|
|
parse_ssh_url(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parses an HTTP url for a git repository.
|
|
|
|
fn parse_http_url(input: &str) -> Result<(String, String, String)> {
|
|
|
|
let split = input.split("/").collect::<Vec<_>>();
|
|
|
|
if split.len() < 3 {
|
|
|
|
return Err(Error::GitUrlParseError);
|
|
|
|
}
|
|
|
|
|
|
|
|
let repo = String::from(split[split.len() - 1]);
|
|
|
|
let owner = String::from(split[split.len() - 2]);
|
2019-02-21 15:21:27 +01:00
|
|
|
let server = split[2..split.len() - 2].join("/");
|
2019-02-12 14:51:45 +01:00
|
|
|
|
|
|
|
Ok((server, owner, repo))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parses an SSH url for a git repository.
|
|
|
|
fn parse_ssh_url(input: &str) -> Result<(String, String, String)> {
|
|
|
|
let url = unwrap!(input.split("@").nth(1));
|
|
|
|
let mut split = url.split(":");
|
|
|
|
let server = String::from(unwrap!(split.next()));
|
|
|
|
let rest = unwrap!(split.next());
|
|
|
|
|
|
|
|
let mut resplit = rest.split("/");
|
|
|
|
let owner = String::from(unwrap!(resplit.next()));
|
|
|
|
let repo = String::from(unwrap!(resplit.next()));
|
|
|
|
|
|
|
|
Ok((server, owner, repo))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clones a git repository in the right place.
|
|
|
|
///
|
|
|
|
/// If an error happens, it deletes the directory created.
|
|
|
|
pub fn clone<P: AsRef<Path>>(url: &str, place: P) -> Result<()> {
|
|
|
|
match clone_dirty(url, &place) {
|
|
|
|
Ok(o) => Ok(o),
|
|
|
|
Err(e) => {
|
|
|
|
remove_dir_all(&place).ok();
|
|
|
|
Err(e)
|
2019-02-21 15:21:27 +01:00
|
|
|
}
|
2019-02-12 14:51:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clones a git repository in the right place.
|
|
|
|
fn clone_dirty<P: AsRef<Path>>(url: &str, place: P) -> Result<()> {
|
|
|
|
let place = place.as_ref();
|
|
|
|
|
|
|
|
if place.exists() {
|
|
|
|
return Err(Error::PathAlreadyExists);
|
|
|
|
}
|
|
|
|
|
|
|
|
create_dir_all(place)?;
|
|
|
|
|
|
|
|
let command = Command::new("git")
|
|
|
|
.args(&["clone", &url, &place.display().to_string()])
|
|
|
|
.stderr(Stdio::null())
|
|
|
|
.status();
|
|
|
|
|
|
|
|
match command {
|
|
|
|
Err(e) => Err(Error::GitCloneError(Some(e))),
|
2019-02-21 15:21:27 +01:00
|
|
|
Ok(o) if !o.success() => Err(Error::GitCloneError(None)),
|
2019-02-12 14:51:45 +01:00
|
|
|
Ok(_) => Ok(()),
|
|
|
|
}
|
|
|
|
}
|