From fb8ed1ae8c4878c5b9bf53d06fa508cc6c86383b Mon Sep 17 00:00:00 2001 From: Bryson Steck Date: Tue, 25 Mar 2025 21:21:11 -0600 Subject: [PATCH] clean up work dirs --- src/common.rs | 7 +++- src/config.rs | 29 +++++++++------ src/main.rs | 12 +++++-- src/refractr.rs | 94 +++++++++++++++++++++++++++++-------------------- 4 files changed, 90 insertions(+), 52 deletions(-) diff --git a/src/common.rs b/src/common.rs index befe619..71e7e4d 100644 --- a/src/common.rs +++ b/src/common.rs @@ -16,6 +16,7 @@ pub enum ExitCode { PushError = 6, FetchError = 7, ConfigError = 8, + HaltError = 130, } pub struct ReturnData { @@ -23,11 +24,15 @@ pub struct ReturnData { pub msg: String, } -pub fn error(msg: String, code: ExitCode) { +pub fn error_quit(msg: String, code: ExitCode) { eprintln!("{} {}", "error:".red().bold(), msg); quit::with_code(code as u8) } +pub fn error(msg: String) { + eprintln!("{} {}", "error:".red().bold(), msg); +} + pub fn warning(msg: String) { eprintln!("{} {}", "warning:".yellow().bold(), msg) } diff --git a/src/config.rs b/src/config.rs index 0720950..4ceb096 100644 --- a/src/config.rs +++ b/src/config.rs @@ -123,6 +123,19 @@ pub struct Schedule { pub interval: Option, } +pub fn get_work_dir(work_dir: &Option) -> String { + match work_dir { + None => { + if cfg!(windows) { + format!("{}\\refractr", env::var("TEMP").unwrap()) + } else { + format!("/tmp/refractr") + } + }, + Some(path) => path.clone(), + } +} + pub fn read_config(paths: Vec, refractr: &Refractr) -> Result, String> { let mut config_files: Vec = vec![]; for path in paths { @@ -233,18 +246,12 @@ fn verify_config(config: &Config) -> Result<(), String> { } } - match &config.work_dir { - Some(path) => format!("{}", path), - None => { - if cfg!(windows) { - match env::var("TEMP") { - Ok(val) => val, - Err(_) => return Err(format!("cannot determine the default temp dir")), - } - } else { - format!("/tmp/refractr") + if let None = &config.work_dir { + if cfg!(windows) { + if let Err(e) = env::var("TEMP") { + return Err(format!("cannot determine the default temp dir: {}", e)); } - }, + } }; if !&config.from.starts_with("ssh://") diff --git a/src/main.rs b/src/main.rs index 243ceb3..e8a9149 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,13 @@ struct Args { help = "Exit on push and unknown host errors instead of ignoring them" )] strict: bool, + + #[arg( + short = 'p', + long, + help = "Do not clean the working directories specified in config(s)" + )] + persist: bool, } fn get_config_default() -> &'static str { @@ -72,6 +79,7 @@ fn main() -> Result<(), String> { }, None => false, }, + persist: args.persist, pid: process::id(), strict: args.strict, unix: cfg!(unix), @@ -125,7 +133,7 @@ fn main() -> Result<(), String> { let mut cfgs = vec![]; match config::read_config(args.config, &refractr) { Ok(c) => cfgs = c, - Err(e) => common::error(format!("{}", e), common::ExitCode::ConfigError), + Err(e) => common::error_quit(format!("{}", e), common::ExitCode::ConfigError), }; if refractr.verbose >= 2 { @@ -142,7 +150,7 @@ fn main() -> Result<(), String> { ); match refractr.run(cfgs) { Ok(_) => (), - Err(e) => common::error(format!("{}", e.msg), e.code), + Err(e) => common::error_quit(format!("{}", e.msg), e.code), }; Ok(()) diff --git a/src/refractr.rs b/src/refractr.rs index 87f99f3..6464e08 100644 --- a/src/refractr.rs +++ b/src/refractr.rs @@ -7,7 +7,7 @@ */ use crate::common::{self, ExitCode, ReturnData}; -use crate::config::{Config, ConfigFile}; +use crate::config::{self, Config, ConfigFile}; use git2::build::RepoBuilder; use git2::string_array::StringArray; @@ -15,8 +15,7 @@ use git2::{CertificateCheckStatus, Cred, FetchOptions, PushOptions, RemoteCallba use git2::{Error, ErrorCode}; use hex; use sha2::{Digest, Sha256}; -use std::env; -use std::fs; +use std::fs::{self, remove_dir_all}; use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -25,6 +24,7 @@ use std::time; pub struct Refractr { pub docker: bool, + pub persist: bool, pub pid: u32, pub strict: bool, pub unix: bool, @@ -39,7 +39,7 @@ struct OpenedRepository { } impl Refractr { - fn set_up_work_dir(&self, work_dir: PathBuf) -> Result { + fn set_up_work_dir(&self, work_dir: PathBuf) -> Result<(), String> { if let Err(e) = fs::create_dir_all(&work_dir) { return Err(format!( "could not create working directory: {}: {}", @@ -47,7 +47,7 @@ impl Refractr { e )); } - Ok(work_dir.to_string_lossy().to_string()) + Ok(()) } fn set_up_ssh(&self, key_path: String, strict: bool) -> Result { @@ -56,7 +56,7 @@ impl Refractr { cb.certificate_check(move |cert, url| { let sha256 = hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()); if strict { - common::error( + common::error_quit( format!( "unknown host {} with sha256 host key {}, exiting", url, sha256 @@ -120,7 +120,7 @@ impl Refractr { fo.remote_callbacks(cb); () }, - Err(e) => common::error( + Err(e) => common::error_quit( format!("error setting up ssh: {}", e), ExitCode::ConfigError, ), @@ -195,7 +195,7 @@ impl Refractr { po.remote_callbacks(cb); () }, - Err(e) => common::error( + Err(e) => common::error_quit( format!("error setting up ssh: {}", e), ExitCode::ConfigError, ), @@ -294,7 +294,7 @@ impl Refractr { &repos[i].cfg.git.ssh_identity_file, self.strict.clone(), ) { - common::error( + common::error_quit( format!("failed to fetch repo {}: {}", repos[i].cfg.from, e), ExitCode::FetchError, ); @@ -302,7 +302,7 @@ impl Refractr { let _ = self.fast_forward(&repos[i].repo, &repos[i].cfg.branches); if let Err(e) = self.push_remotes(&repos[i].cfg, &repos[i].repo, &repos[i].remotes) { - common::error(e, ExitCode::PushError) + common::error_quit(e, ExitCode::PushError) }; current_ints[i] = original_ints[i].clone(); } @@ -322,37 +322,38 @@ impl Refractr { Ok(()) } + fn clean(&self, dirs: Vec) -> Result<(), ReturnData> { + for dir in dirs { + common::verbose(self.verbose, 1, format!("removing working dir {}", dir)); + if let Err(e) = remove_dir_all(&dir) { + common::warning(format!("could not clean up working dir: {}: {}", dir, e)); + } + } + + Ok(()) + } + pub fn run(&self, cfgs: Vec) -> Result<(), ReturnData> { common::verbose(self.verbose, 3, format!("Starting main refractr loop")); let mut loop_repos = Vec::new(); + let mut work_dirs = Vec::new(); for cfg in cfgs { // set up the working directory common::verbose(self.verbose, 3, format!("Loading config: {}", cfg.path)); - let work_dir = self.set_up_work_dir(match &cfg.config.work_dir { - None => { - if cfg!(windows) { - PathBuf::from(format!("{}\\refractr", env::var("TEMP").unwrap())) - } else { - PathBuf::from("/tmp/refractr") - } - }, - Some(path) => PathBuf::from(path), - }); - let path_str = match work_dir { - Ok(p) => p, - Err(e) => { - return Err(ReturnData { - code: ExitCode::FilesystemError, - msg: e, - }) - }, - }; + let work_dir = config::get_work_dir(&cfg.config.work_dir); + if let Err(e) = self.set_up_work_dir(PathBuf::from(&work_dir)) { + return Err(ReturnData { + msg: e, + code: ExitCode::FilesystemError, + }); + } common::verbose( self.verbose, 2, - format!("Created working directory: {}", &path_str), + format!("Created working directory: {}", work_dir), ); + let repo_name = match &cfg.config.from.split("/").last() { Some(split) => split.to_string(), None => { @@ -377,7 +378,7 @@ impl Refractr { fo.remote_callbacks(cb); () }, - Err(e) => common::error( + Err(e) => common::error_quit( format!("error setting up ssh: {}", e), ExitCode::ConfigError, ), @@ -386,7 +387,7 @@ impl Refractr { fo.download_tags(git2::AutotagOption::All); builder.fetch_options(fo); - let repo_dir = format!("{}{}{}", &path_str, MAIN_SEPARATOR_STR, repo_name); + let repo_dir = format!("{}{}{}", &work_dir, MAIN_SEPARATOR_STR, repo_name); common::verbose( self.verbose, 1, @@ -396,7 +397,7 @@ impl Refractr { Ok(repo) => repo, Err(e) => { if e.code() != ErrorCode::Exists { - common::error( + common::error_quit( format!("failed to clone repo to {}: {}", repo_dir, e), ExitCode::FilesystemError, ); @@ -436,7 +437,7 @@ impl Refractr { &cfg.config.git.ssh_identity_file, self.strict.clone(), ) { - common::error( + common::error_quit( format!("failed to fetch repo {}: {}", cfg.config.from, e), ExitCode::FetchError, ); @@ -463,7 +464,7 @@ impl Refractr { }; if let Err(e) = self.set_up_refs(&repo, &cfg.config.branches) { - common::error( + common::error_quit( format!("failed to set up refs: {}", e), ExitCode::RepositoryError, ); @@ -478,8 +479,9 @@ impl Refractr { }) }, }; + if let Err(e) = self.push_remotes(&cfg.config, &repo, &remotes) { - common::error(e, ExitCode::PushError); + common::error_quit(e, ExitCode::PushError); } if cfg.config.schedule.enabled { @@ -489,9 +491,18 @@ impl Refractr { cfg: cfg.config, ssh, }); + if !work_dirs.contains(&work_dir) { + work_dirs.push(work_dir); + } + } else { + if let Err(e) = self.clean(vec![work_dir]) { + return Err(e); + } } } + // end for + let mut result = Ok(()); if loop_repos.len() >= 1 { common::verbose( self.verbose, @@ -501,7 +512,7 @@ impl Refractr { loop_repos.len() ), ); - return self.looper(loop_repos); + result = self.looper(loop_repos); } else { common::verbose( self.verbose, @@ -510,6 +521,13 @@ impl Refractr { ); } - Ok(()) + if !self.persist { + match result { + Ok(()) => return self.clean(work_dirs), + Err(_) => result = self.clean(work_dirs), + } + } + + result } }