1- use core:: panic;
21use regex:: Regex ;
32use std:: fs;
43use 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
1311pub 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+ */
2021pub 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
11578fn 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+ }
0 commit comments