use bofh::Bofh;
use clap::Parser;
mod helper;
use crate::helper::BofhHelper;
use rpassword::prompt_password;
use rustyline::{config::Configurer, error::ReadlineError, Editor};
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[clap(long)]
cmd: Option<String>,
#[clap(short, long, help_heading = "Connection settings", value_name = "PEM", default_value_t = String::from("foo"))]
cert: String,
#[clap(long, help_heading = "Output settings", value_name = "N")]
verbosity: Option<String>,
#[clap(
short,
action = clap::ArgAction::Count,
help_heading = "Output settings",
required = false
)]
verbosity_level: u8,
#[clap(short, long, help_heading = "Output settings")]
quiet: bool,
#[clap(long, help_heading = "Connection settings", default_value_t = String::from("https://cerebrum-uio-test.uio.no:8000/"))]
url: String,
#[clap(long, short, help_heading = "Connection settings", default_value_t = whoami::username())]
user: String,
#[clap(long, help_heading = "Connection settings")]
insecure: bool,
#[clap(
long,
default_value_t = 0,
help_heading = "Connection settings",
value_name = "N"
)]
timeout: u8,
#[clap(long, help_heading = "REPL behavior", alias = "vim")]
vi: bool,
#[clap(long, short, help_heading = "REPL behavior", default_value_t = String::from("bofh> "))]
prompt: String,
}
fn main() {
let args = Args::parse();
println!("Connecting to {}\n", &args.url);
let mut bofh = match Bofh::new(args.url) {
Ok(bofh) => bofh,
Err(err) => {
println!("{}", err);
std::process::exit(1);
}
};
if let Some(motd) = &bofh.motd {
println!("{}\n", motd);
}
let password = match prompt_password(format!("Password for {}: ", &args.user)) {
Ok(password) => password,
Err(_) => std::process::exit(0), };
let commands = match bofh.login(&args.user, password) {
Ok(commands) => commands,
Err(err) => {
println!("{}", err);
std::process::exit(1);
}
};
let helper = BofhHelper {
commands: &commands,
};
let mut rl = Editor::<BofhHelper>::new();
rl.set_helper(Some(helper));
if args.vi {
rl.set_edit_mode(rustyline::EditMode::Vi);
rl.set_completion_type(rustyline::CompletionType::Circular);
}
if rl.load_history("history.txt").is_err() {
println!("No previous history.");
}
loop {
match rl.readline(&args.prompt) {
Ok(line) => {
let command: Vec<&str> = line.split_whitespace().collect();
if !command.is_empty() {
if let Some(command_group) = commands.get(command[0]) {
if command.len() > 1 {
if let Some(subcommand) = command_group.commands.get(command[1]) {
match bofh.run_command(subcommand.fullname.as_str(), &command[2..])
{
Ok(ok) => println!("{:?}", ok),
Err(err) => println!("{}", err),
}
} else {
println!("Unknown command");
}
} else {
println!(
"Incomplete command, possible subcommands:\n{}",
command_group
.commands
.keys()
.cloned()
.collect::<Vec<String>>()
.join(", "),
);
}
}
}
rl.add_history_entry(&line);
}
Err(ReadlineError::Interrupted | ReadlineError::Eof) => {
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
println!("So long, and thanks for all the fish!");
rl.append_history("history.txt").unwrap();
}