Skip to content

Commit

Permalink
more error handling + added way to delete trash contents + completion…
Browse files Browse the repository at this point in the history
…s generation + use real directories + check of the config
  • Loading branch information
Nissyaniss committed May 19, 2024
1 parent 8dbdce2 commit 3a8f671
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 28 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ authors = [ "" ]
clap = { version = "4.5.0", features = ["derive"] }
dialoguer = "0.11.0"
toml = "0.8.13"
clap_complete = "4.5.2"

[dev-dependencies]
anyhow = "1.0.79"
Expand Down
190 changes: 162 additions & 28 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
use clap::Parser;
use clap::{CommandFactory, Parser};
use clap_complete::{generate, Generator, Shell};
use dialoguer::Confirm;
use std::env;
use std::fs::File;
use std::io;
use std::{
fs::{self},
path::PathBuf,
};
#[allow(dead_code)]
use toml::Value;

struct Config {
path_to_trash: String,
}

impl Default for Config {
fn default() -> Self {
let home_dir = match env::var("HOME") {
Ok(val) => val,
Err(_) => {
eprintln!("Error getting home directory. Check your configuration file or create the environment variable named $HOME with your home path in it.");
return Config {
path_to_trash: String::from("null"),
};
}
};
Config {
path_to_trash: String::from("/mnt/c/Users/test/BetterReMove/trash/"),
path_to_trash: String::from(format!(
"{home_dir}/.local/share/BetterReMove/trash/",
home_dir = home_dir
)),
}
}
}
Expand All @@ -24,18 +41,34 @@ struct Args {
short = 't',
long = "trash-path",
help = "Reveal the trash path",
conflicts_with_all = &["force", "new_trash_path", "paths"]
conflicts_with_all = &["force", "new_trash_path", "paths", "generate_completions", "delete_trash_contents"]
)]
trash_path_reveal: bool,

#[arg(
short = 'd',
long = "delete-trash-contents",
help = "Deletes the trash's contents",
conflicts_with_all = &["force", "new_trash_path", "paths", "generate_completions", "trash_path_reveal"]
)]
delete_trash_contents: bool,

#[arg(
long = "set-trash-path",
value_name = "VALUE",
conflicts_with_all = &["force", "trash_path_reveal", "paths"],
conflicts_with_all = &["force", "trash_path_reveal", "paths", "generate_completions", "delete_trash_contents"],
help = "Files to remove"
)]
new_trash_path: Option<PathBuf>,

#[arg(
long = "generate-completions",
value_name = "SHELL",
conflicts_with_all = &["force", "trash_path_reveal", "paths", "new_trash_path", "delete_trash_contents"],
help = "Generate shell completions"
)]
generate_completions: Option<Shell>,

