clean up work dirs

This commit is contained in:
Bryson Steck 2025-03-25 21:21:11 -06:00
parent b98a3beec4
commit fb8ed1ae8c
Signed by: bryson
SSH key fingerprint: SHA256:XpKABw/nP4z8UVaH+weLaBnEOD86+cVwif+QjuYLGT4
4 changed files with 90 additions and 52 deletions

View file

@ -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)
}

View file

@ -123,6 +123,19 @@ pub struct Schedule {
pub interval: Option<i32>,
}
pub fn get_work_dir(work_dir: &Option<String>) -> 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<PathBuf>, refractr: &Refractr) -> Result<Vec<ConfigFile>, String> {
let mut config_files: Vec<ConfigFile> = 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://")

View file

@ -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(())

View file

@ -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<String, String> {
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<RemoteCallbacks, String> {
@ -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<String>) -> 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<ConfigFile>) -> 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
}
}