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,
#[structopt(flatten)]
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")]
EmptyFolders {
@ -235,6 +237,12 @@ pub struct AllowHardLinks {
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 {
pub fn file_name(&self) -> Option<&str> {
if let Some(file_name) = &self.file_to_save {

View File

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

View File

@ -149,6 +149,7 @@ pub struct DuplicateFinder {
delete_method: DeleteMethod,
hash_type: HashType,
ignore_hard_links: bool,
dryrun: bool,
stopped_search: bool,
}
@ -170,6 +171,7 @@ impl DuplicateFinder {
stopped_search: false,
ignore_hard_links: true,
hash_type: HashType::Blake3,
dryrun: false,
}
}
@ -243,6 +245,10 @@ impl DuplicateFinder {
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) {
self.check_method = check_method;
}
@ -944,7 +950,7 @@ impl DuplicateFinder {
match self.check_method {
CheckingMethod::Name => {
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.number_of_removed_files += tuple.1;
self.information.number_of_failed_to_remove_files += tuple.2;
@ -953,7 +959,7 @@ impl DuplicateFinder {
CheckingMethod::Hash | CheckingMethod::HashMB => {
for vector_vectors in self.files_with_identical_hashes.values() {
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.number_of_removed_files += tuple.1;
self.information.number_of_failed_to_remove_files += tuple.2;
@ -962,7 +968,7 @@ impl DuplicateFinder {
}
CheckingMethod::Size => {
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.number_of_removed_files += tuple.1;
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
/// 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).");
let mut gained_space: u64 = 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 {
break;
}
let r = match delete_method {
DeleteMethod::OneOldest | DeleteMethod::OneNewest | DeleteMethod::AllExceptOldest | DeleteMethod::AllExceptNewest => fs::remove_file(&file.path),
DeleteMethod::HardLink => make_hard_link(&vector[q_index].path, &file.path),
DeleteMethod::None => Ok(()),
DeleteMethod::OneOldest | DeleteMethod::OneNewest | DeleteMethod::AllExceptOldest | DeleteMethod::AllExceptNewest => {
if dryrun {
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;
warnings.push(format!("Failed to remove {} ({})", file.path.display(), e));
} else {
removed_files += 1;
gained_space += file.size;
match r {
Err(e) => {
failed_to_remove_files += 1;
text_messages.warnings.push(format!("Failed to remove {} ({})", file.path.display(), e));
}
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)