This commit is contained in:
dece 2020-12-05 17:21:57 +01:00
commit 2f2292342a
5 changed files with 213 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

87
Cargo.lock generated Normal file
View file

@ -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"

9
Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "mira"
version = "0.1.0"
authors = ["dece <shgck@pistache.land>"]
edition = "2018"
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"

5
README.md Normal file
View file

@ -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.

111
src/main.rs Normal file
View file

@ -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<String, io::Error> {
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<String>,
auth: serde_json::Value,
configurations: Vec<Configuration>,
}
// #[derive(Debug, serde::Deserialize)]
// struct Authentication {
// key: Option<String>,
// }
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<Mirror>,
}
#[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))
}