Init
This commit is contained in:
commit
2f2292342a
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
87
Cargo.lock
generated
Normal file
87
Cargo.lock
generated
Normal 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
9
Cargo.toml
Normal 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
5
README.md
Normal 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
111
src/main.rs
Normal 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))
|
||||||
|
}
|
Reference in a new issue