2020-09-12 08:32:17 +12:00
use czkawka_core ::duplicate ::Info ;
2020-09-02 05:34:39 +12:00
use czkawka_core ::{ duplicate , empty_folder } ;
2020-08-27 06:49:43 +12:00
use std ::{ env , process } ;
2020-08-26 21:17:16 +12:00
fn main ( ) {
2020-08-27 06:49:43 +12:00
// Parse argument
2020-08-30 05:11:55 +12:00
let mut all_arguments : Vec < String > = env ::args ( ) . collect ( ) ;
let mut commands_arguments : Vec < String > = Vec ::new ( ) ;
2020-09-12 01:52:06 +12:00
// println!("{:?}", all_arguments);
2020-09-02 05:34:39 +12:00
2020-08-30 05:11:55 +12:00
all_arguments . remove ( 0 ) ; // Removing program name from arguments
2020-08-27 06:49:43 +12:00
2020-08-31 00:00:22 +12:00
// No arguments, so we print help to allow user to learn more about program
if all_arguments . is_empty ( ) {
print_help ( ) ;
process ::exit ( 0 ) ;
}
// Assigning commands with arguments
let mut arguments : Vec < ArgumentsPair > = Vec ::new ( ) ;
2020-09-01 02:15:56 +12:00
for argument in all_arguments {
if argument . starts_with ( " -- " ) {
commands_arguments . push ( argument ) ;
} else if argument . starts_with ( '-' ) {
2020-09-12 01:52:06 +12:00
let a : ArgumentsPair = ArgumentsPair { command : argument , argument : Option ::None } ;
2020-09-01 02:15:56 +12:00
arguments . push ( a ) ;
} else {
if arguments . is_empty ( ) {
println! ( " FATAL ERROR: Trying to use {} without any arguments(like -i -e -delete) " , argument ) ;
2020-08-31 00:00:22 +12:00
process ::exit ( 1 ) ;
}
2020-09-01 02:15:56 +12:00
if arguments [ arguments . len ( ) - 1 ] . argument ! = Option ::None {
println! ( " FATAL ERROR: Trying set second parameter {} , but only one is supported " , argument ) ; // This may be changed in future to support 2 or more attributes with space
process ::exit ( 1 ) ;
}
let last_element = arguments . len ( ) - 1 ;
arguments [ last_element ] . argument = Option ::from ( argument ) ;
2020-08-30 05:11:55 +12:00
}
}
2020-09-12 01:52:06 +12:00
// for a in &arguments {
// println!(
// "Argument number {} - {}",
// a.command,
// match &a.argument {
// Some(t) => t.clone(),
// None => "MISSING_ARGUMENT".to_string(),
// }
// );
// }
2020-08-31 00:00:22 +12:00
2020-08-30 05:11:55 +12:00
if commands_arguments . is_empty ( ) {
2020-08-31 00:00:22 +12:00
println! { " FATAL ERROR: Missing type of app which you want to run, please read help for more info. " } ;
2020-08-30 05:11:55 +12:00
process ::exit ( 0 ) ;
}
match commands_arguments [ 0 ] . as_ref ( ) {
2020-08-31 00:00:22 +12:00
" --d " = > {
let mut df = duplicate ::DuplicateFinder ::new ( ) ;
2020-08-31 03:18:04 +12:00
let mut check_method : duplicate ::CheckingMethod = duplicate ::CheckingMethod ::HASH ;
2020-08-30 05:11:55 +12:00
2020-08-31 00:00:22 +12:00
if ArgumentsPair ::has_command ( & arguments , " -i " ) {
2020-09-16 05:17:13 +12:00
df . set_include_directory ( ArgumentsPair ::get_argument ( & arguments , " -i " , false ) ) ;
2020-08-31 00:00:22 +12:00
} else {
println! ( " FATAL ERROR: Parameter -i with set of included files is required. " ) ;
2020-08-27 06:49:43 +12:00
process ::exit ( 1 ) ;
}
2020-08-31 00:00:22 +12:00
if ArgumentsPair ::has_command ( & arguments , " -e " ) {
2020-09-01 02:15:56 +12:00
df . set_exclude_directory ( ArgumentsPair ::get_argument ( & arguments , " -e " , false ) ) ;
2020-08-30 02:12:20 +12:00
}
2020-08-31 00:00:22 +12:00
if ArgumentsPair ::has_command ( & arguments , " -s " ) {
2020-09-01 02:15:56 +12:00
let min_size = match ArgumentsPair ::get_argument ( & arguments , " -s " , false ) . parse ::< u64 > ( ) {
2020-09-12 01:52:06 +12:00
Ok ( t ) = > {
if t = = 0 {
println! ( " ERROR: Minimum file size must be at least 1 byte. " ) ;
1
} else {
t
}
}
2020-08-30 02:12:20 +12:00
Err ( _ ) = > {
2020-09-12 01:52:06 +12:00
println! ( " FATAL ERROR: \" {} \" is not valid file size(allowed range <1,u64::max>) " , ArgumentsPair ::get_argument ( & arguments , " -s " , false ) ) ;
2020-08-30 02:12:20 +12:00
process ::exit ( 1 ) ;
}
} ;
df . set_min_file_size ( min_size ) ;
}
2020-08-31 00:00:22 +12:00
if ArgumentsPair ::has_command ( & arguments , " -x " ) {
2020-09-01 02:15:56 +12:00
df . set_allowed_extensions ( ArgumentsPair ::get_argument ( & arguments , " -x " , false ) ) ;
2020-08-30 02:12:20 +12:00
}
2020-08-31 00:00:22 +12:00
if ArgumentsPair ::has_command ( & arguments , " -k " ) {
2020-09-01 02:15:56 +12:00
df . set_excluded_items ( ArgumentsPair ::get_argument ( & arguments , " -k " , false ) ) ;
2020-09-16 05:17:13 +12:00
} else {
df . set_excluded_items ( " DEFAULT " . to_string ( ) ) ;
2020-08-31 00:00:22 +12:00
}
2020-09-16 05:17:13 +12:00
2020-09-12 23:25:23 +12:00
if ArgumentsPair ::has_command ( & arguments , " -o " ) {
df . set_recursive_search ( false ) ;
}
2020-08-31 00:00:22 +12:00
if ArgumentsPair ::has_command ( & arguments , " -l " ) {
2020-09-01 02:15:56 +12:00
let argument_name = ArgumentsPair ::get_argument ( & arguments , " -l " , false ) . to_lowercase ( ) ;
if argument_name = = " size " {
2020-08-31 00:00:22 +12:00
check_method = duplicate ::CheckingMethod ::SIZE ;
2020-09-01 02:15:56 +12:00
} else if argument_name = = " hash " {
2020-08-31 00:00:22 +12:00
check_method = duplicate ::CheckingMethod ::HASH ;
} else {
println! ( " -l can only have values hash or size " ) ;
process ::exit ( 1 ) ;
}
2020-08-30 02:12:20 +12:00
}
2020-09-01 02:15:56 +12:00
let mut delete_method : duplicate ::DeleteMethod = duplicate ::DeleteMethod ::None ;
if ArgumentsPair ::has_command ( & arguments , " -delete " ) {
delete_method = duplicate ::DeleteMethod ::AllExceptOldest ;
let argument_name = ArgumentsPair ::get_argument ( & arguments , " -delete " , true ) . to_lowercase ( ) ;
if argument_name = = " aen " {
delete_method = duplicate ::DeleteMethod ::AllExceptNewest ;
} else if argument_name = = " aeo " {
delete_method = duplicate ::DeleteMethod ::AllExceptOldest ;
} else if argument_name = = " on " {
delete_method = duplicate ::DeleteMethod ::OneNewest ;
} else if argument_name = = " oo " {
delete_method = duplicate ::DeleteMethod ::OneOldest ;
} else if argument_name = = " " {
// Nothing to do choosing default one
} else {
println! (
" Invalid argument {} for command -delete, available arguments - aen(All except newest one), aeo(All except oldest one), on(Only one newest), oo(Only one oldest) " ,
argument_name
) ;
process ::exit ( 1 ) ;
}
}
df . find_duplicates ( & check_method , & delete_method ) ;
2020-09-12 01:52:06 +12:00
2020-09-16 05:17:13 +12:00
if ArgumentsPair ::has_command ( & arguments , " -f " ) {
df . save_results_to_file ( & ArgumentsPair ::get_argument ( & arguments , " -f " , false ) ) ;
}
2020-09-12 08:32:17 +12:00
print_infos ( df . get_infos ( ) ) ;
2020-09-01 05:37:30 +12:00
}
2020-08-31 00:00:22 +12:00
" --h " | " --help " = > {
2020-08-30 05:11:55 +12:00
print_help ( ) ;
2020-09-01 05:37:30 +12:00
}
" --e " = > {
let mut ef = empty_folder ::EmptyFolder ::new ( ) ;
let mut delete_folders : bool = false ;
if ArgumentsPair ::has_command ( & arguments , " -i " ) {
ef . set_include_directory ( ArgumentsPair ::get_argument ( & arguments , " -i " , false ) ) ;
} else {
println! ( " FATAL ERROR: Parameter -i with set of included files is required. " ) ;
process ::exit ( 1 ) ;
}
if ArgumentsPair ::has_command ( & arguments , " -e " ) {
ef . set_exclude_directory ( ArgumentsPair ::get_argument ( & arguments , " -e " , false ) ) ;
}
2020-09-01 02:26:14 +12:00
2020-09-01 05:37:30 +12:00
if ArgumentsPair ::has_command ( & arguments , " -delete " ) {
delete_folders = true ;
}
ef . find_empty_folders ( delete_folders ) ;
}
2020-08-31 00:00:22 +12:00
argum = > {
println! ( " FATAL ERROR: \" {} \" argument is not supported, check help for more info. " , argum ) ;
process ::exit ( 1 ) ;
}
2020-08-27 06:49:43 +12:00
} ;
}
fn print_help ( ) {
2020-08-31 03:18:04 +12:00
println! (
2020-09-01 02:15:56 +12:00
r ###"
Usage of Czkawka :
## Main arguments :
- - h / - - help - prints help , also works without any arguments
Usage example :
czkawka - - help
czkawka
2020-09-16 05:17:13 +12:00
- - d < - i directory_to_search > [ - e exclude_directories = " " ] [ - k excluded_items = " DEFAULT " ] [ - s min_size = 1024 ] [ - x allowed_extension = " " ] [ - l type_of_search = " hash " ] [ - o ] [ - f file_to_save = " results.txt " ] [ - delete = " aeo " ] - search for duplicates files
2020-09-01 02:15:56 +12:00
- i directory_to_search - list of directories which should will be searched like / home / rafal
- e exclude_directories - list of directories which will be excluded from search .
2020-09-12 08:32:17 +12:00
- k excluded_items - list of excluded items which contains * wildcard ( may be slow )
2020-09-16 05:17:13 +12:00
- o - this options prevents from recursive check of folders
- f file_to_save - saves results to file
2020-09-01 02:15:56 +12:00
- s min_size - minimum size of checked files in bytes , assigning bigger value may speed up searching .
2020-09-12 08:32:17 +12:00
- x allowed_extension - list of checked extension , e . g . " jpg,mp4 " will allow to check " book.jpg " and " car.mp4 " but not roman . png . There are also helpful macros which allow to easy use a typcal extension like IMAGE ( " jpg,kra,gif,png,bmp,tiff,webp,hdr,svg " ) or TEXT ( " txt,doc,docx,odt,rtf " )
2020-09-01 02:26:14 +12:00
- l type_of_search - allows to use fastest which takes into account only size , and more accurate which check if file contnet is same ( hashes ) .
- delete - delete found files , by default remove all except the most oldest one , it can take arguments : aen ( All except newest one ) , aeo ( All except oldest one ) , on ( Only one newest ) , oo ( Only one oldest )
2020-09-01 02:15:56 +12:00
Usage example :
2020-09-01 02:26:14 +12:00
czkawka - - d - i " /home/rafal/,/home/szczekacz " - e " /home/rafal/Pulpit,/home/rafal/Obrazy " - s 25 - x " 7z,rar,IMAGE " - l " size " - delete
2020-09-12 23:25:23 +12:00
czkawka - - d - i " /etc/,/mnt/Miecz " - s 1000 - x " VIDEO " - l " hash " - o
2020-09-12 08:32:17 +12:00
czkawka - - d - i " /var/ " - k " /var/l*b/,/var/lo*,*tmp "
2020-09-01 02:26:14 +12:00
czkawka - - d - i " /etc/ " - delete " aeo "
2020-09-04 03:33:43 +12:00
2020-09-01 02:26:14 +12:00
- - e < - i directory_to_search > [ - e exclude_directories = " " ] [ - delete ] - option to find and delete empty folders
- i directory_to_search - list of directories which should will be searched like / home / rafal
- e exclude_directories - list of directories which will be excluded from search .
- delete - delete found empty folders
2020-09-02 03:10:54 +12:00
czkawka - - e - i " /home/rafal/rr, /home/gateway " - e " /home/rafal/rr/2 " - delete
2020-09-01 02:15:56 +12:00
" ###
2020-08-31 03:18:04 +12:00
) ;
2020-08-26 21:17:16 +12:00
}
2020-09-12 08:32:17 +12:00
/// Printing infos about warnings, messages and errors
fn print_infos ( infos : & Info ) {
if ! infos . messages . is_empty ( ) {
println! ( " -------------------------------MESSAGES-------------------------------- " ) ;
}
for i in & infos . messages {
println! ( " {} " , i ) ;
}
if ! infos . messages . is_empty ( ) {
println! ( " ---------------------------END OF MESSAGES----------------------------- " ) ;
}
if ! infos . warnings . is_empty ( ) {
println! ( " -------------------------------WARNINGS-------------------------------- " ) ;
}
for i in & infos . warnings {
println! ( " {} " , i ) ;
}
if ! infos . warnings . is_empty ( ) {
println! ( " ---------------------------END OF WARNINGS----------------------------- " ) ;
}
if ! infos . errors . is_empty ( ) {
println! ( " --------------------------------ERRORS--------------------------------- " ) ;
}
for i in & infos . errors {
println! ( " {} " , i ) ;
}
if ! infos . errors . is_empty ( ) {
println! ( " ----------------------------END OF ERRORS------------------------------ " ) ;
}
}
2020-08-31 00:00:22 +12:00
struct ArgumentsPair {
command : String ,
2020-09-01 02:15:56 +12:00
argument : Option < String > ,
2020-08-31 00:00:22 +12:00
}
impl ArgumentsPair {
pub fn has_command ( ar : & [ ArgumentsPair ] , command : & str ) -> bool {
for a in ar {
if a . command = = command {
return true ;
}
}
false
}
2020-09-01 02:15:56 +12:00
pub fn get_argument ( ar : & [ ArgumentsPair ] , command : & str , can_be_empty : bool ) -> String {
2020-08-31 00:00:22 +12:00
for a in ar {
if a . command = = command {
2020-09-01 02:15:56 +12:00
if ! can_be_empty & & a . argument = = Option ::None {
println! ( " FATAL ERROR: {} commands should have argument passed " , command ) ;
process ::exit ( 1 ) ;
}
return match & a . argument {
Some ( t ) = > t . clone ( ) ,
None = > " " . to_string ( ) ,
} ;
2020-08-31 00:00:22 +12:00
}
}
2020-09-12 01:52:06 +12:00
panic! ( " INTERNAL ERROR: Get argument should always return value " ) ;
2020-08-31 00:00:22 +12:00
}
}