diff --git a/Cargo.lock b/Cargo.lock index cdd0db4..dc05b67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "cc" version = "1.2.16" @@ -69,6 +78,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" version = "4.5.31" @@ -115,6 +130,35 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -141,6 +185,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "git2" version = "0.20.0" @@ -168,6 +222,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "icu_collections" version = "1.5.0" @@ -456,8 +516,10 @@ version = "0.1.0" dependencies = [ "clap", "git2", + "hex", "serde", "serde_derive", + "sha2", "toml", "users", ] @@ -491,6 +553,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -581,6 +654,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.17" @@ -632,6 +711,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 30cf872..b40d6f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" [dependencies] clap = { version = "4.5.29", features = ["derive"] } git2 = "0.20.0" +hex = "0.4.3" serde = "1.0.217" serde_derive = "1.0.217" +sha2 = "0.10.8" toml = "0.8.20" users = "0.11.0" diff --git a/src/config.rs b/src/config.rs index 992dac1..1ce9abb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -95,14 +95,14 @@ pub struct Config { #[derive(PartialEq)] #[derive(Deserialize)] -struct Git { - ssh_identity_file: String, +pub struct Git { + pub ssh_identity_file: String, } #[derive(PartialEq)] #[derive(Deserialize)] -struct Schedule { - enabled: bool, +pub struct Schedule { + pub enabled: bool, interval: Option, } diff --git a/src/refractr.rs b/src/refractr.rs index 28cec16..039b717 100644 --- a/src/refractr.rs +++ b/src/refractr.rs @@ -1,15 +1,17 @@ -use git2::{Branch, Repository}; +use git2::Repository; +use sha2::{Sha256, Digest}; use crate::common::{self, Refractr}; -use crate::config::{ConfigFile, Config}; +use crate::config::ConfigFile; use std::fs; use std::env; use std::path::{Path, PathBuf}; -use git2::{Branches, Error}; +use git2::{Error, ErrorCode}; +use hex; fn set_up_work_dir(work_dir: PathBuf) -> String { if let Err(e) = fs::create_dir_all(&work_dir) { - panic!("refractr: could not create working directory: {}", work_dir.to_string_lossy()) + panic!("refractr: could not create working directory: {}: {}", work_dir.to_string_lossy(), e) } work_dir.to_string_lossy().to_string() } @@ -38,10 +40,10 @@ fn fast_forward(repo_dir: &str, branches: &Option>) -> Result<(), Er pub fn start(refractr: Refractr, cfgs: Vec) -> std::io::Result<()> { common::verbose(refractr.verbose, 3, format!("Starting main refractr loop")); - for i in &cfgs { + for cfg in &cfgs { // set up the working directory - common::verbose(refractr.verbose, 3, format!("Loaded config: {}", i.path)); - let path_str = set_up_work_dir(match &i.config.work_dir { + common::verbose(refractr.verbose, 3, format!("Loaded config: {}", cfg.path)); + let path_str = set_up_work_dir(match &cfg.config.work_dir { None => { if cfg!(windows) { PathBuf::from(format!("\"{}\\refractr\"", match env::var("TEMP") { @@ -56,20 +58,44 @@ pub fn start(refractr: Refractr, cfgs: Vec) -> std::io::Result<()> { }); common::verbose(refractr.verbose, 2, format!("Created working directory: {}", &path_str)); - let repo_name = match &i.config.from.split("/").last() { + let repo_name = match &cfg.config.from.split("/").last() { Some(split) => split.to_string(), None => panic!("refractr: failed to parse repository name") }; // make initial clone - common::verbose(refractr.verbose, 1, format!("Cloning repository: {}", &i.config.from)); + common::verbose(refractr.verbose, 1, format!("Cloning repository: {}", &cfg.config.from)); let repo_dir = &format!("{}/{}", &path_str, repo_name); - match Repository::clone(&i.config.from, Path::new(&repo_dir)) { - Ok(repo) => (), - Err(e) => { + let repo = match Repository::clone(&cfg.config.from, Path::new(&repo_dir)) { + Ok(repo) => repo, + Err(_) => { eprintln!("refractr: warning: found existing repo at {}, attempting to use", repo_dir); - if let Err(e) = fast_forward(repo_dir, &i.config.branches) { - eprintln!("failed"); + match fast_forward(repo_dir, &cfg.config.branches) { + Ok(_) => if let Ok(repo) = Repository::open(Path::new(&repo_dir)) { + repo + } else { + panic!("refractr: failed to obtain existing repo") + }, + Err(e) => panic!("refractr: failed to obtain existing repo: {}", e) + } + } + }; + + // create remotes for each "to" repo + let mut remote_list = Vec::new(); + for to in &cfg.config.to { + let mut hasher = Sha256::new(); + hasher.update(to); + let remote_id = format!("refractr-{}", &hex::encode(hasher.finalize())[..8]); + common::verbose(refractr.verbose, 2, format!("Attempting to create remote {} for url {}", remote_id, to)); + match repo.remote(remote_id.as_str(), to) { + Ok(r) => remote_list.push(r), + Err(e) => { + if e.code() == ErrorCode::Exists { + eprintln!("refractr: warning: remote {} already exists, skipping", remote_id) + } else { + panic!("refractr: failed to create remote: {}", e); + } } } }