added recursive file reading using --recursive flag.
added a feature to scan subdirectory and organize the file structure even further.
This commit is contained in:
39
src/files.rs
39
src/files.rs
@@ -2,6 +2,7 @@ use colored::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::{ffi::OsStr, fs, path::Path, path::PathBuf};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct FileCategory {
|
||||
@@ -21,31 +22,31 @@ pub struct FileBatch {
|
||||
impl FileBatch {
|
||||
/// Reads a directory path and populates lists of all files inside it.
|
||||
/// It skips sub-directories (does not read recursively).
|
||||
pub fn from_path(root_path: PathBuf) -> Self {
|
||||
pub fn from_path(root_path: PathBuf, recursive: bool) -> Self {
|
||||
let mut filenames = Vec::new();
|
||||
let mut paths = Vec::new();
|
||||
|
||||
let entries = match fs::read_dir(&root_path) {
|
||||
Ok(entries) => entries,
|
||||
Err(e) => {
|
||||
eprintln!("Error reading directory {:?}: {}", root_path, e);
|
||||
return FileBatch {
|
||||
filenames: Vec::new(),
|
||||
paths: Vec::new(),
|
||||
};
|
||||
}
|
||||
let walker = if recursive {
|
||||
WalkDir::new(&root_path).min_depth(1).follow_links(false)
|
||||
} else {
|
||||
WalkDir::new(&root_path)
|
||||
.min_depth(1)
|
||||
.max_depth(1)
|
||||
.follow_links(false)
|
||||
};
|
||||
|
||||
for entry in entries.flatten() {
|
||||
for entry in walker.into_iter().filter_map(|e| e.ok()) {
|
||||
let path = entry.path();
|
||||
if path.is_file()
|
||||
&& let Ok(relative_path) = path.strip_prefix(&root_path)
|
||||
{
|
||||
filenames.push(relative_path.to_string_lossy().into_owned());
|
||||
paths.push(path);
|
||||
if path.is_file() {
|
||||
match path.strip_prefix(&root_path) {
|
||||
Ok(relative_path) => {
|
||||
filenames.push(relative_path.to_string_lossy().into_owned());
|
||||
paths.push(path.to_path_buf());
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error getting relative path for {:?}: {}", path, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileBatch { filenames, paths }
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ fn test_file_batch_from_path() {
|
||||
File::create(dir_path.join("file2.rs")).unwrap();
|
||||
fs::create_dir(dir_path.join("subdir")).unwrap();
|
||||
|
||||
let batch = FileBatch::from_path(dir_path.to_path_buf());
|
||||
let batch = FileBatch::from_path(dir_path.to_path_buf(), false);
|
||||
assert_eq!(batch.count(), 2);
|
||||
assert!(batch.filenames.contains(&"file1.txt".to_string()));
|
||||
assert!(batch.filenames.contains(&"file2.rs".to_string()));
|
||||
@@ -43,10 +43,47 @@ fn test_file_batch_from_path() {
|
||||
|
||||
#[test]
|
||||
fn test_file_batch_from_path_nonexistent() {
|
||||
let batch = FileBatch::from_path(PathBuf::from("/nonexistent/path"));
|
||||
let batch = FileBatch::from_path(PathBuf::from("/nonexistent/path"), false);
|
||||
assert_eq!(batch.count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_batch_from_path_non_recursive() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let dir_path = temp_dir.path();
|
||||
File::create(dir_path.join("file1.txt")).unwrap();
|
||||
File::create(dir_path.join("file2.rs")).unwrap();
|
||||
fs::create_dir(dir_path.join("subdir")).unwrap();
|
||||
File::create(dir_path.join("subdir").join("file3.txt")).unwrap();
|
||||
let batch = FileBatch::from_path(dir_path.to_path_buf(), false);
|
||||
assert_eq!(batch.count(), 2);
|
||||
assert!(batch.filenames.contains(&"file1.txt".to_string()));
|
||||
assert!(batch.filenames.contains(&"file2.rs".to_string()));
|
||||
assert!(!batch.filenames.contains(&"subdir/file3.txt".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_batch_from_path_recursive() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let dir_path = temp_dir.path();
|
||||
File::create(dir_path.join("file1.txt")).unwrap();
|
||||
fs::create_dir(dir_path.join("subdir1")).unwrap();
|
||||
File::create(dir_path.join("subdir1").join("file2.rs")).unwrap();
|
||||
fs::create_dir(dir_path.join("subdir1").join("nested")).unwrap();
|
||||
File::create(dir_path.join("subdir1").join("nested").join("file3.md")).unwrap();
|
||||
fs::create_dir(dir_path.join("subdir2")).unwrap();
|
||||
File::create(dir_path.join("subdir2").join("file4.py")).unwrap();
|
||||
let batch = FileBatch::from_path(dir_path.to_path_buf(), true);
|
||||
assert_eq!(batch.count(), 4);
|
||||
assert!(batch.filenames.contains(&"file1.txt".to_string()));
|
||||
assert!(batch.filenames.contains(&"subdir1/file2.rs".to_string()));
|
||||
assert!(
|
||||
batch
|
||||
.filenames
|
||||
.contains(&"subdir1/nested/file3.md".to_string())
|
||||
);
|
||||
assert!(batch.filenames.contains(&"subdir2/file4.py".to_string()));
|
||||
}
|
||||
#[test]
|
||||
fn test_read_file_sample() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
@@ -22,6 +22,8 @@ struct Args {
|
||||
help = "Maximum concurrent API requests"
|
||||
)]
|
||||
max_concurrent: usize,
|
||||
#[arg(long, help = "Recursively searches files in subdirectory")]
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -37,7 +39,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
cache.cleanup_old_entries(7 * 24 * 60 * 60);
|
||||
|
||||
let batch = FileBatch::from_path(download_path.clone());
|
||||
let batch = FileBatch::from_path(download_path.clone(), args.recursive);
|
||||
|
||||
if batch.filenames.is_empty() {
|
||||
println!("{}", "No files found to organize!".yellow());
|
||||
|
||||
Reference in New Issue
Block a user