add strict flag, convert remaining fns to use result

This commit is contained in:
Bryson Steck 2025-03-09 13:26:28 -06:00
parent 2c95fbd30d
commit b3aac6060f
Signed by: brysonsteck
SSH key fingerprint: SHA256:XpKABw/nP4z8UVaH+weLaBnEOD86+cVwif+QjuYLGT4
3 changed files with 48 additions and 28 deletions

View file

@ -1,12 +1,13 @@
use crate::common; use crate::common;
use crate::refractr::Refractr; use crate::refractr::Refractr;
use core::fmt; use core::fmt;
use std::io::Read; use serde_derive::Deserialize;
use std::path::PathBuf;
use std::env; use std::env;
use std::fs::{self, File, Metadata}; use std::fs::{self, File, Metadata};
use std::io::Read;
use std::path::PathBuf;
use toml; use toml;
use serde_derive::Deserialize;
pub struct ConfigFile { pub struct ConfigFile {
pub path: String, pub path: String,
@ -129,11 +130,11 @@ pub fn read_config(paths: Vec<PathBuf>, refractr: &Refractr) -> Result<Vec<Confi
let mut dup = false; let mut dup = false;
for i in &config_files { for i in &config_files {
if i.path == config_file.path { if i.path == config_file.path {
eprintln!("refractr: warning: skipping config file \"{}\" as it was already read", path.as_path().display()); common::warning(format!("skipping config file \"{}\" as it was already read", path.as_path().display()));
dup = true; dup = true;
break; break;
} else if i.config == config_file.config { } else if i.config == config_file.config {
eprintln!("refractr: warning: config files \"{}\" and \"{}\" appear to have the same config", i.path, config_file.path); common::warning(format!("config files \"{}\" and \"{}\" appear to have the same config", i.path, config_file.path));
} }
} }

View file

@ -2,12 +2,12 @@ mod common;
mod config; mod config;
mod refractr; mod refractr;
use crate::refractr::Refractr;
use clap::Parser; use clap::Parser;
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
use std::env;
use users; use users;
use crate::refractr::Refractr;
#[derive(Parser)] #[derive(Parser)]
#[command(name = "refractr")] #[command(name = "refractr")]
@ -23,6 +23,9 @@ struct Args {
#[arg(short = 'e', long, help = "Output a full, commented config file and exit")] #[arg(short = 'e', long, help = "Output a full, commented config file and exit")]
create: bool, create: bool,
#[arg(short = 's', long, help = "Exit on push errors instead of ignoring")]
strict: bool,
} }
fn get_config_default() -> &'static str { fn get_config_default() -> &'static str {
@ -44,6 +47,7 @@ fn main() -> Result<(), String> {
None => false None => false
}, },
pid: process::id(), pid: process::id(),
strict: args.strict,
unix: cfg!(unix), unix: cfg!(unix),
verbose: args.verbose verbose: args.verbose
}; };

View file