#[arg(
short = 'f',
long = "force",
Expand All @@ -50,27 +83,61 @@ struct Args {
fn main() {
let args = Args::parse();
let files = args.paths.clone();
let config_file = PathBuf::from(r"/mnt/c/Users/test/BetterReMove/config.toml"); // VALUE FOR DEVELOPMENT
if !config_file.exists() {
fs::write(
config_file.clone(),
"path_to_trash = '/mnt/c/Users/test/BetterReMove/trash'", // VALUE FOR DEVELOPMENT
)
.unwrap();
let home_dir = match env::var("HOME") {
Ok(val) => val,
Err(_) => {
eprintln!("Error getting home directory. Create the environment variable named $HOME with your home path in it.");
return;
}
};
let config_file = PathBuf::from(format!(
"{home_dir}/.config/BetterReMove/config.toml",
home_dir = home_dir
));
let trash_dir = check_config(config_file.clone());
if trash_dir == "null" {
return;
}
let config_str = fs::read_to_string(config_file.clone()).unwrap();
let parsed_config: toml::Value = toml::from_str(&config_str).unwrap();
let trash_dir = parsed_config["path_to_trash"].as_str().unwrap().to_string();

if !PathBuf::from(&trash_dir).exists() {
fs::create_dir(&trash_dir).unwrap();
if args.delete_trash_contents {
let confirmed = Confirm::new()
.with_prompt("Are you sure you want to erase the trash ?")
.default(false)
.interact()
.unwrap();
if confirmed {
for entry in fs::read_dir(trash_dir).unwrap() {
let path = entry.unwrap().path();
if path.is_dir() {
match fs::remove_dir_all(path.clone()) {
Ok(_) => (),
Err(e) => eprintln!("Error removing directory {}: {}", path.display(), e),
};
} else {
match fs::remove_file(path.clone()) {
Ok(_) => (),
Err(e) => eprintln!("Error removing file {}: {}", path.display(), e),
};
}
}
}
return;
}

if args.trash_path_reveal {
println!("This is the current trash directory.\n{}", trash_dir);
}

if let Some(shell) = args.generate_completions {
generate_completions(shell);
return;
}

if args.new_trash_path.clone() != None {
if args.new_trash_path.clone().unwrap().is_file() {
println!("The new trash path must be a directory.");
return;
}
let new_trash_path = args.new_trash_path.unwrap().to_str().unwrap().to_string();
let new_config = format!("path_to_trash = '{}'", new_trash_path);
fs::write(config_file, new_config).unwrap();
Expand All @@ -80,6 +147,70 @@ fn main() {
trashing(files, trash_dir, args);
}

fn check_config(config_file: PathBuf) -> String {
let default_config = Config::default();
let default_config_str = format!("path_to_trash = '{}'", default_config.path_to_trash);
if !config_file.exists() {
fs::create_dir_all(config_file.parent().unwrap()).unwrap();

File::create(config_file.clone()).unwrap();
fs::write(config_file.clone(), default_config_str.clone()).unwrap();
}

let config_str = fs::read_to_string(config_file.clone()).unwrap();
let parsed_config = config_str
.parse::<Value>()
.ok()
.and_then(|r| match r {
Value::Table(table) => Some(table),
_ => None,
})
.unwrap();
let mut trash_dir = String::from("null");
if !parsed_config.get("path_to_trash").is_none() {
trash_dir = parsed_config
.get("path_to_trash")
.unwrap()
.as_str()
.unwrap()
.to_string();
if !PathBuf::from(&trash_dir).exists() {
match fs::create_dir_all(&trash_dir) {
Ok(_) => (),
Err(e) => eprintln!("Error creating trash directory: {}", e),
};
} else if PathBuf::from(&trash_dir).is_file() {
println!("The trash path must be a directory.");
return "null".to_string();
} else if !trash_dir.ends_with("/") {
trash_dir.push_str("/");
}
} else {
println!("Error parsing config file.");
let confirmed = Confirm::new()
.with_prompt("Do you want to reset the config file ?")
.default(false)
.interact()
.unwrap();
if confirmed {
fs::write(config_file.clone(), default_config_str).unwrap();
return "null".to_string();
}
}
trash_dir
}

fn generate_completions<G: Generator>(gen: G) {
let mut cmd = Args::command();
let bin_name = env::current_exe()
.expect("Failed to get binary name")
.file_name()
.expect("Failed to get binary name")
.to_string_lossy()
.to_string();
generate(gen, &mut cmd, &bin_name, &mut io::stdout());
}

fn trashing(files: Vec<PathBuf>, trash_dir: String, args: Args) {
for file in files {
if file.exists() {
Expand All @@ -104,22 +235,27 @@ fn trashing(files: Vec<PathBuf>, trash_dir: String, args: Args) {
i += 1;
}
} else if file.is_dir() {
if args.force {
fs::remove_dir_all(&file).unwrap();
continue;
}

let confirmed = Confirm::new()
.with_prompt("The file you are trying to is a directory.\nAre you sure ?")
.with_prompt(
"The file you are trying to trash or remove is a directory. Are you sure ?",
)
.default(false)
.interact()
.unwrap();

if confirmed {
if args.force {
fs::remove_dir_all(&file).unwrap();
continue;
}

match fs::rename(
&file,
String::from(
trash_dir.clone() + "/" + &file.file_name().unwrap().to_str().unwrap() + "/",
trash_dir.clone()
+ "/"
+ &file.file_name().unwrap().to_str().unwrap()
+ "/",
),
) {
Ok(_) => continue,
Expand All @@ -133,17 +269,15 @@ fn trashing(files: Vec<PathBuf>, trash_dir: String, args: Args) {
match fs::rename(
&file,
String::from(
trash_dir.clone() + "/" + &file.file_name().unwrap().to_str().unwrap(),
trash_dir.clone() + &file.file_name().unwrap().to_str().unwrap(),
),
) {
Ok(_) => continue,
Err(e) => eprintln!(
"Error moving file: {} {}",
e,
String::from(
trash_dir.clone()
+ &file.file_name().unwrap().to_str().unwrap()
+ "/",
trash_dir.clone() + &file.file_name().unwrap().to_str().unwrap(),
),
),
}
Expand Down

0 comments on commit 3a8f671

Please sign in to comment.