Skip to content

Commit c8fd026

Browse files
Refactored file_name collecting function: simplified and improved working with pathes
1 parent b2331a3 commit c8fd026

File tree

9 files changed

+178
-137
lines changed

9 files changed

+178
-137
lines changed

src/console/messages.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn print_processing_directory(path: &str) {
5353
println!("{} {:?}", "🔍 Processing directory:".green(), path);
5454
}
5555

56-
pub fn print_processing_file(file_name: &str) {
56+
pub fn print_processing_file(file_name: &String) {
5757
println!("{} {:?}", "📄 Processing file:".blue(), file_name);
5858
}
5959

@@ -102,6 +102,14 @@ pub fn print_files_not_updated() {
102102
println!("{}", "🚫 File locations were not updated.".yellow());
103103
}
104104

105+
pub fn print_ignoring_entry(is_file: bool, path: &str) {
106+
if is_file {
107+
print_ignoring_file(path);
108+
} else {
109+
print_ignoring_folder(path);
110+
}
111+
}
112+
105113
pub fn print_ignoring_file(path: &str) {
106114
println!("{} {:?}", "⚠️ Ignoring file:".yellow(), path);
107115
}

src/console/table.rs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::{collections::HashMap, path::Path};
22

33
use colored::Colorize;
44
use prettytable::{format, Cell, Row, Table};
@@ -28,9 +28,14 @@ pub fn print_rag_processing_result(config: &RagMlConfig, process_result: &[Proce
2828
} else {
2929
"No"
3030
};
31+
let destination_relative_path = if result.destination_relative_path.is_empty() {
32+
"./"
33+
} else {
34+
&result.destination_relative_path
35+
};
3136
table.add_row(Row::new(vec![
3237
Cell::new(&result.source_file_name),
33-
Cell::new(&result.destination_relative_path),
38+
Cell::new(destination_relative_path),
3439
Cell::new(&result.score.to_string()),
3540
Cell::new(need_reorganize),
3641
]));
@@ -92,32 +97,18 @@ pub fn print_migration_plan_table(files_reorganization_plan: &[FilesReorganisati
9297
table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE);
9398

9499
files_reorganization_plan.first().iter().for_each(|plan| {
95-
let from = format!("📤 From: {}", plan.source);
96-
let to = format!("📥 To: {}", plan.destination);
100+
let from = format!("📤 From: {}/", plan.source);
101+
let to = format!("📥 To: {}/", plan.destination);
97102

98103
table.set_titles(Row::new(vec![Cell::new(&from), Cell::new(&to)]));
99104
});
100105

101106
files_reorganization_plan.iter().for_each(|plan| {
102-
// separators are needed for case when inner_path == "./" to avoid double slash
103-
let source_separator = if plan.source_inner_path == "./" {
104-
""
105-
} else {
106-
"/"
107-
};
108-
let destination_separator = if plan.destination_inner_path == "./" {
109-
""
110-
} else {
111-
"/"
112-
};
113-
let from = format!(
114-
"{}{}{}",
115-
plan.source_inner_path, source_separator, plan.file_name
116-
);
117-
let to = format!(
118-
"{}{}{}",
119-
plan.destination_inner_path, destination_separator, plan.file_name
120-
);
107+
let from_path = Path::new(&plan.source_inner_path).join(&plan.file_name);
108+
let to_path = Path::new(&plan.destination_inner_path).join(&plan.file_name);
109+
110+
let from = from_path.display().to_string();
111+
let to = to_path.display().to_string();
121112

122113
table.add_row(Row::new(vec![Cell::new(&from), Cell::new(&to)]));
123114
});

src/errors/app_error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ pub enum AppError {
1414

1515
#[error("JSON stringify error: {0}")]
1616
JSONStringify(String),
17+
18+
#[error("File processing error: {0}")]
19+
FileError(String),
1720
}

src/files/dirr_processing.rs

Lines changed: 121 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
use core::panic;
21
use regex::Regex;
32
use std::fs;
43
use std::path::Path;
54

6-
use crate::console::messages::print_ignoring_file;
7-
use crate::console::messages::print_ignoring_folder;
8-
use crate::console::messages::print_processing_directory;
9-
use crate::console::messages::print_processing_file;
10-
use crate::file_info::convert_path_meta_to_file_info;
11-
use crate::file_info::FileInfo;
5+
use crate::console::messages::{
6+
print_ignoring_entry, print_processing_directory, print_processing_file,
7+
};
8+
use crate::errors::app_error::AppError;
9+
use crate::file_info::{convert_path_meta_to_file_info, FileInfo};
1210

1311
pub struct CollectFilesMetaConfig {
1412
pub skip_problematic_dir: bool,
@@ -17,103 +15,133 @@ pub struct CollectFilesMetaConfig {
1715
pub process_files: bool,
1816
}
1917

18+
/*
19+
Collects file metadata and saves it to files_data vector.
20+
*/
2021
pub fn collect_files_metadata(
21-
base_path_str: &Path, // destination or source path provided in args
22-
inner_path: &str, // built during recursive calls. Use "./" for root call
23-
files_data: &mut Vec<FileInfo>, // result vector
22+
base_path: &Path,
23+
relative_path: &Path,
24+
files_data: &mut Vec<FileInfo>,
2425
ignore_patterns: &Vec<Regex>,
2526
config: &CollectFilesMetaConfig,
26-
) {
27-
let processed_path_buf = base_path_str.join(inner_path);
28-
let processed_path = processed_path_buf.as_path();
29-
30-
match fs::read_dir(processed_path) {
31-
Ok(read_dir_res) => {
32-
print_processing_directory(processed_path.to_str().unwrap());
33-
34-
for dir in read_dir_res.flatten() {
35-
let metadata = match dir.metadata() {
36-
Ok(meta) => meta,
37-
Err(err) => {
38-
eprintln!("Error reading metadata for {:?}: {:?}", dir.path(), err);
39-
continue;
40-
}
41-
};
42-
43-
let absolute_path = dir.path(); // begining from destination path in arg
44-
let full_relative_path = match absolute_path.strip_prefix(base_path_str) {
45-
Ok(p) => p.to_path_buf(),
46-
Err(_) => absolute_path.to_path_buf(),
47-
};
48-
let relative_path = inner_path.to_string();
49-
50-
let file_name = full_relative_path
51-
.file_name()
52-
.and_then(|s| s.to_str())
53-
.unwrap_or("unknown");
54-
55-
if metadata.is_file() {
56-
if is_ignored(file_name, ignore_patterns) {
57-
print_ignoring_file(full_relative_path.to_str().unwrap());
58-
continue;
59-
}
60-
61-
print_processing_file(file_name);
62-
63-
if config.process_files {
64-
let file_info = convert_path_meta_to_file_info(
65-
&full_relative_path,
66-
relative_path,
67-
metadata,
68-
false,
69-
);
70-
files_data.push(file_info);
71-
}
72-
} else {
73-
if is_ignored(file_name, ignore_patterns) {
74-
print_ignoring_folder(full_relative_path.to_str().unwrap());
75-
continue;
76-
}
77-
78-
if config.process_folders {
79-
let file_info = convert_path_meta_to_file_info(
80-
&full_relative_path,
81-
relative_path,
82-
metadata,
83-
false,
84-
);
85-
files_data.push(file_info);
86-
}
87-
88-
if config.recursive {
89-
if let Some(currently_processing_dir) = dir.file_name().to_str() {
90-
let full_sub_path =
91-
Path::new(inner_path).join(currently_processing_dir);
92-
let full_sub_path_str = full_sub_path.to_str().unwrap();
93-
94-
collect_files_metadata(
95-
base_path_str,
96-
full_sub_path_str,
97-
files_data,
98-
ignore_patterns,
99-
config,
100-
);
101-
}
102-
}
103-
}
104-
}
27+
) -> Result<(), AppError> {
28+
let processed_path = base_path.join(relative_path);
29+
30+
let read_dir_iter = match fs::read_dir(&processed_path) {
31+
Ok(rd) => rd,
32+
Err(e) => {
33+
eprintln!("Error reading directory {:?}: {:?}", processed_path, e);
34+
return Err(AppError::FileError(format!(
35+
"Error reading directory {:?}: {}",
36+
processed_path, e
37+
)));
38+
}
39+
};
40+
41+
print_processing_directory(processed_path.to_str().unwrap_or("[invalid path]"));
42+
43+
for dir_entry_result in read_dir_iter {
44+
let Some((dir, metadata)) = get_dir_entry_and_metadata(dir_entry_result, config)? else {
45+
continue;
46+
};
47+
48+
let file_name = dir.file_name().to_string_lossy().to_string(); //.to_string_lossy().to_string();
49+
let is_file = metadata.is_file();
50+
51+
let new_relative_path = relative_path.join(&file_name);
52+
53+
if is_ignored(&file_name, ignore_patterns) {
54+
print_ignoring_entry(is_file, new_relative_path.to_str().unwrap());
55+
continue;
10556
}
106-
Err(err) => {
107-
eprintln!("Error reading directory {:?}: {:?}", processed_path, err);
108-
if !config.skip_problematic_dir {
109-
panic!("Error reading directory {:?}: {:?}", processed_path, err);
57+
58+
if is_file {
59+
handle_file_entry(&file_name, relative_path, metadata, config, files_data);
60+
} else {
61+
handle_folder_entry(file_name, relative_path, metadata, config, files_data);
62+
63+
if config.recursive {
64+
collect_files_metadata(
65+
base_path,
66+
new_relative_path.as_path(),
67+
files_data,
68+
ignore_patterns,
69+
config,
70+
)?;
11071
}
11172
}
11273
}
74+
75+
Ok(())
11376
}
11477

11578
fn is_ignored(file_path: &str, ignore_patterns: &[Regex]) -> bool {
11679
ignore_patterns
11780
.iter()
11881
.any(|pattern| pattern.is_match(file_path))
11982
}
83+
84+
fn get_dir_entry_and_metadata(
85+
dir_entry_result: Result<std::fs::DirEntry, std::io::Error>,
86+
config: &CollectFilesMetaConfig,
87+
) -> Result<Option<(std::fs::DirEntry, std::fs::Metadata)>, AppError> {
88+
let dir = match dir_entry_result {
89+
Ok(entry) => entry,
90+
Err(e) => {
91+
if config.skip_problematic_dir {
92+
eprintln!("Error reading directory entry: {:?}", e);
93+
return Ok(None);
94+
} else {
95+
return Err(AppError::FileError(e.to_string()));
96+
}
97+
}
98+
};
99+
100+
let metadata = match dir.metadata() {
101+
Ok(m) => m,
102+
Err(e) => {
103+
if config.skip_problematic_dir {
104+
eprintln!("Error reading metadata for {:?}: {:?}", dir.path(), e);
105+
return Ok(None);
106+
} else {
107+
return Err(AppError::FileError(e.to_string()));
108+
}
109+
}
110+
};
111+
112+
Ok(Some((dir, metadata)))
113+
}
114+
115+
fn handle_file_entry(
116+
file_name: &String,
117+
relative_path: &Path,
118+
metadata: std::fs::Metadata,
119+
config: &CollectFilesMetaConfig,
120+
files_data: &mut Vec<FileInfo>,
121+
) {
122+
print_processing_file(file_name);
123+
124+
if config.process_files {
125+
let file_info =
126+
convert_path_meta_to_file_info(file_name.to_string(), relative_path, metadata, false);
127+
files_data.push(file_info);
128+
}
129+
}
130+
131+
fn handle_folder_entry(
132+
file_name: String,
133+
relative_path: &Path,
134+
metadata: std::fs::Metadata,
135+
config: &CollectFilesMetaConfig,
136+
files_data: &mut Vec<FileInfo>,
137+
) {
138+
if config.process_folders {
139+
let file_info = convert_path_meta_to_file_info(
140+
file_name.clone(),
141+
relative_path,
142+
metadata.clone(),
143+
false,
144+
);
145+
files_data.push(file_info);
146+
}
147+
}

src/files/file_info.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,14 @@ fn get_system_time_string(time: SystemTime) -> String {
2222
}
2323

2424
pub fn convert_path_meta_to_file_info(
25-
full_path: &Path,
26-
relative_path: String,
25+
file_name: String,
26+
relative_path: &Path,
2727
file_meta: Metadata,
2828
is_root: bool,
2929
) -> FileInfo {
30-
let file_name = full_path
31-
.file_name()
32-
.map(|s| s.to_string_lossy().to_string())
33-
.unwrap_or_else(|| "unknown".to_string());
34-
35-
// let relative_path = full_path.to_string_lossy().to_string();
36-
3730
FileInfo {
3831
file_name,
39-
relative_path,
32+
relative_path: relative_path.to_string_lossy().to_string(),
4033
size: file_meta.len(),
4134
created_at: get_system_time_string(file_meta.created().unwrap_or(SystemTime::now())),
4235
modified_at: get_system_time_string(file_meta.modified().unwrap_or(SystemTime::now())),

src/main.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ async fn main() {
4040
print_app_error("Qdrant Error", e);
4141
std::process::exit(1);
4242
}
43+
AppError::JSONStringify(_) => {
44+
print_app_error("JSON stringify error", e);
45+
std::process::exit(1);
46+
}
47+
AppError::FileError(_) => {
48+
print_app_error("File processing error", e);
49+
std::process::exit(1);
50+
}
4351
_ => {
4452
print_app_error("Panic", e);
4553
panic!("Unhandled error. \n Please post error stack trace on github issues page https://github.com/PerminovEugene/messy-folder-reorganizer-ai/issues");

0 commit comments

Comments
 (0)