From 2f2292342a980d3d88df4e76b37364816f21c04a Mon Sep 17 00:00:00 2001 From: dece Date: Sat, 5 Dec 2020 17:21:57 +0100 Subject: [PATCH] Init --- .gitignore | 1 + Cargo.lock | 87 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 9 +++++ README.md | 5 +++ src/main.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0e62e6a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,87 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + +[[package]] +name = "mira" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8833e20724c24de12bbaba5ad230ea61c3eafb05b881c7c9d3cfe8638b187e68" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..53ebfa2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "mira" +version = "0.1.0" +authors = ["dece "] +edition = "2018" + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/README.md b/README.md new file mode 100644 index 0000000..cb6a4f7 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +Mira +==== + +Small utility to help with Git repository mirroring, using a single JSON config +file. It is standalone and can be easily integrated in cron or systemd. diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..43da7e7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,111 @@ +use std::env; +use std::fs; +use std::io; +use std::io::prelude::*; +use std::path; +use std::process; + +fn main() { + let config_text = match load_file(&path::Path::new("mira.json")) { + Ok(content) => content, + Err(e) => { eprintln!("{:?}", e); process::exit(1) } + }; + let root_config: RootConfig = match serde_json::from_str(&config_text) { + Ok(config) => config, + Err(e) => { eprintln!("{:?}", e); process::exit(1) } + }; + process_root_config(&root_config); +} + +fn load_file(path: &path::Path) -> Result { + let mut file = fs::File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(contents) +} + +#[derive(Debug, serde::Deserialize)] +struct RootConfig { + workdir: Option, + auth: serde_json::Value, + configurations: Vec, +} + +// #[derive(Debug, serde::Deserialize)] +// struct Authentication { +// key: Option, +// } + +fn process_root_config(root_config: &RootConfig) { + // Ensure working directory exists and move to it. + if let Some(workdir) = &root_config.workdir { + let workdir = path::Path::new(&workdir); + if !workdir.is_dir() { + if let Err(e) = fs::create_dir_all(&workdir) { + eprintln!("Failed to create working directory: {}.", e); + return + } + } + if let Err(e) = env::set_current_dir(&workdir) { + eprintln!("Failed to move to working directory: {}.", e); + return + } + } + // Process each configuration. + for config in &root_config.configurations { + process_config(config); + } +} + +#[derive(Debug, serde::Deserialize)] +struct Configuration { + name: String, + mirrors: Vec, +} + +#[derive(Debug, serde::Deserialize)] +struct Mirror { + src: String, + dest: String, +} + +fn process_config(config: &Configuration) { + println!("Processing config {}.", config.name); + // Move into the configuration directory. + let mut config_path = match env::current_dir() { + Ok(pb) => pb, + Err(e) => { eprintln!("Current directory is not available: {}.", e); return } + }; + config_path.push(&config.name); + if !config_path.is_dir() { + if let Err(e) = fs::create_dir_all(&config_path) { + eprintln!("Failed to create working directory: {}.", e); + return + } + } + if let Err(e) = env::set_current_dir(&config_path) { + eprintln!("Failed to move to working directory: {}.", e); + return + } + // Mirror each repository in the configuration. + for mirror in &config.mirrors { + mirror_repo(&mirror.src, &mirror.dest); + } +} + +fn mirror_repo(src_url: &str, dest_url: &str) -> bool { + clone(src_url) +} + +fn run_git_command(args: Vec<&str>) -> bool { + let mut command = process::Command::new("git"); + command.args(&args); + match command.status() { + Ok(status) => status.success(), + Err(e) => { eprintln!("Failed to run Git: {}", e); false } + } +} + +fn clone(url: &str) -> bool { + run_git_command(vec!("clone", "--mirror", url)) +}