Handle input in environment
This commit is contained in:
parent
85b0b3dbbf
commit
0632d7b0a9
@ -1,18 +1,19 @@
|
||||
use std::env;
|
||||
use std::env::VarError;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::PathBuf;
|
||||
use std::{env, io};
|
||||
|
||||
pub trait Environment {
|
||||
fn args_os(&self) -> Vec<OsString>;
|
||||
fn var<K>(&self, key: K) -> Result<String, VarError>
|
||||
where
|
||||
K: AsRef<OsStr>;
|
||||
fn set_var<K, V>(&self, key: K, value: V)
|
||||
fn set_var<K, V>(&mut self, key: K, value: V)
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>;
|
||||
fn get_home_directory(&self) -> Option<PathBuf>;
|
||||
fn read_line(&mut self) -> Result<String, io::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -30,7 +31,7 @@ impl Environment for Prod {
|
||||
env::var(key)
|
||||
}
|
||||
|
||||
fn set_var<K, V>(&self, key: K, value: V)
|
||||
fn set_var<K, V>(&mut self, key: K, value: V)
|
||||
where
|
||||
K: AsRef<OsStr>,
|
||||
V: AsRef<OsStr>
|
||||
@ -41,4 +42,10 @@ impl Environment for Prod {
|
||||
fn get_home_directory(&self) -> Option<PathBuf> {
|
||||
homedir::my_home().ok().flatten()
|
||||
}
|
||||
|
||||
fn read_line(&mut self) -> Result<String, io::Error> {
|
||||
let mut buffer = String::new();
|
||||
io::stdin().read_line(&mut buffer)?;
|
||||
Ok(buffer.trim().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
106
src/main.rs
106
src/main.rs
@ -141,24 +141,6 @@ enum OldVersionPolicy {
|
||||
Delete,
|
||||
}
|
||||
|
||||
//TODO IO would also need to be handled by the environment
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! input {
|
||||
($prompt: tt) => {{
|
||||
print!($prompt);
|
||||
io::stdout().flush().expect("failed to flush stdout");
|
||||
let mut buf = String::new();
|
||||
io::stdin()
|
||||
.read_line(&mut buf)
|
||||
.expect("failed to read stdin");
|
||||
buf.trim().to_string()
|
||||
}};
|
||||
() => {
|
||||
input!()
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Application<E> {
|
||||
pub environment: E,
|
||||
@ -168,12 +150,14 @@ impl<E> Application<E>
|
||||
where
|
||||
E: Environment,
|
||||
{
|
||||
pub fn run(&self) -> Result<(), String> {
|
||||
pub fn run(&mut self) -> Result<(), String> {
|
||||
let args = Args::try_parse_from(self.environment.args_os()).map_err(|e| e.to_string())?;
|
||||
self.run_with_args(args)
|
||||
}
|
||||
|
||||
pub fn run_with_args(&self, args: Args) -> Result<(), String> {
|
||||
pub fn run_with_args(&mut self, args: Args) -> Result<(), String> {
|
||||
let env = &mut self.environment;
|
||||
|
||||
let logger = Logger {
|
||||
//all the below options are conflicting with each other so an if else is fine
|
||||
level: if args.quiet {
|
||||
@ -216,7 +200,6 @@ where
|
||||
} => {
|
||||
Self::require_non_empty_servers(&servers)?;
|
||||
Self::require_non_empty(&files, "files to upload")?;
|
||||
self.start_ssh_agent(&logger)?;
|
||||
|
||||
//resolve file server
|
||||
let file_server = match file_server {
|
||||
@ -230,6 +213,8 @@ where
|
||||
None => None,
|
||||
};
|
||||
|
||||
self.start_ssh_agent(&logger)?;
|
||||
|
||||
//make sure files exist
|
||||
match &file_server {
|
||||
Some(file_server) => match &file_server.address {
|
||||
@ -448,14 +433,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if !no_confirm {
|
||||
match input!("Continue? [Y|n] ").to_lowercase().as_str() {
|
||||
"n" | "no" => {
|
||||
log!(logger, "Aborting...");
|
||||
return Ok(());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !no_confirm && !self.confirm("Continue?", true) {
|
||||
log!(logger, "Aborting...");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for server_actions in actions {
|
||||
@ -557,7 +537,8 @@ where
|
||||
let download_directory = match download_directory {
|
||||
Some(download_directory) => download_directory,
|
||||
None => {
|
||||
let home_dir = self.get_home_directory()
|
||||
let home_dir = self
|
||||
.get_home_directory()
|
||||
.map_err(|e| format!("Missing download-directory: {e}"))?;
|
||||
home_dir.join("Downloads")
|
||||
}
|
||||
@ -588,14 +569,8 @@ where
|
||||
download_directory.to_string_lossy()
|
||||
);
|
||||
|
||||
if !args.quiet {
|
||||
match input!("{duplication_notification}. Do you want to replace it? [N|y] ")
|
||||
.to_lowercase()
|
||||
.as_str()
|
||||
{
|
||||
"y" | "yes" => break 'duplicate_check,
|
||||
_ => {}
|
||||
}
|
||||
if !args.quiet && self.confirm(format!("{duplication_notification}. Do you want to replace it?"), false) {
|
||||
break 'duplicate_check;
|
||||
}
|
||||
|
||||
return Err(format!(
|
||||
@ -677,8 +652,8 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_ssh_agent(&self, logger: &Logger) -> Result<(), String> {
|
||||
let env = &self.environment;
|
||||
fn start_ssh_agent(&mut self, logger: &Logger) -> Result<(), String> {
|
||||
let env = &mut self.environment;
|
||||
|
||||
//start the ssh agent
|
||||
let agent_output = ShellCmd::new("ssh-agent")
|
||||
@ -711,9 +686,36 @@ where
|
||||
.map_err(|_| format!("Missing environment variable {}", SERVERS_ENV_VAR))
|
||||
.and_then(|value| parse_server_configuration(&value, || self.get_home_directory()))
|
||||
}
|
||||
|
||||
|
||||
fn get_home_directory(&self) -> Result<PathBuf, String> {
|
||||
self.environment.get_home_directory().ok_or("Failed to find your home directory".to_string())
|
||||
self
|
||||
.environment
|
||||
.get_home_directory()
|
||||
.ok_or("Failed to find your home directory".to_string())
|
||||
}
|
||||
|
||||
fn confirm<S>(&mut self, prompt: S, default_value: bool) -> bool
|
||||
where
|
||||
S: ToString,
|
||||
{
|
||||
loop {
|
||||
print!(
|
||||
"{}[{}]",
|
||||
prompt.to_string(),
|
||||
if default_value { "Y|n" } else { "y|N" }
|
||||
);
|
||||
io::stdout().flush().expect("failed to flush stdout");
|
||||
let line = self
|
||||
.environment
|
||||
.read_line()
|
||||
.expect("Failed to read console input");
|
||||
match line.to_lowercase().as_str() {
|
||||
"" => return default_value,
|
||||
"y" | "yes" => return true,
|
||||
"n" | "no" => return false,
|
||||
_ => println!("Invalid input, please choose one of the provided options"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -736,12 +738,22 @@ fn osstring_from_ssh_output(output: Vec<u8>) -> OsString {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_server_configuration<F>(config_str: &str, get_home_directory: F) -> Result<Vec<Server>, String> where F: Fn() -> Result<PathBuf, String> {
|
||||
fn parse_server_configuration<F>(
|
||||
config_str: &str,
|
||||
get_home_directory: F,
|
||||
) -> Result<Vec<Server>, String>
|
||||
where
|
||||
F: Fn() -> Result<PathBuf, String>,
|
||||
{
|
||||
config_str
|
||||
.split(',')
|
||||
.map(|server_entry| {
|
||||
Server::from_str(server_entry, RelativeLocalPathAnker::Home, &get_home_directory)
|
||||
.map_err(|e| format!("Invalid server entry '{server_entry}': {e}"))
|
||||
Server::from_str(
|
||||
server_entry,
|
||||
RelativeLocalPathAnker::Home,
|
||||
&get_home_directory,
|
||||
)
|
||||
.map_err(|e| format!("Invalid server entry '{server_entry}': {e}"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -755,8 +767,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_parse_server_configuration() {
|
||||
let servers =
|
||||
parse_server_configuration("foo:bar,.:fizz/buzz", || Ok(PathBuf::from("/test"))).expect("valid server configuration");
|
||||
let servers = parse_server_configuration("foo:bar,.:fizz/buzz", || Ok(PathBuf::from("/test")))
|
||||
.expect("valid server configuration");
|
||||
assert_eq!(
|
||||
vec![
|
||||
Server {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user