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