2020-08-27 06:49:43 +12:00
use std ::{ env , process } ;
2020-09-01 05:37:30 +12:00
mod common ;
2020-08-27 06:49:43 +12:00
mod duplicate ;
2020-09-01 05:37:30 +12:00
mod empty_folder ;
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 ( ) ;
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 ( '-' ) {
let a : ArgumentsPair = ArgumentsPair {
command : argument ,
argument : Option ::None ,
} ;
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-08-31 00:00:22 +12:00
for a in & arguments {
2020-09-01 02:15:56 +12:00
println! (
" Argument number {} - {} " ,
a . command ,
match & a . argument {
Some ( t ) = > t . clone ( ) ,
None = > " MISSING_ARGUMENT " . to_string ( ) ,
}
) ;
2020-08-27 06:49:43 +12:00
}
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-01 02:15:56 +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-08-30 02:12:20 +12:00
Ok ( t ) = > t ,
Err ( _ ) = > {
2020-09-01 02:15:56 +12:00
println! (
" FATAL ERROR: \" {} \" is not valid file size(allowed range <0,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-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-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-01 02:26:14 +12:00
- - d < - i directory_to_search > [ - e exclude_directories = " " ] [ - s min_size = 1024 ] [ - x allowed_extension = " " ] [ - l type_of_search = " hash " ] [ - 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 .
- s min_size - minimum size of checked files in bytes , assigning bigger value may speed up searching .
- 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
czkawka - - d - i " /etc/,/mnt/Miecz " - s 1000 - x " VIDEO " - l " hash "
czkawka - - d - i " /etc/ " - delete " aeo "
- - 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-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
}
}
panic! ( " FATAL ERROR: Get argument should always return value " ) ;
}
}