2020-09-23 22:17:19 +12:00
use czkawka_core ::* ;
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-09-23 22:17:19 +12:00
let all_arguments : Vec < String > = env ::args ( ) . skip ( 1 ) . collect ( ) ; // Not need to check program name
2020-08-30 05:11:55 +12:00
let mut commands_arguments : Vec < String > = Vec ::new ( ) ;
2020-09-23 22:17:19 +12:00
#[ cfg(debug_assertions) ]
println! ( " {:?} " , all_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-18 17:32:37 +12:00
#[ cfg(debug_assertions) ]
for a in & arguments {
println! (
" Argument number {} - {} " ,
a . command ,
match & a . argument {
Some ( t ) = > t . clone ( ) ,
None = > " NO_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-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-09-17 22:07:58 +12:00
df . set_check_method ( duplicate ::CheckingMethod ::HASH ) ; // Default
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-09-17 22:07:58 +12:00
df . set_check_method ( duplicate ::CheckingMethod ::SIZE ) ;
2020-09-01 02:15:56 +12:00
} else if argument_name = = " hash " {
2020-09-17 22:07:58 +12:00
df . set_check_method ( duplicate ::CheckingMethod ::HASH ) ;
2020-08-31 00:00:22 +12:00
} 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
2020-09-17 22:07:58 +12:00
df . set_delete_method ( duplicate ::DeleteMethod ::None ) ;
2020-09-01 02:15:56 +12:00
if ArgumentsPair ::has_command ( & arguments , " -delete " ) {
let argument_name = ArgumentsPair ::get_argument ( & arguments , " -delete " , true ) . to_lowercase ( ) ;
if argument_name = = " aen " {
2020-09-17 22:07:58 +12:00
df . set_delete_method ( duplicate ::DeleteMethod ::AllExceptNewest ) ;
2020-09-01 02:15:56 +12:00
} else if argument_name = = " aeo " {
2020-09-17 22:07:58 +12:00
df . set_delete_method ( duplicate ::DeleteMethod ::AllExceptOldest ) ;
2020-09-01 02:15:56 +12:00
} else if argument_name = = " on " {
2020-09-17 22:07:58 +12:00
df . set_delete_method ( duplicate ::DeleteMethod ::OneNewest ) ;
2020-09-01 02:15:56 +12:00
} else if argument_name = = " oo " {
2020-09-17 22:07:58 +12:00
df . set_delete_method ( duplicate ::DeleteMethod ::OneOldest ) ;
2020-09-01 02:15:56 +12:00
} else if argument_name = = " " {
2020-09-17 22:07:58 +12:00
// Default
df . set_delete_method ( duplicate ::DeleteMethod ::AllExceptOldest ) ;
2020-09-01 02:15:56 +12:00
} 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 ) ;
}
}
2020-09-17 22:07:58 +12:00
df . find_duplicates ( ) ;
2020-09-12 01:52:06 +12:00
2020-09-18 20:23:49 +12:00
#[ allow(clippy::collapsible_if) ]
2020-09-16 05:17:13 +12:00
if ArgumentsPair ::has_command ( & arguments , " -f " ) {
2020-09-18 20:23:49 +12:00
if ! df . save_results_to_file ( & ArgumentsPair ::get_argument ( & arguments , " -f " , false ) ) {
df . get_text_messages ( ) . print_messages ( ) ;
process ::exit ( 1 ) ;
}
2020-09-16 05:17:13 +12:00
}
2020-09-19 18:20:49 +12:00
#[ cfg(not(debug_assertions)) ] // This will show too much probably unnecessary data to debug, comment line only if needed
df . print_duplicated_entries ( ) ;
2020-09-18 20:23:49 +12:00
df . get_text_messages ( ) . print_messages ( ) ;
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 ( ) ;
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 ) ;
}
2020-09-18 21:11:08 +12:00
if ArgumentsPair ::has_command ( & arguments , " -delete " ) {
ef . set_delete_folder ( true ) ;
}
ef . find_empty_folders ( ) ;
2020-09-18 20:23:49 +12:00
#[ allow(clippy::collapsible_if) ]
if ArgumentsPair ::has_command ( & arguments , " -f " ) {
if ! ef . save_results_to_file ( & ArgumentsPair ::get_argument ( & arguments , " -f " , false ) ) {
ef . get_text_messages ( ) . print_messages ( ) ;
process ::exit ( 1 ) ;
}
2020-09-01 05:37:30 +12:00
}
2020-09-01 02:26:14 +12:00
2020-09-19 18:20:49 +12:00
#[ cfg(not(debug_assertions)) ] // This will show too much probably unnecessary data to debug, comment line only if needed
2020-09-18 17:32:37 +12:00
ef . print_empty_folders ( ) ;
2020-09-01 05:37:30 +12:00
}
2020-09-23 22:17:19 +12:00
" --version " | " v " = > {
println! ( " Czkawka CLI {} " , CZKAWKA_VERSION ) ;
process ::exit ( 0 ) ;
}
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
2020-09-23 22:17:19 +12:00
Usage example :
czkawka - - help
czkawka
2020-09-01 02:15:56 +12:00
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-23 22:17:19 +12:00
Usage example :
czkawka - - d - i " /home/rafal/,/home/szczekacz " - e " /home/rafal/Pulpit,/home/rafal/Obrazy " - s 25 - x " 7z,rar,IMAGE " - l " size " - delete
czkawka - - d - i " /etc/,/mnt/Miecz " - s 1000 - x " VIDEO " - l " hash " - o
czkawka - - d - i " /var/ " - k " /var/l*b/,/var/lo*,*tmp "
czkawka - - d - i " /etc/ " - delete " aeo "
2020-09-04 03:33:43 +12:00
2020-09-18 17:32:37 +12:00
- - e < - i directory_to_search > [ - e exclude_directories = " " ] [ - o ] [ - f file_to_save ] [ - delete ] - option to find and delete empty folders
2020-09-01 02:26:14 +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-18 17:32:37 +12:00
- f file_to_save - saves results to file
2020-09-01 02:26:14 +12:00
- delete - delete found empty folders
2020-09-23 22:17:19 +12:00
Usage example :
czkawka - - e - i " /home/rafal/rr, /home/gateway " - e " /home/rafal/rr/2 " - delete
- - version / - - v - prints program name and version
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-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
}
}