use crate::models::LoopBranch;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::fs::metadata;
use std::collections::HashSet;
use std::path::{PathBuf, Path};
use std::process::Command;
#[cfg(feature = "color")]
use colored::*;
use chrono::NaiveDateTime;
use filetime::FileTime;
use crate::consts::*;
use crate::RifError;
pub fn get_file_unix_time(path: &Path) -> Result<NaiveDateTime, RifError> {
let metadata = std::fs::metadata(path)?;
let mtime = FileTime::from_last_modification_time(&metadata);
let unix_time = chrono::NaiveDateTime::from_timestamp(mtime.unix_seconds(), 0);
Ok(unix_time)
}
pub fn get_current_unix_time() -> NaiveDateTime {
let now = chrono::Utc::now().timestamp();
let unix_time = chrono::NaiveDateTime::from_timestamp(now, 0);
unix_time
}
pub fn walk_directory_recursive(path: &Path, f: &mut dyn FnMut(PathBuf) -> Result<LoopBranch, RifError>) -> Result<(), RifError> {
for entry in std::fs::read_dir(path)? {
let entry_path: PathBuf = strip_path(&entry?.path(), None)?;
let md = metadata(entry_path.clone()).unwrap();
if entry_path != path { if !md.is_dir() {
if let LoopBranch::Exit = f(entry_path)? {
return Ok(());
}
} else {
if let LoopBranch::Continue = f(entry_path.clone())? {
walk_directory_recursive(&entry_path, f)?;
}
}
}
}
Ok(())
}
pub fn walk_directory(path: &Path, f: &mut dyn FnMut(PathBuf) -> Result<(), RifError>) -> Result<(), RifError> {
for entry in std::fs::read_dir(path)? {
f(entry?.path())?;
}
Ok(())
}
pub fn strip_path(path: &Path, base_path: Option<PathBuf>) -> Result<PathBuf, RifError> {
if let Some(base_path) = base_path {
if let Ok( striped_path ) = path.strip_prefix(base_path) {
Ok(striped_path.to_owned())
} else {
Err(RifError::Ext(String::from("Failed to get stripped path")))
}
} else {
if let Ok( striped_path ) = path.strip_prefix(std::env::current_dir()?) {
Ok(striped_path.to_owned())
} else {
Ok(path.to_path_buf())
}
}
}
pub fn relativize_path(path: &Path) -> Result<PathBuf, RifError> {
let path_buf: PathBuf;
if path.starts_with("./") {
path_buf = strip_path(path, Some(PathBuf::from("./")))?;
} else if path.starts_with(&std::env::current_dir()?){
path_buf = strip_path(path, Some(std::env::current_dir()?))?;
} else if !std::env::current_dir()?.join(path).exists() {
return Err(RifError::RifIoError( format!("Only files inside of rif directory can be added\nFile \"{}\" is not.", path.display())));
} else {
return Ok(path.to_path_buf());
}
Ok(path_buf)
}
pub fn get_rif_directory() -> Result<PathBuf, RifError> {
for path in std::env::current_dir()?.ancestors() {
if path.join(RIF_DIECTORY).is_dir() {
return Ok(path.to_owned());
}
}
Err(RifError::ConfigError("Not a rif directory".to_owned()))
}
pub fn get_black_list(use_gitignore: bool) -> Result<HashSet<PathBuf>, RifError> {
let mut black_list: HashSet<PathBuf> = HashSet::new();
let rif_ignore = read_rif_ignore()?;
black_list.extend(BLACK_LIST.to_vec().iter().map(|a| PathBuf::from(*a)).collect::<HashSet<PathBuf>>());
black_list.extend(rif_ignore);
if use_gitignore{
black_list.extend(read_git_ignore()?);
black_list.insert(PathBuf::from(".gitignore"));
}
Ok(black_list)
}
fn read_rif_ignore() -> Result<HashSet<PathBuf>, RifError> {
if let Ok(file) = File::open(RIF_IGNORE_FILE) {
let buffer = BufReader::new(file);
let ignore: Result<HashSet<PathBuf>, RifError> = buffer
.lines()
.map(|op| -> Result<PathBuf, RifError> {Ok(PathBuf::from(op?))})
.collect();
Ok(ignore?)
} else {
Ok(HashSet::new())
}
}
fn read_git_ignore() -> Result<HashSet<PathBuf>, RifError> {
if let Ok(file) = File::open(".gitignore") {
let buffer = BufReader::new(file);
let ignore: Result<HashSet<PathBuf>, RifError> = buffer
.lines()
.map(|op| -> Result<PathBuf, RifError> {Ok(PathBuf::from(op?))})
.collect();
Ok(ignore?)
} else {
Ok(HashSet::new())
}
}
pub fn get_rel_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
let path = if let Some(path) = path {
path.as_ref().to_owned()
} else {
std::env::current_dir()?
};
Ok(path.join(RIF_DIECTORY).join(RIF_REL_FILE))
}
pub fn get_config_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
let path = if let Some(path) = path {
path.as_ref().to_owned()
} else {
std::env::current_dir()?
};
Ok(path.join(RIF_DIECTORY).join(RIF_CONFIG))
}
pub fn get_history_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
let path = if let Some(path) = path {
path.as_ref().to_owned()
} else {
std::env::current_dir()?
};
Ok(path.join(RIF_DIECTORY).join(RIF_HIST_FILE))
}
pub fn get_meta_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
let path = if let Some(path) = path {
path.as_ref().to_owned()
} else {
std::env::current_dir()?
};
Ok(path.join(RIF_DIECTORY).join(RIF_META))
}
pub fn green(string : &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.green().to_owned());
}
Box::new(string.to_owned())
}
pub fn blue(string : &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.blue().to_owned());
}
Box::new(string.to_owned())
}
pub fn red(string : &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.red().to_owned());
}
Box::new(string.to_owned())
}
pub fn yellow(string : &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.yellow().to_owned());
}
Box::new(string.to_owned())
}
pub fn cmd(cmd: &str, args: Vec<String>) -> Result<(), RifError> {
let output = if cfg!(target_os = "windows") {
Command::new("cmd")
.arg("/C")
.args(args)
.output()
.expect("failed to execute process")
} else {
Command::new(cmd)
.args(args)
.output()
.expect("failed to execute process")
};
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
if stdout.len() != 0 { println!("{}",stdout); }
if stderr.len() != 0 { eprintln!("{}",stderr); }
Ok(())
}