1use crate::models::LoopBranch;
2use std::io::{BufRead, BufReader};
3use std::fs::File;
4use std::fs::metadata;
5use std::collections::HashSet;
6use std::path::{PathBuf, Path};
7use std::process::Command;
8
9#[cfg(feature = "color")]
10use colored::*;
11use chrono::NaiveDateTime;
12use filetime::FileTime;
13use crate::consts::*;
14use crate::RifError;
15
16pub fn get_file_unix_time(path: &Path) -> Result<NaiveDateTime, RifError> {
22 let metadata = std::fs::metadata(path)?;
23 let mtime = FileTime::from_last_modification_time(&metadata);
25 let unix_time = chrono::NaiveDateTime::from_timestamp(mtime.unix_seconds(), 0);
27 Ok(unix_time)
28}
29
30pub fn get_current_unix_time() -> NaiveDateTime {
32 let now = chrono::Utc::now().timestamp();
33 let unix_time = chrono::NaiveDateTime::from_timestamp(now, 0);
34 unix_time
35}
36
37pub fn walk_directory_recursive(path: &Path, f: &mut dyn FnMut(PathBuf) -> Result<LoopBranch, RifError>) -> Result<(), RifError> {
47 for entry in std::fs::read_dir(path)? {
48 let entry_path: PathBuf = strip_path(&entry?.path(), None)?;
49 let md = metadata(entry_path.clone()).unwrap();
50
51 if entry_path != path { if !md.is_dir() {
56 if let LoopBranch::Exit = f(entry_path)? {
57 return Ok(());
58 }
59 } else {
60 if let LoopBranch::Continue = f(entry_path.clone())? {
61 walk_directory_recursive(&entry_path, f)?;
62 }
63 }
64 }
65 }
66
67 Ok(())
68} pub fn walk_directory(path: &Path, f: &mut dyn FnMut(PathBuf) -> Result<(), RifError>) -> Result<(), RifError> {
80 for entry in std::fs::read_dir(path)? {
81 f(entry?.path())?;
82 }
83 Ok(())
84}
85
86pub fn strip_path(path: &Path, base_path: Option<PathBuf>) -> Result<PathBuf, RifError> {
107 if let Some(base_path) = base_path {
108 if let Ok( striped_path ) = path.strip_prefix(base_path) {
109 Ok(striped_path.to_owned())
110 } else {
111 Err(RifError::Ext(String::from("Failed to get stripped path")))
112 }
113 } else {
114 if let Ok( striped_path ) = path.strip_prefix(std::env::current_dir()?) {
115 Ok(striped_path.to_owned())
116 } else {
117 Ok(path.to_path_buf())
118 }
119 }
120}
121
122pub fn relativize_path(path: &Path) -> Result<PathBuf, RifError> {
139 let path_buf: PathBuf;
140
141 if path.starts_with("./") {
142 path_buf = strip_path(path, Some(PathBuf::from("./")))?;
143 } else if path.starts_with(&std::env::current_dir()?){
144 path_buf = strip_path(path, Some(std::env::current_dir()?))?;
145 } else if !std::env::current_dir()?.join(path).exists() {
146 return Err(RifError::RifIoError( format!("Only files inside of rif directory can be added\nFile \"{}\" is not.", path.display())));
147 } else {
148 return Ok(path.to_path_buf());
149 }
150
151 Ok(path_buf)
152}
153
154pub fn get_rif_directory() -> Result<PathBuf, RifError> {
159 for path in std::env::current_dir()?.ancestors() {
160 if path.join(RIF_DIECTORY).is_dir() {
161 return Ok(path.to_owned());
162 }
163 }
164 Err(RifError::ConfigError("Not a rif directory".to_owned()))
165}
166
167pub fn get_black_list(use_gitignore: bool) -> Result<HashSet<PathBuf>, RifError> {
171 let mut black_list: HashSet<PathBuf> = HashSet::new();
172 let rif_ignore = read_rif_ignore()?;
173
174 black_list.extend(BLACK_LIST.to_vec().iter().map(|a| PathBuf::from(*a)).collect::<HashSet<PathBuf>>());
176 black_list.extend(rif_ignore);
178
179 if use_gitignore{
181 black_list.extend(read_git_ignore()?);
182 black_list.insert(PathBuf::from(".gitignore"));
183 }
184
185 Ok(black_list)
186}
187
188fn read_rif_ignore() -> Result<HashSet<PathBuf>, RifError> {
192 if let Ok(file) = File::open(RIF_IGNORE_FILE) {
193 let buffer = BufReader::new(file);
194 let ignore: Result<HashSet<PathBuf>, RifError> = buffer
195 .lines()
196 .map(|op| -> Result<PathBuf, RifError> {Ok(PathBuf::from(op?))})
197 .collect();
198
199 Ok(ignore?)
200 } else {
201 Ok(HashSet::new())
203 }
204}
205
206fn read_git_ignore() -> Result<HashSet<PathBuf>, RifError> {
208 if let Ok(file) = File::open(".gitignore") {
209 let buffer = BufReader::new(file);
210 let ignore: Result<HashSet<PathBuf>, RifError> = buffer
211 .lines()
212 .map(|op| -> Result<PathBuf, RifError> {Ok(PathBuf::from(op?))})
213 .collect();
214
215 Ok(ignore?)
216 } else {
217 Ok(HashSet::new())
219 }
220}
221
222pub fn get_rel_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
225 let path = if let Some(path) = path {
226 path.as_ref().to_owned()
227 } else {
228 std::env::current_dir()?
229 };
230 Ok(path.join(RIF_DIECTORY).join(RIF_REL_FILE))
231}
232
233pub fn get_config_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
234 let path = if let Some(path) = path {
235 path.as_ref().to_owned()
236 } else {
237 std::env::current_dir()?
238 };
239 Ok(path.join(RIF_DIECTORY).join(RIF_CONFIG))
240}
241
242pub fn get_history_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
243 let path = if let Some(path) = path {
244 path.as_ref().to_owned()
245 } else {
246 std::env::current_dir()?
247 };
248 Ok(path.join(RIF_DIECTORY).join(RIF_HIST_FILE))
249}
250
251pub fn get_meta_path(path : Option<impl AsRef<Path>>) -> Result<PathBuf, RifError> {
252 let path = if let Some(path) = path {
253 path.as_ref().to_owned()
254 } else {
255 std::env::current_dir()?
256 };
257 Ok(path.join(RIF_DIECTORY).join(RIF_META))
258}
259
260pub fn green(string : &str) -> Box<dyn std::fmt::Display> {
261 if cfg!(feature = "color") {
262 #[cfg(feature = "color")]
263 return Box::new(string.green().to_owned());
264 }
265 Box::new(string.to_owned())
266}
267
268pub fn blue(string : &str) -> Box<dyn std::fmt::Display> {
269 if cfg!(feature = "color") {
270 #[cfg(feature = "color")]
271 return Box::new(string.blue().to_owned());
272 }
273 Box::new(string.to_owned())
274}
275
276pub fn red(string : &str) -> Box<dyn std::fmt::Display> {
277 if cfg!(feature = "color") {
278 #[cfg(feature = "color")]
279 return Box::new(string.red().to_owned());
280 }
281 Box::new(string.to_owned())
282}
283
284pub fn yellow(string : &str) -> Box<dyn std::fmt::Display> {
285 if cfg!(feature = "color") {
286 #[cfg(feature = "color")]
287 return Box::new(string.yellow().to_owned());
288 }
289 Box::new(string.to_owned())
290}
291
292pub fn cmd(cmd: &str, args: Vec<String>) -> Result<(), RifError> {
293 let output = if cfg!(target_os = "windows") {
294 Command::new("cmd")
295 .arg("/C")
296 .args(args)
297 .output()
298 .expect("failed to execute process")
299 } else {
300 Command::new(cmd)
301 .args(args)
302 .output()
303 .expect("failed to execute process")
304 };
305
306 let stdout = String::from_utf8_lossy(&output.stdout);
308 let stderr = String::from_utf8_lossy(&output.stderr);
309
310 if stdout.len() != 0 { println!("{}",stdout); }
311 if stderr.len() != 0 { eprintln!("{}",stderr); }
312
313 Ok(())
314}