mod config;
#[cfg(test)]
mod tests;
use config::EXTENSIONS;
use rand::Rng;
use self_update::cargo_crate_version;
use std::{
collections::HashMap,
ffi::OsStr,
fs,
io::Write,
path::{Path, PathBuf},
time::{Duration, SystemTime},
};
pub fn create_files(amount: u32) {
for file in 1..amount {
let mut file_name = String::new();
file_name.push_str(&file.to_string());
file_name.push('.');
let mut rng = rand::thread_rng();
let random_extension = EXTENSIONS[rng.gen_range(0..EXTENSIONS.len())].0;
file_name.push_str(random_extension);
let _file = fs::File::create(file_name).expect("Failed to create file");
}
}
pub fn custom_sort(
input_directory: &str,
output_directory: &str,
extension: &str,
verbose: bool,
log: bool,
) {
let input_directory = Path::new(input_directory);
let output_directory = Path::new(output_directory);
let files = fs::read_dir(input_directory).unwrap();
for file in files {
let file = file.unwrap().path();
let _file_name = match file.file_name() {
Some(file_name) => file_name,
None => continue,
};
match file.extension() {
Some(ext) if ext == extension => {
fs::create_dir_all(output_directory).unwrap();
let output_file = output_directory.join(file.file_name().unwrap());
fs::rename(file.clone(), output_file).unwrap();
}
_ => continue,
}
if verbose {
println!("Moved file: {:?} to {:?}", file, output_directory);
}
if log {
write_logfile(
file.as_os_str(),
output_directory,
input_directory.to_str().unwrap(),
);
}
}
}
pub fn get_subdir_by_extension(ext: &str, nesting_level: u8, use_alt: bool) -> PathBuf {
if !(1..=3).contains(&nesting_level) {
panic!("Nesting level is out of range.");
}
let extensions: HashMap<&str, (&str, Option<&str>, Option<&str>)> =
HashMap::from(config::EXTENSIONS);
let ext_data = match extensions.get(ext) {
None => return PathBuf::from("other"),
Some(e) => e,
};
let mut path = PathBuf::from(ext_data.0);
match (nesting_level, use_alt) {
(1, _) => {} (2, true) => {
path.push(ext_data.1.unwrap_or(ext_data.2.unwrap_or(ext))); }
(3, true) => {
if ext_data.1.is_some() {
path.push(ext_data.1.unwrap())
}
path.push(ext_data.2.unwrap_or(ext));
}
(_, false) => {
path.push(ext_data.2.unwrap_or(ext));
}
_ => {
panic!(
"{} | get_subdir_by_extension() | nesting_level: {nesting_level}, use_alt: {use_alt}",
file!()
)
}
}
path
}
pub fn write_logfile(file_name: &OsStr, moveto_directory: &Path, input_directory: &str) -> bool {
let logdir = Path::new(input_directory).join("sorter-logs/");
fs::create_dir_all(logdir.clone()).unwrap();
let mut logfile = fs::OpenOptions::new()
.append(true)
.create(true)
.open(logdir.to_str().unwrap().to_owned() + "sorter.log")
.expect("create failed");
logfile
.write_all(format!("{:?}", file_name).as_bytes())
.expect("write failed");
logfile
.write_all(" Moved to ".as_bytes())
.expect("write failed");
logfile
.write_all(format!("{:?}\n", moveto_directory.display()).as_bytes())
.expect("write failed");
true
}
pub fn sort_files(
in_dir: PathBuf,
out_dir: PathBuf,
nesting_level: u8,
use_alt: bool,
verbose: bool,
log: bool,
) -> std::io::Result<()> {
for entry in fs::read_dir(in_dir.clone())? {
let path = entry?.path();
let file_name = match path.file_name() {
None => continue,
Some(f) => f,
};
let ext = match path.extension() {
None => continue,
Some(e) => e,
};
let moveto_directory = out_dir.join(get_subdir_by_extension(
ext.to_str().unwrap(),
nesting_level,
use_alt,
));
fs::create_dir_all(&moveto_directory).unwrap();
fs::rename(&path, moveto_directory.join(path.file_name().unwrap()))?;
if verbose {
println!("{:?} moved to {:?}", file_name, moveto_directory.display());
}
if log {
let log_dir = "sorter-logs";
fs::create_dir_all(log_dir).unwrap();
write_logfile(file_name, &moveto_directory, in_dir.to_str().unwrap());
}
}
Ok(())
}
pub fn update_filesorterx() -> Result<(), Box<dyn (std::error::Error)>> {
println!("Updating FileSorterX to the latest version...");
let status = self_update::backends::github::Update::configure()
.repo_owner("xanthus58")
.repo_name("FileSorterX")
.bin_name("github")
.show_download_progress(true)
.current_version(cargo_crate_version!())
.build()?
.update()?;
println!("Update status: `{}`!", status.version());
Ok(())
}
pub fn benchmark() -> Duration {
let files = fs::read_dir(".");
if files.is_ok() && files.unwrap().count() > 0 {
println!("Please run benchmark in an empty directory.");
return Duration::from_secs(0);
}
let startbench = SystemTime::now();
create_files(10001);
sort_files(".".into(), "./benchmark".into(), 3, false, false, false)
.expect("Failed to sort files");
let endbench = SystemTime::now();
std::fs::remove_dir_all("./benchmark").expect("Failed to remove benchmark directory");
endbench.duration_since(startbench).unwrap()
}