diff --git a/src/main.rs b/src/main.rs index 197a993..d275f03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ use std::io::prelude::*; use std::path; use std::process; +const MIRROR_REMOTE_NAME: &str = "mirror"; + fn main() { let config_text = match load_file(&path::Path::new("mira.json")) { Ok(content) => content, @@ -27,16 +29,9 @@ fn load_file(path: &path::Path) -> Result { #[derive(Debug, serde::Deserialize)] struct RootConfig { workspace: String, - auth: serde_json::Value, configurations: Vec, } -/// Authentication options, unused at the moment. -#[derive(Debug, serde::Deserialize)] -struct Authentication { - key: Option, -} - /// Server configuration. #[derive(Debug, serde::Deserialize)] struct Configuration { @@ -77,6 +72,7 @@ fn process_root_config(root_config: &RootConfig) -> bool { enum MirrorResult { Success, CloneFailed, + FetchFailed, RemotesError, PushFailed, } @@ -103,6 +99,10 @@ fn process_config(config: &Configuration, workspace: &path::Path) -> Result { + println!("Failed to fetch changes for {}.", mirror.name); + complete_success = false; + }, Ok(MirrorResult::RemotesError) => { println!("Failed to process remotes for {}.", mirror.name); complete_success = false; @@ -132,19 +132,28 @@ fn mirror_repo( ) -> Result { let mut repo_path = path.to_path_buf(); repo_path.push(name); - // Ensure the repository is cloned. + // Ensure the repository is cloned and up to date. if !repo_path.exists() { if !clone(src_url, path, name) { return Ok(MirrorResult::CloneFailed) } + } else { + if !fetch(&repo_path) { + return Ok(MirrorResult::FetchFailed) + } } // Ensure the mirror remote is available. let remotes = match get_remotes(&repo_path) { Some(remotes) => remotes, None => return Ok(MirrorResult::RemotesError) }; + if !remotes.contains(&MIRROR_REMOTE_NAME.to_string()) { + if !add_mirror_remote(&repo_path, dest_url) { + return Ok(MirrorResult::RemotesError) + } + } // Push to the mirror repo. - if !push(&repo_path, dest_url) { + if !push(&repo_path) { return Ok(MirrorResult::PushFailed) } Ok(MirrorResult::Success) @@ -152,22 +161,37 @@ fn mirror_repo( /// Run a git mirror clone command. fn clone(url: &str, path: &path::Path, name: &str) -> bool { - let (success, _) = run_git_command_in(vec!("clone", "--mirror", url, name), path); + let args = vec!("clone", "--mirror", url, name); + let (success, _) = run_git_command_in(args, path); + success +} + +/// Update a local repository. +fn fetch(path: &path::Path) -> bool { + let (success, _) = run_git_command_in(vec!("fetch"), path); success } /// Return a vector of remote names on success. fn get_remotes(path: &path::Path) -> Option> { let (success, stdout) = run_git_command_in(vec!("remote"), path); - if !success || stdout.is_none() { + if !success { return None } - Some(stdout.unwrap().split_whitespace().map(|s| s.to_string()).collect()) + stdout.and_then(|s| Some(s.split_whitespace().map(|ss| ss.to_string()).collect())) +} + +/// Set the mirror remote `url` in the repository at `path`. +fn add_mirror_remote(path: &path::Path, url: &str) -> bool { + let args = vec!("remote", "add", MIRROR_REMOTE_NAME, url); + let (success, _) = run_git_command_in(args, path); + success } /// Run a git mirror push command. -fn push(path: &path::Path, url: &str) -> bool { - let (success, _) = run_git_command_in(vec!("push", "--mirror", url), path); +fn push(path: &path::Path) -> bool { + let args = vec!("push", "--mirror", MIRROR_REMOTE_NAME); + let (success, _) = run_git_command_in(args, path); success }