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:
parent
ed7b197100
commit
1d904a858e
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue