1
0
Fork 0
mirror of synced 2024-05-19 11:53:43 +12:00

Dryrun for duplicates (#277)

```
    czkawka_cli dup --dryrun -d $(pwd)/folder -m1 -D aen
    Found 2 duplicated files in 1 groups with same content which took 2 B:
    Size - 2 B (2) - 2 files
    /home/thomas/Development/czkawka/folder/a
    /home/thomas/Development/czkawka/folder/b
    ----

    -------------------------------MESSAGES--------------------------------
    Delete /home/thomas/Development/czkawka/folder/a
    Delete /home/thomas/Development/czkawka/folder/b
    ---------------------------END OF MESSAGES-----------------------------
    ```
This commit is contained in:
Thomas Andreas Jung 2021-03-01 12:23:43 +01:00 committed by GitHub
parent ed7b197100
commit 1d904a858e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 13 deletions

View file

@ -32,6 +32,8 @@ pub enum Commands {
not_recursive: NotRecursive, not_recursive: NotRecursive,
#[structopt(flatten)] #[structopt(flatten)]
allow_hard_links: AllowHardLinks, allow_hard_links: AllowHardLinks,
#[structopt(flatten)]
dryrun: DryRun,
}, },
#[structopt(name = "empty-folders", about = "Finds empty folders", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka empty-folders -d /home/rafal/rr /home/gateway -f results.txt")] #[structopt(name = "empty-folders", about = "Finds empty folders", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka empty-folders -d /home/rafal/rr /home/gateway -f results.txt")]
EmptyFolders { EmptyFolders {
@ -235,6 +237,12 @@ pub struct AllowHardLinks {
pub allow_hard_links: bool, pub allow_hard_links: bool,
} }
#[derive(Debug, StructOpt)]
pub struct DryRun {
#[structopt(long, help = "Do nothing and print the operation that would happen.")]
pub dryrun: bool,
}
impl FileToSave { impl FileToSave {
pub fn file_name(&self) -> Option<&str> { pub fn file_name(&self) -> Option<&str> {
if let Some(file_name) = &self.file_to_save { if let Some(file_name) = &self.file_to_save {

View file

@ -40,6 +40,7 @@ fn main() {
file_to_save, file_to_save,
not_recursive, not_recursive,
allow_hard_links, allow_hard_links,
dryrun,
} => { } => {
let mut df = DuplicateFinder::new(); let mut df = DuplicateFinder::new();
@ -53,6 +54,7 @@ fn main() {
df.set_hash_type(hash_type); df.set_hash_type(hash_type);
df.set_recursive_search(!not_recursive.not_recursive); df.set_recursive_search(!not_recursive.not_recursive);
df.set_ignore_hard_links(!allow_hard_links.allow_hard_links); df.set_ignore_hard_links(!allow_hard_links.allow_hard_links);
df.set_dryrun(dryrun.dryrun);
df.find_duplicates(None, None); df.find_duplicates(None, None);

View file

@ -149,6 +149,7 @@ pub struct DuplicateFinder {
delete_method: DeleteMethod, delete_method: DeleteMethod,
hash_type: HashType, hash_type: HashType,
ignore_hard_links: bool, ignore_hard_links: bool,
dryrun: bool,
stopped_search: bool, stopped_search: bool,
} }
@ -170,6 +171,7 @@ impl DuplicateFinder {
stopped_search: false, stopped_search: false,
ignore_hard_links: true, ignore_hard_links: true,
hash_type: HashType::Blake3, hash_type: HashType::Blake3,
dryrun: false,
} }
} }
@ -243,6 +245,10 @@ impl DuplicateFinder {
self.ignore_hard_links = ignore_hard_links; self.ignore_hard_links = ignore_hard_links;
} }
pub fn set_dryrun(&mut self, dryrun: bool) {
self.dryrun = dryrun;
}
pub fn set_check_method(&mut self, check_method: CheckingMethod) { pub fn set_check_method(&mut self, check_method: CheckingMethod) {
self.check_method = check_method; self.check_method = check_method;
} }
@ -944,7 +950,7 @@ impl DuplicateFinder {
match self.check_method { match self.check_method {
CheckingMethod::Name => { CheckingMethod::Name => {
for vector in self.files_with_identical_names.values() { for vector in self.files_with_identical_names.values() {
let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages.warnings); let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
self.information.gained_space += tuple.0; self.information.gained_space += tuple.0;
self.information.number_of_removed_files += tuple.1; self.information.number_of_removed_files += tuple.1;
self.information.number_of_failed_to_remove_files += tuple.2; self.information.number_of_failed_to_remove_files += tuple.2;
@ -953,7 +959,7 @@ impl DuplicateFinder {
CheckingMethod::Hash | CheckingMethod::HashMB => { CheckingMethod::Hash | CheckingMethod::HashMB => {
for vector_vectors in self.files_with_identical_hashes.values() { for vector_vectors in self.files_with_identical_hashes.values() {
for vector in vector_vectors.iter() { for vector in vector_vectors.iter() {
let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages.warnings); let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
self.information.gained_space += tuple.0; self.information.gained_space += tuple.0;
self.information.number_of_removed_files += tuple.1; self.information.number_of_removed_files += tuple.1;
self.information.number_of_failed_to_remove_files += tuple.2; self.information.number_of_failed_to_remove_files += tuple.2;
@ -962,7 +968,7 @@ impl DuplicateFinder {
} }
CheckingMethod::Size => { CheckingMethod::Size => {
for vector in self.files_with_identical_size.values() { for vector in self.files_with_identical_size.values() {
let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages.warnings); let tuple: (u64, usize, usize) = delete_files(vector, &self.delete_method, &mut self.text_messages, self.dryrun);
self.information.gained_space += tuple.0; self.information.gained_space += tuple.0;
self.information.number_of_removed_files += tuple.1; self.information.number_of_removed_files += tuple.1;
self.information.number_of_failed_to_remove_files += tuple.2; self.information.number_of_failed_to_remove_files += tuple.2;
@ -1216,7 +1222,7 @@ impl PrintResults for DuplicateFinder {
/// Functions to remove slice(vector) of files with provided method /// Functions to remove slice(vector) of files with provided method
/// Returns size of removed elements, number of deleted and failed to delete files and modified warning list /// Returns size of removed elements, number of deleted and failed to delete files and modified warning list
fn delete_files(vector: &[FileEntry], delete_method: &DeleteMethod, warnings: &mut Vec<String>) -> (u64, usize, usize) { fn delete_files(vector: &[FileEntry], delete_method: &DeleteMethod, text_messages: &mut Messages, dryrun: bool) -> (u64, usize, usize) {
assert!(vector.len() > 1, "Vector length must be bigger than 1(This should be done in previous steps)."); assert!(vector.len() > 1, "Vector length must be bigger than 1(This should be done in previous steps).");
let mut gained_space: u64 = 0; let mut gained_space: u64 = 0;
let mut removed_files: usize = 0; let mut removed_files: usize = 0;
@ -1238,17 +1244,40 @@ fn delete_files(vector: &[FileEntry], delete_method: &DeleteMethod, warnings: &m
} else if removed_files + failed_to_remove_files >= n { } else if removed_files + failed_to_remove_files >= n {
break; break;
} }
let r = match delete_method { let r = match delete_method {
DeleteMethod::OneOldest | DeleteMethod::OneNewest | DeleteMethod::AllExceptOldest | DeleteMethod::AllExceptNewest => fs::remove_file(&file.path), DeleteMethod::OneOldest | DeleteMethod::OneNewest | DeleteMethod::AllExceptOldest | DeleteMethod::AllExceptNewest => {
DeleteMethod::HardLink => make_hard_link(&vector[q_index].path, &file.path), if dryrun {
DeleteMethod::None => Ok(()), Ok(Some(format!("Delete {}", file.path.display())))
} else {
fs::remove_file(&file.path).map(|_| None)
}
}
DeleteMethod::HardLink => {
let src = &vector[q_index].path;
if dryrun {
Ok(Some(format!("Replace file {} with hard link to {}", file.path.display(), src.display())))
} else {
make_hard_link(&src, &file.path).map(|_| None)
}
}
DeleteMethod::None => Ok(None),
}; };
if let Err(e) = r {
failed_to_remove_files += 1; match r {
warnings.push(format!("Failed to remove {} ({})", file.path.display(), e)); Err(e) => {
} else { failed_to_remove_files += 1;
removed_files += 1; text_messages.warnings.push(format!("Failed to remove {} ({})", file.path.display(), e));
gained_space += file.size; }
Ok(Some(msg)) => {
text_messages.messages.push(msg);
removed_files += 1;
gained_space += file.size;
}
Ok(None) => {
removed_files += 1;
gained_space += file.size;
}
} }
} }
(gained_space, removed_files, failed_to_remove_files) (gained_space, removed_files, failed_to_remove_files)