mod common; mod config; mod refractr; use crate::refractr::Refractr; use clap::Parser; use std::path::PathBuf; use std::process; #[cfg(target_family = "unix")] use users; #[cfg(target_family = "windows")] use username; #[derive(Parser)] #[command(name = "refractr")] #[command(version = option_env!("CARGO_PKG_VERSION"))] #[command(about = "An automated pull/push utility for mirroring Git repositories")] #[command(long_about = None)] struct Args { #[arg(short, long, help = "Specify a config file", default_value = get_config_default())] config: Vec, #[arg(short, long, help = "Specify the level of verbosity", action = clap::ArgAction::Count)] verbose: u8, #[arg(short = 'e', long, help = "Output a full, commented config file and exit")] create: bool, #[arg(short = 's', long, help = "Exit on push errors instead of ignoring")] strict: bool, } fn get_config_default() -> &'static str { #[cfg(target_os = "windows")] return "C:\\ProgramData\\refractr\\config.toml"; #[cfg(target_os = "linux")] return "/etc/refractr/config.toml"; #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "macos" ))] return "/usr/local/etc/refractr/config.toml"; } #[quit::main] fn main() -> Result<(), String> { let args = Args::parse(); let refractr = Refractr { docker: match option_env!("REFRACTR_DOCKER") { Some(v) => match v { "true" => true, _ => false, }, None => false }, pid: process::id(), strict: args.strict, unix: cfg!(unix), verbose: args.verbose }; // warn to avoid root/admin // unix-like #[cfg(target_family = "unix")] if users::get_current_uid() == 0 { common::warning(format!("this program should not ran as root")); } // windows #[cfg(target_family = "windows")] match username::get_user_name() { Ok(user) => { if user.contains("Administrator") || user.contains("SYSTEM") { common::warning(format!("this program should not ran as {}", user)); } }, Err(_) => common::warning(format!("failed to get process username")), } common::verbose(refractr.verbose, 1, format!("refractr started with level {} verbosity enabled", refractr.verbose.to_string())); common::verbose(refractr.verbose, 3, format!("Process ID: {}", refractr.pid)); common::verbose(refractr.verbose, 3, format!("Running in Docker: {}", refractr.docker)); common::verbose(refractr.verbose, 3, format!("System is UNIX(-like): {}", refractr.unix)); common::verbose(refractr.verbose, 2, format!("Checking for create flag")); if args.create { common::verbose(refractr.verbose, 3, format!("Printing sample config")); let example = include_str!("example/config.toml"); println!("{}", example); return Ok(()) } let cfgs = match config::read_config(args.config, &refractr) { Ok(cfgs) => cfgs, Err(e) => return Err(e) }; if refractr.verbose >= 2 { // no need to loop over configs if verbose is not at the correct level for i in &cfgs { common::verbose(refractr.verbose, 2, format!("{}", i)); } } common::verbose(refractr.verbose, 1, format!("Config file(s) read successfully")); match refractr.run(cfgs) { Ok(_) => (), Err(e) => common::error(format!("{}", e.msg), e.code) }; Ok(()) }