Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smaller fixes #795

Merged
merged 5 commits into from
Jul 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ jobs:
run: cargo build --release --features heif
env:
CARGO_INCREMENTAL: 0
RUSTFLAGS: "-C debuginfo=0 -D warnings"
if: ${{ matrix.type == 'release'}}

- name: Store MacOS CLI
Expand Down
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Version 5.0.1 - .08.2022r
- Fixed problem with removing ending slash with empty disk window path
- Added to CLI bad extensions mode
- Fixed default sorting method in CLI where finding biggest files
- Added tests to CI
- Show error message when all directories are set as reference folders

## Version 5.0.0 - 28.07.2022r
- GUI ported to use GTK 4 - [#466](https://github.com/qarmin/czkawka/pull/466)
- Use multithreading and improved algorithm to compare image hashes - [#762](https://github.com/qarmin/czkawka/pull/762)
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@

![Czkawka](https://user-images.githubusercontent.com/41945903/145280350-506f7e94-4db0-4de7-a68d-6e7c26bbd2bf.gif)

## Supported OS
Linux - Ubuntu 22.04+, Fedora 36+, Alpine Linux 3.16+, Debian 12+ and a lot of more
Windows - 7, 8.1, 10, 11
MacOS - 10.15+

If you are looking for older version that use GTK 3 and have support for more OS(like e.g. Ubuntu 20.04), look at [4.1.0](https://github.com/qarmin/czkawka/releases/tag/4.1.0) or older versions.

## How do I use it?
You can find the instructions on how to use Czkawka [**here**](instructions/Instruction.md).

Expand Down Expand Up @@ -140,6 +147,7 @@ You can help by creating:
If the change is bigger, then it's a good idea to open a new issue to discuss changes, but issues with label `PR welcome` are already checked and accepted.
- Documentation - There is an [instruction](instructions/Instruction.md) which you can improve.
- Translations - Instruction how to translate files is available [here](instructions/Translations.md)
- External contributions - App use big number of external libraries like [lofty](https://github.com/Serial-ATA/lofty-rs), [image-rs](https://github.com/image-rs/image) or [symphonia](https://github.com/pdeljanov/Symphonia) so improving this libraries will automatically improve Czkawka

You can also help by doing other things:
- Creating text articles - [LinuxUprising](https://www.linuxuprising.com/2021/03/find-and-remove-duplicate-files-similar.html) or [Ubunlog](https://ubunlog.com/en/czkawka-finds-and-removes-empty-and-broken-duplicate-files/)
Expand Down
39 changes: 32 additions & 7 deletions czkawka_cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub enum Commands {
file_to_save: FileToSave,
#[clap(flatten)]
not_recursive: NotRecursive,
#[clap(flatten)]
case_sensitive_name_comparison: CaseSensitiveNameComparison,
#[cfg(target_family = "unix")]
#[clap(flatten)]
exclude_other_filesystems: ExcludeOtherFilesystems,
Expand All @@ -60,7 +62,7 @@ pub enum Commands {
#[clap(flatten)]
exclude_other_filesystems: ExcludeOtherFilesystems,
},
#[clap(name = "big", about = "Finds big files", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka big -d /home/rafal/ /home/piszczal -e /home/rafal/Roman -n 25 -x VIDEO -f results.txt")]
#[clap(name = "big", about = "Finds big files", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka big -d /home/rafal/ /home/piszczal -e /home/rafal/Roman -n 25 -J -x VIDEO -f results.txt")]
BiggestFiles {
#[clap(flatten)]
directories: Directories,
Expand All @@ -78,6 +80,8 @@ pub enum Commands {
file_to_save: FileToSave,
#[clap(flatten)]
not_recursive: NotRecursive,
#[clap(short = 'J', long, help = "Finds the smallest files instead the biggest")]
smallest_mode: bool,
#[cfg(target_family = "unix")]
#[clap(flatten)]
exclude_other_filesystems: ExcludeOtherFilesystems,
Expand Down Expand Up @@ -130,7 +134,7 @@ pub enum Commands {
minimal_file_size: u64,
#[clap(short = 'i', long, parse(try_from_str = parse_maximal_file_size), default_value = "18446744073709551615", help = "Maximum size in bytes", long_help = "Maximum size of checked files in bytes, assigning lower value may speed up searching")]
maximal_file_size: u64,
#[clap(short, long, default_value = "High", parse(try_from_str = parse_similar_images_similarity), help = "Similairty level (Minimal, VerySmall, Small, Medium, High, VeryHigh)", long_help = "Methods to choose similarity level of images which will be considered as duplicated.")]
#[clap(short, long, default_value = "High", parse(try_from_str = parse_similar_images_similarity), help = "Similairty level (Minimal, VerySmall, Small, Medium, High, VeryHigh, Original)", long_help = "Methods to choose similarity level of images which will be considered as duplicated.")]
similarity_preset: SimilarityPreset,
#[clap(flatten)]
excluded_items: ExcludedItems,
Expand All @@ -143,7 +147,7 @@ pub enum Commands {
exclude_other_filesystems: ExcludeOtherFilesystems,
#[clap(short = 'g', long, default_value = "Gradient", parse(try_from_str = parse_similar_hash_algorithm), help = "Hash algorithm (allowed: Mean, Gradient, Blockhash, VertGradient, DoubleGradient)")]
hash_alg: HashAlg,
#[clap(short = 'z', long, default_value = "Lanczos3", parse(try_from_str = parse_similar_image_filter), help = "Hash algorithm (allowed: Lanczos3, Nearest, Triangle, Faussian, Catmullrom)")]
#[clap(short = 'z', long, default_value = "Nearest", parse(try_from_str = parse_similar_image_filter), help = "Hash algorithm (allowed: Lanczos3, Nearest, Triangle, Faussian, Catmullrom)")]
image_filter: FilterType,
#[clap(short = 'c', long, default_value = "16", parse(try_from_str = parse_image_hash_size), help = "Hash size (allowed: 8, 16, 32, 64)")]
hash_size: u8,
Expand Down Expand Up @@ -238,11 +242,26 @@ pub enum Commands {
#[clap(short = 't', long, parse(try_from_str = parse_tolerance), default_value = "10", help = "Video maximium difference (allowed values <0,20>)", long_help = "Maximum difference between video frames, bigger value means that videos can looks more and more different (allowed values <0,20>)")]
tolerance: i32,
},
#[clap(name = "tester", about = "Contains various test", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka tests -i")]
Tester {
#[clap(short = 'i', long = "test_image", help = "Test speed of hashing provided test.jpg image with different filters and methods.")]
test_image: bool,
#[clap(name = "ext", about = "Finds files with invalid extensions", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka broken -d /home/czokolada/ -f results.txt")]
BadExtensions {
#[clap(flatten)]
directories: Directories,
#[clap(flatten)]
excluded_directories: ExcludedDirectories,
#[clap(flatten)]
excluded_items: ExcludedItems,
#[clap(flatten)]
allowed_extensions: AllowedExtensions,
#[clap(flatten)]
file_to_save: FileToSave,
#[clap(flatten)]
not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
exclude_other_filesystems: ExcludeOtherFilesystems,
},
#[clap(name = "tester", about = "Small utility to test supported speed of ", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka tester")]
Tester {},
}

#[derive(Debug, clap::StructOpt)]
Expand Down Expand Up @@ -317,6 +336,12 @@ pub struct AllowHardLinks {
pub allow_hard_links: bool,
}

#[derive(Debug, clap::StructOpt)]
pub struct CaseSensitiveNameComparison {
#[clap(short = 'l', long, help = "Use case sensitive name comparison")]
pub case_sensitive_name_comparison: bool,
}

#[derive(Debug, clap::StructOpt)]
pub struct DryRun {
#[clap(long, help = "Do nothing and print the operation that would happen.")]
Expand Down
50 changes: 43 additions & 7 deletions czkawka_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ use std::process;
use clap::Parser;

use commands::Commands;
use czkawka_core::big_file::SearchMode;
#[allow(unused_imports)] // It is used in release for print_results().
use czkawka_core::common_traits::*;
use czkawka_core::similar_images::test_image_conversion_speed;
use czkawka_core::{
bad_extensions::BadExtensions,
big_file::{self, BigFile},
broken_files::{self, BrokenFiles},
duplicate::DuplicateFinder,
empty_files::{self, EmptyFiles},
empty_folder::EmptyFolder,
invalid_symlinks,
invalid_symlinks::InvalidSymlinks,
invalid_symlinks::{self, InvalidSymlinks},
same_music::SameMusic,
similar_images::{return_similarity_from_similarity_preset, SimilarImages},
similar_videos::SimilarVideos,
Expand Down Expand Up @@ -49,6 +50,7 @@ fn main() {
exclude_other_filesystems,
allow_hard_links,
dryrun,
case_sensitive_name_comparison,
} => {
let mut df = DuplicateFinder::new();

Expand All @@ -67,6 +69,7 @@ fn main() {
df.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
df.set_ignore_hard_links(!allow_hard_links.allow_hard_links);
df.set_dryrun(dryrun.dryrun);
df.set_case_sensitive_name_comparison(case_sensitive_name_comparison.case_sensitive_name_comparison);

df.find_duplicates(None, None);

Expand Down Expand Up @@ -123,6 +126,7 @@ fn main() {
#[cfg(target_family = "unix")]
exclude_other_filesystems,
delete_files,
smallest_mode,
} => {
let mut bf = BigFile::new();

Expand All @@ -137,6 +141,9 @@ fn main() {
if delete_files {
bf.set_delete_method(big_file::DeleteMethod::Delete);
}
if smallest_mode {
bf.set_search_mode(SearchMode::SmallestFiles);
}

bf.find_big_files(None, None);

Expand Down Expand Up @@ -425,12 +432,41 @@ fn main() {
vr.print_results();
vr.get_text_messages().print_messages();
}
Commands::Tester { test_image } => {
if test_image {
test_image_conversion_speed();
} else {
println!("At least one test should be choosen!");
Commands::BadExtensions {
directories,
excluded_directories,
excluded_items,
file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
allowed_extensions,
} => {
let mut be = BadExtensions::new();

be.set_included_directory(directories.directories);
be.set_excluded_directory(excluded_directories.excluded_directories);
be.set_excluded_items(excluded_items.excluded_items);
be.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
be.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
be.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);

if let Some(file_name) = file_to_save.file_name() {
if !be.save_results_to_file(file_name) {
be.get_text_messages().print_messages();
process::exit(1);
}
}

be.find_bad_extensions_files(None, None);

#[cfg(not(debug_assertions))] // This will show too much probably unnecessary data to debug, comment line only if needed
be.print_results();
be.get_text_messages().print_messages();
}
Commands::Tester {} => {
test_image_conversion_speed();
}
}
}
6 changes: 3 additions & 3 deletions czkawka_core/src/bad_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ impl BadExtensions {

self.information.number_of_files_with_bad_extension = self.bad_extensions_files.len();

Common::print_time(system_time, SystemTime::now(), "sort_images - reading data from files in parallel".to_string());
Common::print_time(system_time, SystemTime::now(), "bad extension finding".to_string());

// Clean unused data
self.files_to_check = Default::default();
Expand Down Expand Up @@ -539,7 +539,7 @@ impl SaveResults for BadExtensions {
if !self.bad_extensions_files.is_empty() {
writeln!(writer, "Found {} files with invalid extension.", self.information.number_of_files_with_bad_extension).unwrap();
for file_entry in self.bad_extensions_files.iter() {
writeln!(writer, "{}", file_entry.path.display()).unwrap();
writeln!(writer, "{} ----- {}", file_entry.path.display(), file_entry.proper_extensions).unwrap();
}
} else {
write!(writer, "Not found any files with invalid extension.").unwrap();
Expand All @@ -556,7 +556,7 @@ impl PrintResults for BadExtensions {
let start_time: SystemTime = SystemTime::now();
println!("Found {} files with invalid extension.\n", self.information.number_of_files_with_bad_extension);
for file_entry in self.bad_extensions_files.iter() {
println!("{}", file_entry.path.display());
println!("{} ----- {}", file_entry.path.display(), file_entry.proper_extensions);
}

Common::print_time(start_time, SystemTime::now(), "print_entries".to_string());
Expand Down
19 changes: 13 additions & 6 deletions czkawka_core/src/big_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,12 @@ impl SaveResults for BigFile {
}

if self.information.number_of_real_files != 0 {
write!(writer, "{} the biggest files.\n\n", self.information.number_of_real_files).unwrap();

for (size, file_entry) in self.big_files.iter().rev() {
if self.search_mode == SearchMode::BiggestFiles {
write!(writer, "{} the biggest files.\n\n", self.information.number_of_real_files).unwrap();
} else {
write!(writer, "{} the smallest files.\n\n", self.information.number_of_real_files).unwrap();
}
for (size, file_entry) in self.big_files.iter() {
writeln!(writer, "{} ({}) - {}", size.file_size(options::BINARY).unwrap(), size, file_entry.path.display()).unwrap();
}
} else {
Expand All @@ -480,9 +483,13 @@ impl SaveResults for BigFile {
impl PrintResults for BigFile {
fn print_results(&self) {
let start_time: SystemTime = SystemTime::now();
for (size, file_entry) in self.big_files.iter().rev() {
// TODO Align all to same width
println!("{} ({} bytes) - {}", size.file_size(options::BINARY).unwrap(), size, file_entry.path.display());
if self.search_mode == SearchMode::BiggestFiles {
println!("{} the biggest files.\n\n", self.information.number_of_real_files);
} else {
println!("{} the smallest files.\n\n", self.information.number_of_real_files);
}
for (size, file_entry) in self.big_files.iter() {
println!("{} ({}) - {}", size.file_size(options::BINARY).unwrap(), size, file_entry.path.display());
}
Common::print_time(start_time, SystemTime::now(), "print_entries".to_string());
}
Expand Down
4 changes: 3 additions & 1 deletion czkawka_core/src/similar_images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::flc;
use crate::localizer_core::generate_translation_hashmap;

pub const SIMILAR_VALUES: [[u32; 6]; 4] = [
[0, 2, 5, 7, 14, 20], // 8
[1, 2, 5, 7, 14, 20], // 8
[2, 5, 15, 30, 40, 40], // 16
[4, 10, 20, 40, 40, 40], // 32
[6, 20, 40, 40, 40, 40], // 64
Expand All @@ -59,6 +59,7 @@ pub struct FileEntry {
/// Used by CLI tool when we cannot use directly values
#[derive(Clone, Debug)]
pub enum SimilarityPreset {
Original,
VeryHigh,
High,
Medium,
Expand Down Expand Up @@ -1283,6 +1284,7 @@ pub fn return_similarity_from_similarity_preset(similarity_preset: &SimilarityPr
_ => panic!(),
};
match similarity_preset {
SimilarityPreset::Original => 0,
SimilarityPreset::VeryHigh => SIMILAR_VALUES[index_preset][0],
SimilarityPreset::High => SIMILAR_VALUES[index_preset][1],
SimilarityPreset::Medium => SIMILAR_VALUES[index_preset][2],
Expand Down
1 change: 1 addition & 0 deletions czkawka_gui/i18n/en/czkawka_gui.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ invalid_symlink_infinite_recursion = Infinite recursion
invalid_symlink_non_existent_destination = Non-existent destination file

# Other
selected_all_reference_folders = Cannot start search, when all directories are set as reference folders
searching_for_data = Searching data, it may take a while, please wait...
text_view_messages = MESSAGES
text_view_warnings = WARNINGS
Expand Down
7 changes: 7 additions & 0 deletions czkawka_gui/src/connect_things/connect_button_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ pub fn connect_button_search(
let check_button_settings_save_also_json = gui_data.settings.check_button_settings_save_also_json.clone();

buttons_search_clone.connect_clicked(move |_| {
// Check if user selected all referenced folders
let list_store_included_directories = get_list_store(&tree_view_included_directories);
if check_if_list_store_column_have_all_same_values(&list_store_included_directories, ColumnsIncludedDirectory::ReferenceButton as i32, true) {
entry_info.set_text(&flg!("selected_all_reference_folders"));
return;
}

let included_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(&tree_view_included_directories, ColumnsIncludedDirectory::Path as i32, None));
let excluded_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(&tree_view_excluded_directories, ColumnsExcludedDirectory::Path as i32, None));
let reference_directories = get_path_buf_from_vector_of_strings(get_string_from_list_store(
Expand Down
10 changes: 10 additions & 0 deletions czkawka_gui/src/connect_things/connect_selection_of_directories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ fn add_manually_directories(window_main: &Window, tree_view: &TreeView, excluded
dialog.close();
});
}

fn remove_ending_slashes(original_string: &mut String) {
let mut windows_disk_path: bool = false;
let mut chars = original_string.chars();
Expand All @@ -202,6 +203,7 @@ fn remove_ending_slashes(original_string: &mut String) {
original_string.pop();
}
}

#[test]
pub fn test_remove_ending_slashes() {
let mut original = "/home/rafal".to_string();
Expand Down Expand Up @@ -248,6 +250,14 @@ pub fn test_remove_ending_slashes() {
remove_ending_slashes(&mut original);
assert_eq!(&original, "C:/");

let mut original = "C:/roman/function/".to_string();
remove_ending_slashes(&mut original);
assert_eq!(&original, "C:/roman/function");

let mut original = "C:/staszek/without".to_string();
remove_ending_slashes(&mut original);
assert_eq!(&original, "C:/staszek/without");

let mut original = "C:\\\\\\\\\\".to_string();
remove_ending_slashes(&mut original);
assert_eq!(&original, "C:\\");
Expand Down
Loading