Merge branch 'safe-output'
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
commit
1347784898
6 changed files with 202 additions and 85 deletions
|
@ -211,7 +211,13 @@ fn delete_category(rt: &Runtime) {
|
||||||
let scmd = rt.cli().subcommand_matches("delete-category").unwrap(); // safed by main()
|
let scmd = rt.cli().subcommand_matches("delete-category").unwrap(); // safed by main()
|
||||||
let name = scmd.value_of("delete-category-name").map(String::from).unwrap(); // safed by clap
|
let name = scmd.value_of("delete-category-name").map(String::from).unwrap(); // safed by clap
|
||||||
let ques = format!("Do you really want to delete category '{}' and remove links to all categorized enties?", name);
|
let ques = format!("Do you really want to delete category '{}' and remove links to all categorized enties?", name);
|
||||||
let answer = ask_bool(&ques, Some(false));
|
|
||||||
|
let mut input = rt.stdin().unwrap_or_else(|| {
|
||||||
|
error!("No input stream. Cannot ask for permission");
|
||||||
|
::std::process::exit(1)
|
||||||
|
});
|
||||||
|
let mut output = rt.stdout();
|
||||||
|
let answer = ask_bool(&ques, Some(false), &mut input, &mut output).map_err_trace_exit_unwrap(1);
|
||||||
|
|
||||||
if answer {
|
if answer {
|
||||||
info!("Deleting category '{}'", name);
|
info!("Deleting category '{}'", name);
|
||||||
|
|
|
@ -117,9 +117,19 @@ fn remove(rt: &Runtime) {
|
||||||
.into_storeid()
|
.into_storeid()
|
||||||
.map_err_trace_exit_unwrap(1);
|
.map_err_trace_exit_unwrap(1);
|
||||||
|
|
||||||
|
let mut input = rt.stdin().unwrap_or_else(|| {
|
||||||
|
error!("No input stream. Cannot ask for permission");
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
match rt.store().get(id.clone()).map_err_trace_exit_unwrap(1) {
|
match rt.store().get(id.clone()).map_err_trace_exit_unwrap(1) {
|
||||||
Some(mut entry) => {
|
Some(mut entry) => {
|
||||||
if yes || ask_bool(&format!("Delete ref from entry '{}'", id), None) {
|
if yes ||
|
||||||
|
ask_bool(&format!("Delete ref from entry '{}'", id), None, &mut input, &mut output)
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
{
|
||||||
let _ = entry.remove_ref().map_err_trace_exit_unwrap(1);
|
let _ = entry.remove_ref().map_err_trace_exit_unwrap(1);
|
||||||
} else {
|
} else {
|
||||||
info!("Aborted");
|
info!("Aborted");
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
|
@ -72,14 +73,9 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! ask_continue {
|
fn ask_continue(inputstream: &mut Read, outputstream: &mut Write) -> bool {
|
||||||
{ yes => $yes:expr; no => $no:expr } => {
|
::libimaginteraction::ask::ask_bool("Edit tempfile", Some(true), inputstream, outputstream)
|
||||||
if ::libimaginteraction::ask::ask_bool("Edit tempfile", Some(true)) {
|
.map_err_trace_exit_unwrap(1)
|
||||||
$yes
|
|
||||||
} else {
|
|
||||||
$no
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(rt: &Runtime) {
|
pub fn create(rt: &Runtime) {
|
||||||
|
@ -90,7 +86,7 @@ pub fn create(rt: &Runtime) {
|
||||||
if let Some(mut fl) = scmd.value_of("file-location").map(PathBuf::from) {
|
if let Some(mut fl) = scmd.value_of("file-location").map(PathBuf::from) {
|
||||||
let uuid = if fl.is_file() {
|
let uuid = if fl.is_file() {
|
||||||
error!("File does exist, cannot create/override");
|
error!("File does exist, cannot create/override");
|
||||||
exit(1);
|
exit(1)
|
||||||
} else if fl.is_dir() {
|
} else if fl.is_dir() {
|
||||||
let uuid = Uuid::new_v4().to_hyphenated().to_string();
|
let uuid = Uuid::new_v4().to_hyphenated().to_string();
|
||||||
fl.push(uuid.clone());
|
fl.push(uuid.clone());
|
||||||
|
@ -147,6 +143,13 @@ pub fn create(rt: &Runtime) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut input = rt.stdin().unwrap_or_else(|| {
|
||||||
|
error!("No input stream. Cannot ask for permission");
|
||||||
|
exit(1)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
::libimagentryedit::edit::edit_in_tmpfile(&rt, &mut template)
|
::libimagentryedit::edit::edit_in_tmpfile(&rt, &mut template)
|
||||||
.map_warn_err_str("Editing failed.")
|
.map_warn_err_str("Editing failed.")
|
||||||
|
@ -158,20 +161,27 @@ pub fn create(rt: &Runtime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
match ::toml::de::from_str(&template)
|
match ::toml::de::from_str(&template)
|
||||||
.map(|toml| parse_toml_into_vcard(toml, uuid.clone()))
|
.map(|toml| parse_toml_into_vcard(&mut output, &mut input, toml, uuid.clone()))
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
{
|
{
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error parsing template");
|
error!("Error parsing template");
|
||||||
trace_error(&e);
|
trace_error(&e);
|
||||||
ask_continue! { yes => continue; no => exit(1) };
|
|
||||||
|
if ask_continue(&mut input, &mut output) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Ok(None) => continue,
|
Ok(None) => continue,
|
||||||
Ok(Some(vcard)) => {
|
Ok(Some(vcard)) => {
|
||||||
if template == TEMPLATE || template.is_empty() {
|
if template == TEMPLATE || template.is_empty() {
|
||||||
if ::libimaginteraction::ask::ask_bool("Abort contact creating", Some(false)) {
|
if ::libimaginteraction::ask::ask_bool("Abort contact creating", Some(false), &mut input, &mut output)
|
||||||
exit(1);
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
{
|
||||||
|
exit(1)
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +215,7 @@ pub fn create(rt: &Runtime) {
|
||||||
info!("Ready");
|
info!("Ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
fn parse_toml_into_vcard(output: &mut Write, input: &mut Read, toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
let mut vcard = VcardBuilder::new().with_uid(uuid);
|
let mut vcard = VcardBuilder::new().with_uid(uuid);
|
||||||
|
|
||||||
{ // parse name
|
{ // parse name
|
||||||
|
@ -257,7 +267,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'nickname.[{}].name' missing", i);
|
error!("Key 'nickname.[{}].name' missing", i);
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -274,7 +288,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Type Error: Expected Array or String at 'nickname'");
|
error!("Type Error: Expected Array or String at 'nickname'");
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -310,7 +328,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'phones.[{}].type' missing", i);
|
error!("Key 'phones.[{}].type' missing", i);
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -318,7 +340,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'phones.[{}].number' missing", i);
|
error!("Key 'phones.[{}].number' missing", i);
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -331,7 +357,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Expected Array at 'phones'.");
|
error!("Expected Array at 'phones'.");
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -347,7 +377,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
let adrtype = match read_str_from_toml(element, "type", false) {
|
let adrtype = match read_str_from_toml(element, "type", false) {
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'adresses.[{}].type' missing", i);
|
error!("Key 'adresses.[{}].type' missing", i);
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
};
|
};
|
||||||
|
@ -378,7 +412,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Type Error: Expected Array at 'addresses'");
|
error!("Type Error: Expected Array at 'addresses'");
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -394,7 +432,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
let mailtype = match read_str_from_toml(element, "type", false) {
|
let mailtype = match read_str_from_toml(element, "type", false) {
|
||||||
None => {
|
None => {
|
||||||
error!("Error: 'email.[{}].type' missing", i);
|
error!("Error: 'email.[{}].type' missing", i);
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
}; // TODO: Unused, because unsupported by vobject
|
}; // TODO: Unused, because unsupported by vobject
|
||||||
|
@ -402,7 +444,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
let mail = match read_str_from_toml(element, "addr", false) {
|
let mail = match read_str_from_toml(element, "addr", false) {
|
||||||
None => {
|
None => {
|
||||||
error!("Error: 'email.[{}].addr' missing", i);
|
error!("Error: 'email.[{}].addr' missing", i);
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
};
|
};
|
||||||
|
@ -416,7 +462,11 @@ fn parse_toml_into_vcard(toml: Value, uuid: String) -> Option<Vcard> {
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Type Error: Expected Array at 'email'");
|
error!("Type Error: Expected Array at 'email'");
|
||||||
ask_continue! { yes => return None; no => exit(1) };
|
if ask_continue(input, output) {
|
||||||
|
return None
|
||||||
|
} else {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// nothing
|
// nothing
|
||||||
|
@ -508,6 +558,7 @@ fn read_str_from_toml(toml: &Value, path: &'static str, must_be_there: bool) ->
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_parsing {
|
mod test_parsing {
|
||||||
use super::parse_toml_into_vcard;
|
use super::parse_toml_into_vcard;
|
||||||
|
use std::io::empty;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
const TEMPLATE : &'static str = include_str!("../static/new-contact-template-test.toml");
|
const TEMPLATE : &'static str = include_str!("../static/new-contact-template-test.toml");
|
||||||
|
@ -515,7 +566,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_names() {
|
fn test_template_names() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
@ -532,7 +584,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_person() {
|
fn test_template_person() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
@ -550,7 +603,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_organization() {
|
fn test_template_organization() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
@ -567,7 +621,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_phone() {
|
fn test_template_phone() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
@ -582,7 +637,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_email() {
|
fn test_template_email() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
@ -597,7 +653,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_addresses() {
|
fn test_template_addresses() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
@ -614,7 +671,8 @@ mod test_parsing {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_template_other() {
|
fn test_template_other() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let vcard = parse_toml_into_vcard(::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let mut output = Vec::new();
|
||||||
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
||||||
assert!(vcard.is_some(), "Failed to parse test template.");
|
assert!(vcard.is_some(), "Failed to parse test template.");
|
||||||
let vcard = vcard.unwrap();
|
let vcard = vcard.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,16 @@ pub fn delete(rt: &Runtime) {
|
||||||
.get_location()
|
.get_location()
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true)) {
|
let mut input = rt.stdin().unwrap_or_else(|| {
|
||||||
|
error!("No input stream. Cannot ask for permission");
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
|
if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true), &mut input, &mut output)
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
{
|
||||||
info!("Aborting delete action");
|
info!("Aborting delete action");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,6 +166,13 @@ fn delete(rt: &Runtime) {
|
||||||
let yes = scmd.is_present("delete-yes");
|
let yes = scmd.is_present("delete-yes");
|
||||||
let delete_instances = scmd.is_present("delete-instances");
|
let delete_instances = scmd.is_present("delete-instances");
|
||||||
|
|
||||||
|
let mut input = rt.stdin().unwrap_or_else(|| {
|
||||||
|
error!("No input stream. Cannot ask for permission");
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut output = rt.stdout();
|
||||||
|
|
||||||
let _ = rt
|
let _ = rt
|
||||||
.store()
|
.store()
|
||||||
.all_habit_templates()
|
.all_habit_templates()
|
||||||
|
@ -191,7 +198,9 @@ fn delete(rt: &Runtime) {
|
||||||
let do_delete = |id| rt.store().delete(id).map_err_trace_exit_unwrap(1);
|
let do_delete = |id| rt.store().delete(id).map_err_trace_exit_unwrap(1);
|
||||||
if !yes {
|
if !yes {
|
||||||
let q = format!("Really delete {}", id);
|
let q = format!("Really delete {}", id);
|
||||||
if ask_bool(&q, Some(false)) {
|
if ask_bool(&q, Some(false), &mut input, &mut output)
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
{
|
||||||
let _ = do_delete(id);
|
let _ = do_delete(id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -215,7 +224,9 @@ fn delete(rt: &Runtime) {
|
||||||
let do_delete_template = |sid| rt.store().delete(sid).map_err_trace_exit_unwrap(1);
|
let do_delete_template = |sid| rt.store().delete(sid).map_err_trace_exit_unwrap(1);
|
||||||
if !yes {
|
if !yes {
|
||||||
let q = format!("Really delete template {}", sid);
|
let q = format!("Really delete template {}", sid);
|
||||||
if ask_bool(&q, Some(false)) {
|
if ask_bool(&q, Some(false), &mut input, &mut output)
|
||||||
|
.map_err_trace_exit_unwrap(1)
|
||||||
|
{
|
||||||
let _ = do_delete_template(sid);
|
let _ = do_delete_template(sid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
|
|
||||||
// functions to ask the user for data, with crate:spinner
|
// functions to ask the user for data, with crate:spinner
|
||||||
|
|
||||||
use std::io::stdin;
|
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::result::Result as RResult;
|
use std::result::Result as RResult;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ansi_term::Colour::*;
|
use ansi_term::Colour::*;
|
||||||
|
@ -34,33 +35,33 @@ use failure::err_msg;
|
||||||
|
|
||||||
/// Ask the user for a Yes/No answer. Optionally provide a default value. If none is provided, this
|
/// Ask the user for a Yes/No answer. Optionally provide a default value. If none is provided, this
|
||||||
/// keeps loop{}ing
|
/// keeps loop{}ing
|
||||||
pub fn ask_bool(s: &str, default: Option<bool>) -> bool {
|
pub fn ask_bool(s: &str, default: Option<bool>, input: &mut Read, output: &mut Write) -> Result<bool> {
|
||||||
ask_bool_(s, default, &mut BufReader::new(stdin()))
|
ask_bool_(s, default, &mut BufReader::new(input), output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_bool_<R: BufRead>(s: &str, default: Option<bool>, input: &mut R) -> bool {
|
fn ask_bool_<R: BufRead>(s: &str, default: Option<bool>, input: &mut R, output: &mut Write) -> Result<bool> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref R_YES: Regex = Regex::new(r"^[Yy](\n?)$").unwrap();
|
static ref R_YES: Regex = Regex::new(r"^[Yy](\n?)$").unwrap();
|
||||||
static ref R_NO: Regex = Regex::new(r"^[Nn](\n?)$").unwrap();
|
static ref R_NO: Regex = Regex::new(r"^[Nn](\n?)$").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ask_question(s, false);
|
ask_question(s, false, output)?;
|
||||||
if match default { Some(s) => s, _ => true } {
|
if match default { Some(s) => s, _ => true } {
|
||||||
println!(" [Yn]: ");
|
writeln!(output, " [Yn]: ")?;
|
||||||
} else {
|
} else {
|
||||||
println!(" [yN]: ");
|
writeln!(output, " [yN]: ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let _ = input.read_line(&mut s);
|
let _ = input.read_line(&mut s);
|
||||||
|
|
||||||
if R_YES.is_match(&s[..]) {
|
if R_YES.is_match(&s[..]) {
|
||||||
return true
|
return Ok(true)
|
||||||
} else if R_NO.is_match(&s[..]) {
|
} else if R_NO.is_match(&s[..]) {
|
||||||
return false
|
return Ok(false)
|
||||||
} else if default.is_some() {
|
} else if default.is_some() {
|
||||||
return default.unwrap();
|
return Ok(default.unwrap())
|
||||||
}
|
}
|
||||||
// else again...
|
// else again...
|
||||||
}
|
}
|
||||||
|
@ -68,25 +69,25 @@ fn ask_bool_<R: BufRead>(s: &str, default: Option<bool>, input: &mut R) -> bool
|
||||||
|
|
||||||
/// Ask the user for an unsigned number. Optionally provide a default value. If none is provided,
|
/// Ask the user for an unsigned number. Optionally provide a default value. If none is provided,
|
||||||
/// this keeps loop{}ing
|
/// this keeps loop{}ing
|
||||||
pub fn ask_uint(s: &str, default: Option<u64>) -> u64 {
|
pub fn ask_uint(s: &str, default: Option<u64>, input: &mut Read, output: &mut Write) -> Result<u64> {
|
||||||
ask_uint_(s, default, &mut BufReader::new(stdin()))
|
ask_uint_(s, default, &mut BufReader::new(input), output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_uint_<R: BufRead>(s: &str, default: Option<u64>, input: &mut R) -> u64 {
|
fn ask_uint_<R: BufRead>(s: &str, default: Option<u64>, input: &mut R, output: &mut Write) -> Result<u64> {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
ask_question(s, false);
|
ask_question(s, false, output)?;
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let _ = input.read_line(&mut s);
|
let _ = input.read_line(&mut s);
|
||||||
|
|
||||||
let u : RResult<u64, _> = FromStr::from_str(&s[..]);
|
let u : RResult<u64, _> = FromStr::from_str(&s[..]);
|
||||||
match u {
|
match u {
|
||||||
Ok(u) => { return u; },
|
Ok(u) => { return Ok(u); },
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if default.is_some() {
|
if default.is_some() {
|
||||||
return default.unwrap();
|
return Ok(default.unwrap());
|
||||||
} // else keep looping
|
} // else keep looping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,8 +110,10 @@ pub fn ask_string(s: &str,
|
||||||
permit_empty: bool,
|
permit_empty: bool,
|
||||||
permit_multiline: bool,
|
permit_multiline: bool,
|
||||||
eof: Option<&str>,
|
eof: Option<&str>,
|
||||||
prompt: &str)
|
prompt: &str,
|
||||||
-> String
|
input: &mut Read,
|
||||||
|
output: &mut Write)
|
||||||
|
-> Result<String>
|
||||||
{
|
{
|
||||||
ask_string_(s,
|
ask_string_(s,
|
||||||
default,
|
default,
|
||||||
|
@ -118,7 +121,8 @@ pub fn ask_string(s: &str,
|
||||||
permit_multiline,
|
permit_multiline,
|
||||||
eof,
|
eof,
|
||||||
prompt,
|
prompt,
|
||||||
&mut BufReader::new(stdin()))
|
&mut BufReader::new(input),
|
||||||
|
output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_string_<R: BufRead>(s: &str,
|
fn ask_string_<R: BufRead>(s: &str,
|
||||||
|
@ -127,36 +131,37 @@ fn ask_string_<R: BufRead>(s: &str,
|
||||||
permit_multiline: bool,
|
permit_multiline: bool,
|
||||||
eof: Option<&str>,
|
eof: Option<&str>,
|
||||||
prompt: &str,
|
prompt: &str,
|
||||||
input: &mut R)
|
input: &mut R,
|
||||||
-> String
|
output: &mut Write)
|
||||||
|
-> Result<String>
|
||||||
{
|
{
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
loop {
|
loop {
|
||||||
ask_question(s, true);
|
ask_question(s, true, output)?;
|
||||||
print!("{}", prompt);
|
write!(output, "{}", prompt)?;
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let _ = input.read_line(&mut s);
|
let _ = input.read_line(&mut s);
|
||||||
|
|
||||||
if permit_multiline {
|
if permit_multiline {
|
||||||
if permit_multiline && eof.map_or(false, |e| e == s) {
|
if permit_multiline && eof.map_or(false, |e| e == s) {
|
||||||
return v.join("\n");
|
return Ok(v.join("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if permit_empty || !v.is_empty() {
|
if permit_empty || !v.is_empty() {
|
||||||
v.push(s);
|
v.push(s);
|
||||||
}
|
}
|
||||||
print!("{}", prompt);
|
write!(output, "{}", prompt)?;
|
||||||
} else if s.is_empty() && permit_empty {
|
} else if s.is_empty() && permit_empty {
|
||||||
return s;
|
return Ok(s);
|
||||||
} else if s.is_empty() && !permit_empty {
|
} else if s.is_empty() && !permit_empty {
|
||||||
if default.is_some() {
|
if default.is_some() {
|
||||||
return default.unwrap();
|
return Ok(default.unwrap());
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return s;
|
return Ok(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,11 +176,11 @@ pub fn ask_select_from_list(list: &[&str]) -> Result<String> {
|
||||||
/// trailing questionmark.
|
/// trailing questionmark.
|
||||||
///
|
///
|
||||||
/// The `nl` parameter can be used to configure whether a newline character should be printed
|
/// The `nl` parameter can be used to configure whether a newline character should be printed
|
||||||
pub fn ask_question(question: &str, nl: bool) {
|
pub fn ask_question(question: &str, nl: bool, output: &mut Write) -> Result<()> {
|
||||||
if nl {
|
if nl {
|
||||||
println!("[imag]: {}?", Yellow.paint(question));
|
writeln!(output, "[imag]: {}?", Yellow.paint(question)).map_err(Error::from)
|
||||||
} else {
|
} else {
|
||||||
print!("[imag]: {}?", Yellow.paint(question));
|
writeln!(output, "[imag]: {}?", Yellow.paint(question)).map_err(Error::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,8 +196,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = None;
|
let default = None;
|
||||||
let answers = "\n\n\n\n\ny";
|
let answers = "\n\n\n\n\ny";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -200,8 +206,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = None;
|
let default = None;
|
||||||
let answers = "\n\n\n\n\ny\n";
|
let answers = "\n\n\n\n\ny\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -209,8 +216,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = None;
|
let default = None;
|
||||||
let answers = "n";
|
let answers = "n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -218,8 +226,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = None;
|
let default = None;
|
||||||
let answers = "n\n";
|
let answers = "n\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -227,8 +236,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(false);
|
let default = Some(false);
|
||||||
let answers = "n";
|
let answers = "n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -236,8 +246,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(false);
|
let default = Some(false);
|
||||||
let answers = "n\n";
|
let answers = "n\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -245,8 +256,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(true);
|
let default = Some(true);
|
||||||
let answers = "y";
|
let answers = "y";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -254,8 +266,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(true);
|
let default = Some(true);
|
||||||
let answers = "y\n";
|
let answers = "y\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -263,8 +276,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(true);
|
let default = Some(true);
|
||||||
let answers = "n";
|
let answers = "n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -272,8 +286,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(false);
|
let default = Some(false);
|
||||||
let answers = "y";
|
let answers = "y";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -281,8 +296,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(false);
|
let default = Some(false);
|
||||||
let answers = "\n";
|
let answers = "\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(false == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -290,8 +306,9 @@ mod test {
|
||||||
let question = "Is this true";
|
let question = "Is this true";
|
||||||
let default = Some(true);
|
let default = Some(true);
|
||||||
let answers = "\n";
|
let answers = "\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -299,8 +316,9 @@ mod test {
|
||||||
let question = "Is this 1";
|
let question = "Is this 1";
|
||||||
let default = None;
|
let default = None;
|
||||||
let answers = "1";
|
let answers = "1";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -308,8 +326,9 @@ mod test {
|
||||||
let question = "Is this 1";
|
let question = "Is this 1";
|
||||||
let default = Some(1);
|
let default = Some(1);
|
||||||
let answers = "1";
|
let answers = "1";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -317,8 +336,9 @@ mod test {
|
||||||
let question = "Is this 1";
|
let question = "Is this 1";
|
||||||
let default = Some(2);
|
let default = Some(2);
|
||||||
let answers = "1";
|
let answers = "1";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -326,8 +346,9 @@ mod test {
|
||||||
let question = "Is this 1";
|
let question = "Is this 1";
|
||||||
let default = Some(2);
|
let default = Some(2);
|
||||||
let answers = "\n";
|
let answers = "\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -335,8 +356,9 @@ mod test {
|
||||||
let question = "Is this 1";
|
let question = "Is this 1";
|
||||||
let default = Some(2);
|
let default = Some(2);
|
||||||
let answers = "\n\n\n\n";
|
let answers = "\n\n\n\n";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -344,8 +366,9 @@ mod test {
|
||||||
let question = "Is this 1";
|
let question = "Is this 1";
|
||||||
let default = Some(2);
|
let default = Some(2);
|
||||||
let answers = "\n\n\nasfb\nsakjf\naskjf\n-2";
|
let answers = "\n\n\nasfb\nsakjf\naskjf\n-2";
|
||||||
|
let mut sink: Vec<u8> = vec![];
|
||||||
|
|
||||||
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes())));
|
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue