2024-03-26 13:55:15 +00:00
use anyhow ::{ Context , Result } ;
2024-03-13 19:27:25 +00:00
use clap ::Parser ;
use colored ::Colorize ;
2024-03-22 21:13:30 +00:00
use std ::{ fs , path , process } ;
2024-04-02 16:37:03 +01:00
use std ::{ io , io ::Write } ;
2024-03-13 19:27:25 +00:00
#[ derive(Parser, Debug) ]
2024-03-13 20:23:48 +00:00
#[ command(version, about, long_about = None, author) ]
2024-03-13 20:20:31 +00:00
/// A simple, featureful and blazingly fast memory-safe alternative to 'rm' written in Rust.
2024-03-13 19:27:25 +00:00
struct Args {
2024-03-13 20:20:31 +00:00
/// Don't try to preserve '~' or '/'
2024-03-13 20:03:48 +00:00
#[ arg(long) ]
2024-03-13 20:05:55 +00:00
no_preserve : bool ,
2024-03-13 20:03:48 +00:00
2024-04-02 16:37:03 +01:00
/// Ask once before removing all
#[ arg(short, long) ]
ask_once : bool ,
/// Ask before removing each target
#[ arg(short = 'x', long, conflicts_with = " ask_once " ) ]
ask_each : bool ,
2024-03-13 19:27:25 +00:00
#[ arg(trailing_var_arg = true, allow_hyphen_values = false) ]
targets : Vec < String > ,
}
2024-04-02 16:37:03 +01:00
fn confirm_parse ( ) {
io ::stdout ( ) . flush ( ) . unwrap ( ) ;
let mut confirm = String ::new ( ) ;
io ::stdin ( ) . read_line ( & mut confirm ) . expect ( " failed to read input " ) ;
if confirm ! = " y \n " {
process ::exit ( 0 ) ;
}
}
fn confirm_once ( ) {
print! ( " Are you sure you want to delete the specified targets? [y/N]: " ) ;
confirm_parse ( ) ;
}
fn confirm_each ( target : & String ) {
2024-04-02 16:45:05 +01:00
print! ( " Are you sure you want to delete {} ? [y/N]: " , target . bold ( ) ) ;
2024-04-02 16:37:03 +01:00
confirm_parse ( ) ;
}
2024-03-26 13:54:15 +00:00
fn vaporise ( ) -> Result < ( ) > {
2024-03-13 19:27:25 +00:00
let args = Args ::parse ( ) ;
2024-03-21 22:06:20 +00:00
if args . targets . is_empty ( ) {
2024-03-26 13:54:15 +00:00
println! ( " {} : no arguments passed " , " error " . red ( ) . bold ( ) ) ;
2024-03-22 21:13:30 +00:00
println! (
2024-03-26 13:54:15 +00:00
" {}: try 'vpr -h' for more information " ,
" note " . cyan ( ) . bold ( )
2024-03-22 21:13:30 +00:00
) ;
2024-03-13 19:27:25 +00:00
process ::exit ( 0 ) ;
}
2024-03-13 20:03:48 +00:00
2024-04-02 16:37:03 +01:00
if args . ask_once {
confirm_once ( ) ;
}
2024-03-13 19:27:25 +00:00
for target in args . targets . iter ( ) {
2024-03-21 22:06:20 +00:00
if ! args . no_preserve & & ( target = = " / " | | target = = " ~ " ) {
2024-03-26 13:54:15 +00:00
println! ( " {} : you're trying to delete an important directory ( {} )! specify ' {} ' if you really want to do this " , " error " . red ( ) . bold ( ) , " --no-preserve " . yellow ( ) , target ) ;
2024-03-21 22:06:20 +00:00
process ::exit ( 0 ) ;
2024-03-13 20:03:48 +00:00
}
2024-03-22 21:13:30 +00:00
2024-04-02 16:37:03 +01:00
if args . ask_each {
confirm_each ( target ) ;
}
2024-03-13 19:27:25 +00:00
if path ::Path ::new ( target ) . exists ( ) {
if fs ::metadata ( target ) . unwrap ( ) . is_dir ( ) {
2024-03-26 13:56:11 +00:00
fs ::remove_dir_all ( target )
2024-03-26 13:54:15 +00:00
. with_context ( | | format! ( " could not remove directory: {} " , target . bold ( ) ) ) ? ;
2024-03-13 19:27:25 +00:00
} else {
2024-03-26 13:56:11 +00:00
fs ::remove_file ( target )
2024-03-26 13:54:15 +00:00
. with_context ( | | format! ( " could not remove file: {} " , target . bold ( ) ) ) ? ;
2024-03-13 19:27:25 +00:00
}
} else {
2024-03-22 21:13:30 +00:00
println! (
2024-04-02 16:37:34 +01:00
" {}: the specified target does not exist: {} " ,
2024-03-26 13:54:15 +00:00
" error " . red ( ) . bold ( ) ,
2024-03-22 21:13:30 +00:00
target . yellow ( )
) ;
2024-03-13 19:27:25 +00:00
}
}
Ok ( ( ) )
}
2024-03-26 13:54:15 +00:00
fn main ( ) {
if let Err ( error ) = vaporise ( ) {
println! ( " {} : {:?} " , " error " . red ( ) . bold ( ) , error ) ;
}
}