1use itertools::Itertools;
2use std::collections::HashMap;
3use std::env;
4use std::ffi::OsStr;
5use std::fs;
6use std::path;
7use std::process;
8use walkdir::WalkDir;
9
10pub fn get_os_sep() -> String {
11 if cfg!(windows) {
12 return String::from("\\");
13 } else if cfg!(unix) {
14 return String::from("/");
15 } else {
16 eprintln!("Your OS is not supported!");
17 process::exit(201);
18 }
19}
20
21pub fn get_dirs_recursively(path: &str, follow_links: bool, include_dot_files: bool) -> Vec<String> {
22 let mut files: Vec<String> = vec![];
23
24 for dir in WalkDir::new(&path)
25 .follow_links(follow_links)
26 .into_iter()
27 .filter_map(|dir| dir.ok())
28 {
29 if dir.metadata().unwrap().is_dir() {
31 if !include_dot_files {
32 if dir.file_name().to_str().unwrap().chars().next().unwrap().to_string() == "." {
33 continue;
34 }
35 }
36 files.push(dir.path().display().to_string());
37 }
38 }
39
40 files
41}
42
43pub fn get_current_dir() -> String {
44 match env::current_dir() {
45 Ok(dir) => dir.display().to_string(),
46 Err(error) => {
47 eprintln!(
48 "[001] There was an error getting the current dir path, the given error is: {}",
49 error
50 );
51 process::exit(1);
52 }
53 }
54}
55
56pub fn get_files_in_dir(path: &str, include_dot_files: bool) -> Vec<path::PathBuf> {
57 let read = match fs::read_dir(&path) {
58 Ok(read) => read,
59 Err(error) => {
60 eprintln!(
61 "[002] There was an error reading a directory, the given error is: {}",
62 error
63 );
64 process::exit(2);
65 }
66 };
67
68 let mut files = Vec::new();
69 for entry in read.filter_map(|file| file.ok()) {
70 if entry.metadata().unwrap().is_file() {
72 if !include_dot_files {
73 if &entry
74 .file_name()
75 .to_str()
76 .unwrap()
77 .chars()
78 .next()
79 .unwrap()
80 .to_string()
81 == "."
82 {
83 continue;
84 }
85 }
86 files.push(entry.path());
87 }
88 }
89
90 files
91}
92
93pub fn get_file_extensions(files: &Vec<path::PathBuf>) -> Vec<String> {
94 let mut extensions = Vec::new();
96 for file in files {
97 let extension = match file.extension() {
99 Some(ext_os) => match ext_os.to_str() {
100 Some(ext) => ext,
101 None => {
102 eprintln!("[003] There was an error getting the extension of a file, this may be bug, but please check your file extensions");
103 process::exit(3);
104 }
105 },
106 None => "else",
107 };
108 extensions.push(extension.to_string().to_uppercase());
109 }
110
111 extensions.sort();
114 extensions.dedup();
116
117 extensions
118}
119
120pub fn get_file_ext_names(files: &Vec<path::PathBuf>) -> HashMap<String, String> {
121 let extensions = get_file_extensions(files);
122
123 let ext_len = &extensions.len().to_string();
125 if ext_len == &"1" || ext_len == &"0" {
126 if &files.len().to_string() != "0" {
127 let parent = match files[0].parent() {
128 Some(root) => root.to_str().unwrap(),
129 None => "ROOT",
130 };
131 println!("ALREADY SORTED DIR: {}", parent);
132 }
133 return HashMap::new();
134 }
135
136 let mut extensions_dupped = Vec::new();
138 for file in files {
139 let extension = match file.extension() {
141 Some(ext_os) => match ext_os.to_str() {
142 Some(ext) => ext,
143 None => {
144 eprintln!("[003] There was an error getting the extension of a file, this may be bug, but please check your file extensions");
145 process::exit(3);
146 }
147 },
148 None => "else",
149 };
150 extensions_dupped.push(extension.to_string().to_uppercase());
151 }
152 extensions_dupped.sort();
154 extensions_dupped.reverse();
156
157 let mut ext_count = Vec::new();
159 let mut last_count = 0;
160 for item in &extensions {
161 let index = &extensions_dupped.iter().position(|x| x == item).unwrap();
162 let count = &extensions_dupped.len() - index - last_count;
163 last_count = last_count + count;
164 ext_count.push((count, item));
165 }
166 ext_count.sort();
168
169 let mut start_number = ext_count.len();
171 let mut ext_dir_names = HashMap::new();
172 for key in &ext_count {
173 ext_dir_names.insert(key.1.to_owned(), start_number.to_string() + "-" + key.1);
174 start_number = start_number - 1;
175 }
176
177 ext_dir_names
178}
179
180pub fn mass_make_dirs(path: &str, names: &Vec<&String>) {
181 match env::set_current_dir(&path) {
182 Ok(_) => (),
183 Err(error) => {
184 eprintln!(
185 "[004] There was an error changing the current dir, the given error is: {}",
186 error
187 );
188 process::exit(4);
189 }
190 };
191
192 for name in names {
193 match fs::create_dir(name) {
194 Ok(_) => (),
195 Err(error) => {
196 eprintln!("[005] There was an error creating a new dir inside the dir/one of the sub dirs, the given error is: {}", error);
197 process::exit(5);
198 }
199 };
200 }
201}
202
203pub fn sort_files_by_ext(path: &str, include_dot_files: bool) {
204 let os_sep = get_os_sep();
206
207 match env::set_current_dir(&path) {
209 Ok(_) => (),
210 Err(error) => {
211 eprintln!(
212 "[004] There was an error changing the current dir, the given error is: {}",
213 error
214 );
215 process::exit(4);
216 }
217 };
218
219 let files = get_files_in_dir(&path, include_dot_files);
221
222 let extensions = get_file_ext_names(&files);
224 let ext_len = &extensions.len().to_string();
226 if ext_len == &"1" || ext_len == &"0" {
227 return;
228 }
229
230 let folders = extensions.values().collect();
231
232 mass_make_dirs(&path, &folders);
234
235 for file in files {
237 let file_name = match file.file_name() {
238 Some(name) => name,
239 None => {
240 eprintln!("[006] There was an issue getting a file's name, files that terminate in \"..\" are not supported!");
241 process::exit(6);
242 }
243 };
244
245 let root_path = match file.parent() {
246 Some(path) => match path.to_str() {
247 Some(str) => str,
248 None => {
249 eprintln!("[007] There was a problem converting a path to string!");
250 process::exit(7);
251 }
252 },
253 None => {
254 eprintln!("[008] There was a problem getting the parent directory of a path!");
255 process::exit(8);
256 }
257 };
258 let extension = match &file.extension() {
260 Some(ext) => ext.to_str().unwrap(),
261 None => "else",
262 };
263 let destination = root_path.to_owned()
264 + &os_sep
265 + &extensions[&extension.to_uppercase()]
266 + &os_sep
267 + file_name.to_str().unwrap();
268
269 match fs::copy(&file, &destination) {
271 Ok(_) => {
272 println!("COPY: {} -> {}", &file.display().to_string(), &destination);
273 }
274 Err(error) => {
275 eprintln!("[008] There was an error copying a file to the newly created dir for it, the given error is: {}", error);
276 process::exit(8);
277 }
278 };
279
280 match fs::remove_file(&file) {
282 Ok(_) => {
283 println!("DELETE: {}", &file.display().to_string());
284 }
285 Err(error) => {
286 eprintln!("There was a problem deleting a file that was successfully copied to it's new location, the given error is: {}", error);
287 }
288 };
289 }
290}