@ -1,25 +1,26 @@
use git2::build::CheckoutBuilder;
use git2::{CertificateCheckStatus, Cred, PushOptions, RemoteCallbacks, Repository};
use sha2::{Sha256, Digest};
use crate::freak_out; use crate::freak_out;
use crate::common; use crate::common;
use crate::config::{Config, ConfigFile}; use crate::config::{Config, ConfigFile};
use std::fs;
use git2::{CertificateCheckStatus, Cred, PushOptions, RemoteCallbacks, Repository};
use git2::{Error, ErrorCode};
use git2::build::CheckoutBuilder;
use hex;
use sha2::{Sha256, Digest};
use std::env; use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread; use std::thread;
use std::time; use std::time;
use std::path::{Path, PathBuf};
use git2::{Error, ErrorCode};
use hex;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
pub struct Refractr { pub struct Refractr {
pub docker: bool, pub docker: bool,
pub verbose: u8,
pub pid: u32, pub pid: u32,
pub unix: bool pub strict: bool,
pub unix: bool,
pub verbose: u8
} }
struct OpenedRepository { struct OpenedRepository {
@ -83,7 +84,7 @@ impl Refractr {
Ok(_) => remote_list.push(remote_id), Ok(_) => remote_list.push(remote_id),
Err(e) => { Err(e) => {
if e.code() == ErrorCode::Exists { if e.code() == ErrorCode::Exists {
eprintln!("refractr: warning: remote {} already exists, skipping", remote_id); common::warning(format!("remote {} already exists, skipping", remote_id));
remote_list.push(remote_id) remote_list.push(remote_id)
} else { } else {
freak_out!(format!("failed to create remote: {}", e)); freak_out!(format!("failed to create remote: {}", e));
@ -95,7 +96,7 @@ impl Refractr {
Ok(remote_list) Ok(remote_list)
} }
fn push_remotes(&self, cfg: &Config, repo: &Repository, remote_list: &Vec<String>) { fn push_remotes(&self, cfg: &Config, repo: &Repository, remote_list: &Vec<String>) -> Result<(), String> {
for id in remote_list { for id in remote_list {
let mut remote = repo.find_remote(&id).unwrap(); let mut remote = repo.find_remote(&id).unwrap();
common::verbose( common::verbose(
@ -133,13 +134,19 @@ impl Refractr {
match remote.push::<&str>(&refs, Some(&mut push_options)) { match remote.push::<&str>(&refs, Some(&mut push_options)) {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
eprintln!("refractr: failed to push to remote: {}: {}", remote.url().unwrap(), e) if self.strict {
return Err(format!("failed to push to remote: {}: {}", remote.url().unwrap(), e))
} else {
common::warning(format!("failed to push to remote: {}: {}", remote.url().unwrap(), e))
}
} }
} }
} }
Ok(())
} }
fn looper(&self, repos: Vec<OpenedRepository>) { fn looper(&self, repos: Vec<OpenedRepository>) -> Result<(), String> {
let mut current_ints = Vec::new(); let mut current_ints = Vec::new();
let running = Arc::new(AtomicBool::new(true)); let running = Arc::new(AtomicBool::new(true));
let r = running.clone(); let r = running.clone();
@ -178,7 +185,12 @@ impl Refractr {
2, 2,
format!("Interval for {} has arrived, pulling", repos[i].cfg.from)); format!("Interval for {} has arrived, pulling", repos[i].cfg.from));
let _ = self.fast_forward(&repos[i].path, &repos[i].cfg.branches); let _ = self.fast_forward(&repos[i].path, &repos[i].cfg.branches);
self.push_remotes(&repos[i].cfg, &repos[i].repo, &repos[i].remotes); if let Err(e) = self.push_remotes(
&repos[i].cfg,
&repos[i].repo,
&repos[i].remotes) {
return Err(e)
}
} }
} }
do_break = false; do_break = false;
@ -186,8 +198,9 @@ impl Refractr {
} }
} }
} }
common::verbose(self.verbose, 1, format!("Exited looper due to ^C"));
common::verbose(self.verbose, 1, format!("Exited looper due to ^C"));
Ok(())
} }
pub fn run(&self, cfgs: Vec<ConfigFile>) -> Result<(), String> { pub fn run(&self, cfgs: Vec<ConfigFile>) -> Result<(), String> {
@ -229,7 +242,7 @@ impl Refractr {
let repo = match Repository::clone(&cfg.config.from, Path::new(&repo_dir)) { let repo = match Repository::clone(&cfg.config.from, Path::new(&repo_dir)) {
Ok(repo) => repo, Ok(repo) => repo,
Err(_) => { Err(_) => {
eprintln!("refractr: warning: found existing repo at {}, attempting to use", repo_dir); common::warning(format!("found existing repo at {}, attempting to use", repo_dir));
match self.fast_forward(&repo_dir, &cfg.config.branches) { match self.fast_forward(&repo_dir, &cfg.config.branches) {
Ok(_) => if let Ok(repo) = Repository::open(Path::new(&repo_dir)) { Ok(_) => if let Ok(repo) = Repository::open(Path::new(&repo_dir)) {
repo repo
@ -246,7 +259,9 @@ impl Refractr {
Ok(v) => v, Ok(v) => v,
Err(e) => return Err(e) Err(e) => return Err(e)
}; };
self.push_remotes(&cfg.config, &repo, &remotes); if let Err(e) = self.push_remotes(&cfg.config, &repo, &remotes) {
return Err(e)
}
if cfg.config.schedule.enabled { if cfg.config.schedule.enabled {
loop_repos.push(OpenedRepository { loop_repos.push(OpenedRepository {
repo, repo,
@ -262,7 +277,7 @@ impl Refractr {
self.verbose, self.verbose,
2, 2,
format!("{} configs have schedules enabled, setting up looper", loop_repos.len())); format!("{} configs have schedules enabled, setting up looper", loop_repos.len()));
self.looper(loop_repos); return self.looper(loop_repos);
} else { } else {
common::verbose( common::verbose(
self.verbose, self.verbose,