Add some comments
This commit is contained in:
parent
9d4de08ece
commit
7eeff49426
18
README.md
18
README.md
|
@ -4,30 +4,37 @@ It is in very early development, so most of the functions aren't added and doesn
|
|||
|
||||
|
||||
## Done
|
||||
- Basic menu(need refactoring)
|
||||
- Rich instruction with examples - CLI(`cargo run --bin czkawka_cli`)
|
||||
- Duplicated file finding - CLI
|
||||
- Including and excluding directories(absolute pathes)
|
||||
- Option to remove files in different ways
|
||||
- Fast(by size) or accurate(by hash) file checking
|
||||
- Empty folders finding - CLI
|
||||
- Advanced empty files finding(finds and remove folders which contains only empty folders)
|
||||
- Option to remove all files
|
||||
|
||||
## TODO
|
||||
- Comments - a lot of things should be described
|
||||
- Tests
|
||||
- Github CI
|
||||
- Unit tests(if available)
|
||||
- Duplicated file finding - CLI
|
||||
- saving results to file
|
||||
- support for * when excluding files and folders
|
||||
- GUI(GTK)
|
||||
- Removing empty folders
|
||||
- Files with debug symbols
|
||||
- Support for showing only duplicates with specific extension, name(Regex support needed)
|
||||
- Maybe windows support, but this will need some refactoring in code
|
||||
|
||||
## Usage
|
||||
For now only Linux(and probably also macOS) is supported
|
||||
- Install requirements for GTK(minimum 3.16)
|
||||
```
|
||||
apt install -y libgtk-3-dev
|
||||
```
|
||||
- Download source
|
||||
```
|
||||
git clone github/czkawka // TODO
|
||||
git clone https://github.com/qarmin/czkawka.git
|
||||
cd czkawka
|
||||
```
|
||||
- Run GUI(Still WIP)
|
||||
|
@ -35,8 +42,9 @@ cd czkawka
|
|||
cargo run --bin czkawka_gui
|
||||
```
|
||||
- Run CLI
|
||||
|
||||
|
||||
```
|
||||
cargo run --bin czkawka_cli
|
||||
```
|
||||
|
||||
## License
|
||||
Czkawka is released under the terms of the GNU Lesser General Public License, version 2.1 or, at your option, any later version, as published by the Free Software Foundation.
|
|
@ -151,7 +151,7 @@ impl DuplicateFinder {
|
|||
println!("Include Directory ERROR: Path {} doesn't exists.", directory);
|
||||
continue;
|
||||
}
|
||||
if !Path::new(&directory).exists() {
|
||||
if !Path::new(&directory).is_dir() {
|
||||
println!("Include Directory ERROR: {} isn't folder.", directory);
|
||||
continue;
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ impl DuplicateFinder {
|
|||
println!("Exclude Directory ERROR: Path {} doesn't exists.", directory);
|
||||
continue;
|
||||
}
|
||||
if !Path::new(&directory).exists() {
|
||||
if !Path::new(&directory).is_dir() {
|
||||
println!("Exclude Directory ERROR: {} isn't folder.", directory);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -5,18 +5,22 @@ use std::path::Path;
|
|||
use std::time::SystemTime;
|
||||
use std::{fs, process};
|
||||
|
||||
/// Enum with values which show if folder is empty.
|
||||
/// In function "optimize_folders" automatically "Maybe" is changed to "Yes", so it is not necessery to put it here
|
||||
#[derive(Eq, PartialEq, Copy, Clone)]
|
||||
enum FolderEmptiness {
|
||||
No,
|
||||
Maybe,
|
||||
}
|
||||
|
||||
/// Struct assigned to each checked folder with parent path(used to ignore parent if children are not empty) and flag which shows if folder is empty
|
||||
#[derive(Clone)]
|
||||
struct FolderEntry {
|
||||
parent_path: Option<String>,
|
||||
is_empty: FolderEmptiness,
|
||||
}
|
||||
|
||||
/// Struct to store most basics info about all folder
|
||||
pub struct EmptyFolder {
|
||||
number_of_checked_folders: usize,
|
||||
number_of_empty_folders: usize,
|
||||
|
@ -25,7 +29,9 @@ pub struct EmptyFolder {
|
|||
included_directories: Vec<String>,
|
||||
}
|
||||
|
||||
/// Method implementation for EmptyFolder
|
||||
impl EmptyFolder {
|
||||
/// New function providing basics values
|
||||
pub fn new() -> EmptyFolder {
|
||||
EmptyFolder {
|
||||
number_of_checked_folders: 0,
|
||||
|
@ -36,6 +42,7 @@ impl EmptyFolder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Public function used by CLI to search for empty folders
|
||||
pub fn find_empty_folders(mut self, delete_folders: bool) {
|
||||
self.optimize_directories();
|
||||
self.debug_print();
|
||||
|
@ -68,7 +75,8 @@ impl EmptyFolder {
|
|||
self.empty_folder_list = new_directory_folders;
|
||||
}
|
||||
|
||||
/// Function to check if folder are empty, initial_checking is used to check again if folder is
|
||||
/// Function to check if folder are empty.
|
||||
/// Parameter initial_checking for second check before deleting to be sure that checked folder is still empty
|
||||
fn check_for_empty_folders(&mut self, initial_checking: bool) {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
let mut folders_to_check: Vec<String> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
|
||||
|
@ -87,7 +95,7 @@ impl EmptyFolder {
|
|||
folders_to_check.push(id.clone());
|
||||
}
|
||||
} else {
|
||||
// Add root folders for finding
|
||||
// Add folders searched before
|
||||
for id in &self.empty_folder_list {
|
||||
folders_checked.insert(
|
||||
id.0.clone(),
|
||||
|
@ -104,7 +112,7 @@ impl EmptyFolder {
|
|||
let mut next_folder: String;
|
||||
while !folders_to_check.is_empty() {
|
||||
current_folder = folders_to_check.pop().unwrap();
|
||||
|
||||
// Checked folder may be deleted so we assume that cannot removed folder be empty
|
||||
let read_dir = match fs::read_dir(¤t_folder) {
|
||||
Ok(t) => t,
|
||||
_ => {
|
||||
|
@ -112,9 +120,11 @@ impl EmptyFolder {
|
|||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for entry in read_dir {
|
||||
let entry_data = entry.unwrap();
|
||||
let metadata: Metadata = entry_data.metadata().unwrap();
|
||||
// If child is dir, still folder may be considered as empty if all children are only directories.
|
||||
if metadata.is_dir() {
|
||||
let mut is_excluded_dir = false;
|
||||
next_folder = "".to_owned() + ¤t_folder + &entry_data.file_name().into_string().unwrap() + "/";
|
||||
|
@ -136,7 +146,7 @@ impl EmptyFolder {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
// Not folder so it may be a file or symbolic link
|
||||
// Not folder so it may be a file or symbolic link so it isn't empty
|
||||
folders_checked.get_mut(¤t_folder).unwrap().is_empty = FolderEmptiness::No;
|
||||
let mut d = folders_checked.get_mut(¤t_folder).unwrap();
|
||||
let mut cf: String;
|
||||
|
@ -153,13 +163,14 @@ impl EmptyFolder {
|
|||
}
|
||||
}
|
||||
if initial_checking {
|
||||
// We need to set empty folder list
|
||||
for entry in folders_checked {
|
||||
if entry.1.is_empty != FolderEmptiness::No {
|
||||
self.empty_folder_list.insert(entry.0, entry.1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sprawdzenie
|
||||
// We need to check if parent of folder isn't also empty, because we wan't to delete only parent with two empty folders except this folders and at the end parent folder
|
||||
let mut new_folders_list: HashMap<String, FolderEntry> = Default::default();
|
||||
for entry in folders_checked {
|
||||
if entry.1.is_empty != FolderEmptiness::No && self.empty_folder_list.contains_key(&entry.0) {
|
||||
|
@ -172,9 +183,11 @@ impl EmptyFolder {
|
|||
Common::print_time(start_time, SystemTime::now(), "check_for_empty_folder".to_string());
|
||||
}
|
||||
|
||||
/// Deletes earlier finded empty folders
|
||||
fn delete_empty_folders(&self) {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
let mut errors: Vec<String> = Vec::new();
|
||||
// Folders may be deleted or require too big privileges
|
||||
for entry in &self.empty_folder_list {
|
||||
match fs::remove_dir_all(entry.0) {
|
||||
Ok(_) => (),
|
||||
|
@ -192,6 +205,7 @@ impl EmptyFolder {
|
|||
Common::print_time(start_time, SystemTime::now(), "delete_files".to_string());
|
||||
}
|
||||
|
||||
/// Prints basic info about empty folders
|
||||
fn print_empty_folders(&self) {
|
||||
if !self.empty_folder_list.is_empty() {
|
||||
println!("Found {} empty folders", self.empty_folder_list.len());
|
||||
|
@ -201,6 +215,7 @@ impl EmptyFolder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Debug print
|
||||
fn debug_print(&self) {
|
||||
if false {
|
||||
println!("---------------DEBUG PRINT---------------");
|
||||
|
@ -216,6 +231,7 @@ impl EmptyFolder {
|
|||
}
|
||||
|
||||
// TODO maybe move this and one from duplicated finder to one common class to avoid duplicating code
|
||||
/// Optimize include and exclude directories by removing duplicates etc.
|
||||
fn optimize_directories(&mut self) {
|
||||
let start_time: SystemTime = SystemTime::now();
|
||||
|
||||
|
@ -333,6 +349,8 @@ impl EmptyFolder {
|
|||
self.included_directories.sort();
|
||||
Common::print_time(start_time, SystemTime::now(), "optimize_directories".to_string());
|
||||
}
|
||||
|
||||
/// Set include dir which needst to be relative, exists,
|
||||
pub fn set_include_directory(&mut self, mut include_directory: String) {
|
||||
// let start_time: SystemTime = SystemTime::now();
|
||||
|
||||
|
@ -369,7 +387,7 @@ impl EmptyFolder {
|
|||
println!("Include Directory ERROR: Path {} doesn't exists.", directory);
|
||||
continue;
|
||||
}
|
||||
if !Path::new(&directory).exists() {
|
||||
if !Path::new(&directory).is_dir() {
|
||||
println!("Include Directory ERROR: {} isn't folder.", directory);
|
||||
continue;
|
||||
}
|
||||
|
@ -428,7 +446,7 @@ impl EmptyFolder {
|
|||
println!("Exclude Directory ERROR: Path {} doesn't exists.", directory);
|
||||
continue;
|
||||
}
|
||||
if !Path::new(&directory).exists() {
|
||||
if !Path::new(&directory).is_dir() {
|
||||
println!("Exclude Directory ERROR: {} isn't folder.", directory);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
pub mod common;
|
||||
pub mod duplicate;
|
||||
pub mod empty_folder;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue