Merge branch 'imag-contact/main-return-result' into master
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
commit
6f53964dc0
5 changed files with 310 additions and 378 deletions
|
@ -28,6 +28,7 @@ walkdir = "2.2.8"
|
||||||
uuid = { version = "0.7.4", features = ["v4"] }
|
uuid = { version = "0.7.4", features = ["v4"] }
|
||||||
serde_json = "1.0.39"
|
serde_json = "1.0.39"
|
||||||
failure = "0.1.5"
|
failure = "0.1.5"
|
||||||
|
resiter = "0.4"
|
||||||
|
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::process::exit;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -48,12 +47,11 @@ use toml::Value;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::ResultExt;
|
||||||
|
|
||||||
use libimagcontact::store::ContactStore;
|
use libimagcontact::store::ContactStore;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::trace::trace_error;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagutil::warn_result::WarnResult;
|
use libimagutil::warn_result::WarnResult;
|
||||||
|
|
||||||
const TEMPLATE : &str = include_str!("../static/new-contact-template.toml");
|
const TEMPLATE : &str = include_str!("../static/new-contact-template.toml");
|
||||||
|
@ -76,32 +74,26 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_continue(inputstream: &mut dyn Read, outputstream: &mut dyn Write) -> bool {
|
fn ask_continue(inputstream: &mut dyn Read, outputstream: &mut dyn Write) -> Result<bool> {
|
||||||
::libimaginteraction::ask::ask_bool("Edit tempfile", Some(true), inputstream, outputstream)
|
::libimaginteraction::ask::ask_bool("Edit tempfile", Some(true), inputstream, outputstream)
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(rt: &Runtime) {
|
pub fn create(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("create").unwrap();
|
let scmd = rt.cli().subcommand_matches("create").unwrap();
|
||||||
let mut template = String::from(TEMPLATE);
|
let mut template = String::from(TEMPLATE);
|
||||||
let collection_name = rt.cli().value_of("ref-collection-name").unwrap_or("contacts");
|
let collection_name = rt.cli().value_of("ref-collection-name").unwrap_or("contacts");
|
||||||
let collection_name = String::from(collection_name);
|
let collection_name = String::from(collection_name);
|
||||||
let ref_config = rt // TODO: Re-Deserialize to libimagentryref::reference::Config
|
let ref_config = rt // TODO: Re-Deserialize to libimagentryref::reference::Config
|
||||||
.config()
|
.config()
|
||||||
.ok_or_else(|| err_msg("Configuration missing, cannot continue!"))
|
.ok_or_else(|| err_msg("Configuration missing, cannot continue!"))?
|
||||||
.map_err_trace_exit_unwrap()
|
.read_partial::<libimagentryref::reference::Config>()?
|
||||||
.read_partial::<libimagentryref::reference::Config>()
|
.ok_or_else(|| format_err!("Configuration missing: {}", libimagentryref::reference::Config::LOCATION))?;
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.ok_or_else(|| format_err!("Configuration missing: {}", libimagentryref::reference::Config::LOCATION))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
// TODO: Refactor the above to libimagutil or libimagrt?
|
// TODO: Refactor the above to libimagutil or libimagrt?
|
||||||
|
|
||||||
let (mut dest, location, uuid) : (Box<dyn Write>, Option<PathBuf>, String) = {
|
let (mut dest, location, uuid) : (Box<dyn Write>, Option<PathBuf>, String) = {
|
||||||
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");
|
return Err(err_msg("File does exist, cannot create/override"))
|
||||||
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());
|
||||||
|
@ -121,7 +113,7 @@ pub fn create(rt: &Runtime) {
|
||||||
.map(|f| format!(" '{}' ", f)) // ugly
|
.map(|f| format!(" '{}' ", f)) // ugly
|
||||||
.unwrap_or_else(|| String::from(" ")); // hack
|
.unwrap_or_else(|| String::from(" ")); // hack
|
||||||
|
|
||||||
warn!("File{}has no extension 'vcf'", f); // ahead
|
warn!("File {} has no extension 'vcf'", f); // ahead
|
||||||
warn!("other tools might not recognize this as contact.");
|
warn!("other tools might not recognize this as contact.");
|
||||||
warn!("Continuing...");
|
warn!("Continuing...");
|
||||||
}
|
}
|
||||||
|
@ -135,20 +127,16 @@ pub fn create(rt: &Runtime) {
|
||||||
.write(true)
|
.write(true)
|
||||||
.create_new(true)
|
.create_new(true)
|
||||||
.open(fl.clone())
|
.open(fl.clone())
|
||||||
.map_warn_err_str("Cannot create/open destination File. Stopping.")
|
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
.map_err_trace_exit_unwrap();
|
.context("Cannot create/open destination File. Stopping.")?;
|
||||||
|
|
||||||
let uuid_string = uuid
|
let uuid_string = match uuid {
|
||||||
.unwrap_or_else(|| {
|
Some(s) => s,
|
||||||
fl.file_name()
|
None => fl.file_name()
|
||||||
.and_then(|fname| fname.to_str())
|
.and_then(|fname| fname.to_str())
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| err_msg("Cannot calculate UUID for vcard"))?,
|
||||||
error!("Cannot calculate UUID for vcard");
|
};
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
(Box::new(file), Some(fl), uuid_string)
|
(Box::new(file), Some(fl), uuid_string)
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,56 +146,47 @@ pub fn create(rt: &Runtime) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut input = rt.stdin().unwrap_or_else(|| {
|
let mut input = rt.stdin().ok_or_else(|| {
|
||||||
error!("No input stream. Cannot ask for permission");
|
err_msg("No input stream. Cannot ask for permission")
|
||||||
exit(1)
|
})?;
|
||||||
});
|
|
||||||
|
|
||||||
let mut output = rt.stdout();
|
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_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
if template == TEMPLATE || template.is_empty() {
|
if template == TEMPLATE || template.is_empty() {
|
||||||
error!("No (changed) content in tempfile. Not doing anything.");
|
return Err(err_msg("No (changed) content in tempfile. Not doing anything."))
|
||||||
exit(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match ::toml::de::from_str(&template)
|
match ::toml::de::from_str(&template)
|
||||||
.map(|toml| parse_toml_into_vcard(&mut output, &mut input, toml, uuid.clone()))
|
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
|
.and_then(|toml| parse_toml_into_vcard(&mut output, &mut input, toml, uuid.clone()))
|
||||||
{
|
{
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error parsing template");
|
error!("Error parsing template");
|
||||||
trace_error(&e);
|
|
||||||
|
|
||||||
if ask_continue(&mut input, &mut output) {
|
if ask_continue(&mut input, &mut output)? {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
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), &mut input, &mut output)
|
let q = "Abort contact creating";
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
{
|
if ::libimaginteraction::ask::ask_bool(q, Some(false), &mut input, &mut output)? {
|
||||||
exit(1)
|
return Ok(())
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let vcard_string = write_component(&vcard);
|
let vcard_string = write_component(&vcard);
|
||||||
dest
|
dest.write_all(&vcard_string.as_bytes())?;
|
||||||
.write_all(&vcard_string.as_bytes())
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,11 +194,8 @@ pub fn create(rt: &Runtime) {
|
||||||
|
|
||||||
if let Some(location) = location {
|
if let Some(location) = location {
|
||||||
if !scmd.is_present("dont-track") {
|
if !scmd.is_present("dont-track") {
|
||||||
let entry = rt.store()
|
let entry = rt.store().create_from_path(&location, &ref_config, &collection_name)?;
|
||||||
.create_from_path(&location, &ref_config, &collection_name)
|
rt.report_touched(entry.get_location())?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
|
||||||
|
|
||||||
info!("Created entry in store");
|
info!("Created entry in store");
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,26 +206,27 @@ pub fn create(rt: &Runtime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Ready");
|
info!("Ready");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[clippy::cognitive_complexity = "71"]
|
#[clippy::cognitive_complexity = "71"]
|
||||||
fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Value, uuid: String) -> Option<Vcard> {
|
fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Value, uuid: String) -> Result<Option<Vcard>> {
|
||||||
let mut vcard = VcardBuilder::new().with_uid(uuid);
|
let mut vcard = VcardBuilder::new().with_uid(uuid);
|
||||||
|
|
||||||
{ // parse name
|
{ // parse name
|
||||||
debug!("Parsing name");
|
debug!("Parsing name");
|
||||||
let firstname = read_str_from_toml(&toml, "name.first", true);
|
let firstname = read_str_from_toml(&toml, "name.first", true)?;
|
||||||
trace!("firstname = {:?}", firstname);
|
trace!("firstname = {:?}", firstname);
|
||||||
|
|
||||||
let lastname = read_str_from_toml(&toml, "name.last", true);
|
let lastname = read_str_from_toml(&toml, "name.last", true)?;
|
||||||
trace!("lastname = {:?}", lastname);
|
trace!("lastname = {:?}", lastname);
|
||||||
|
|
||||||
vcard = vcard.with_name(parameters!(),
|
vcard = vcard.with_name(parameters!(),
|
||||||
read_str_from_toml(&toml, "name.prefix", false),
|
read_str_from_toml(&toml, "name.prefix", false)?,
|
||||||
firstname.clone(),
|
firstname.clone(),
|
||||||
read_str_from_toml(&toml, "name.additional", false),
|
read_str_from_toml(&toml, "name.additional", false)?,
|
||||||
lastname.clone(),
|
lastname.clone(),
|
||||||
read_str_from_toml(&toml, "name.suffix", false));
|
read_str_from_toml(&toml, "name.suffix", false)?);
|
||||||
|
|
||||||
if let (Some(first), Some(last)) = (firstname, lastname) {
|
if let (Some(first), Some(last)) = (firstname, lastname) {
|
||||||
trace!("Building fullname: '{} {}'", first, last);
|
trace!("Building fullname: '{} {}'", first, last);
|
||||||
|
@ -259,7 +236,7 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
{ // parse personal
|
{ // parse personal
|
||||||
debug!("Parsing person information");
|
debug!("Parsing person information");
|
||||||
let birthday = read_str_from_toml(&toml, "person.birthday", false);
|
let birthday = read_str_from_toml(&toml, "person.birthday", false)?;
|
||||||
trace!("birthday = {:?}", birthday);
|
trace!("birthday = {:?}", birthday);
|
||||||
|
|
||||||
if let Some(bday) = birthday {
|
if let Some(bday) = birthday {
|
||||||
|
@ -269,10 +246,10 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
{ // parse nicknames
|
{ // parse nicknames
|
||||||
debug!("Parsing nicknames");
|
debug!("Parsing nicknames");
|
||||||
match toml.read("nickname").map_err(Error::from).map_err_trace_exit_unwrap() {
|
match toml.read("nickname").map_err(Error::from)? {
|
||||||
Some(&Value::Array(ref ary)) => {
|
Some(&Value::Array(ref ary)) => {
|
||||||
for (i, element) in ary.iter().enumerate() {
|
for (i, element) in ary.iter().enumerate() {
|
||||||
let nicktype = match read_str_from_toml(element, "type", false) {
|
let nicktype = match read_str_from_toml(element, "type", false)? {
|
||||||
None => BTreeMap::new(),
|
None => BTreeMap::new(),
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
let mut m = BTreeMap::new();
|
let mut m = BTreeMap::new();
|
||||||
|
@ -281,14 +258,14 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = match read_str_from_toml(element, "name", false) {
|
let name = match read_str_from_toml(element, "name", false)? {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'nickname.[{}].name' missing", i);
|
error!("Key 'nickname.[{}].name' missing", i);
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Key 'nickname.[{}].name' missing", i))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -306,10 +283,10 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Type Error: Expected Array or String at 'nickname'");
|
error!("Type Error: Expected Array or String at 'nickname'");
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Type Error: Expected Array or String at 'nickname'"))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -321,17 +298,17 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
{ // parse organisation
|
{ // parse organisation
|
||||||
debug!("Parsing organisation");
|
debug!("Parsing organisation");
|
||||||
|
|
||||||
if let Some(orgs) = read_strary_from_toml(&toml, "organisation.name") {
|
if let Some(orgs) = read_strary_from_toml(&toml, "organisation.name")? {
|
||||||
trace!("orgs = {:?}", orgs);
|
trace!("orgs = {:?}", orgs);
|
||||||
vcard = vcard.with_org(orgs);
|
vcard = vcard.with_org(orgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(title) = read_str_from_toml(&toml, "organisation.title", false) {
|
if let Some(title) = read_str_from_toml(&toml, "organisation.title", false)? {
|
||||||
trace!("title = {:?}", title);
|
trace!("title = {:?}", title);
|
||||||
vcard = vcard.with_title(title);
|
vcard = vcard.with_title(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(role) = read_str_from_toml(&toml, "organisation.role", false) {
|
if let Some(role) = read_str_from_toml(&toml, "organisation.role", false)? {
|
||||||
trace!("role = {:?}", role);
|
trace!("role = {:?}", role);
|
||||||
vcard = vcard.with_role(role);
|
vcard = vcard.with_role(role);
|
||||||
}
|
}
|
||||||
|
@ -339,29 +316,29 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
{ // parse phone
|
{ // parse phone
|
||||||
debug!("Parse phone");
|
debug!("Parse phone");
|
||||||
match toml.read("person.phone").map_err(Error::from).map_err_trace_exit_unwrap() {
|
match toml.read("person.phone")? {
|
||||||
Some(&Value::Array(ref ary)) => {
|
Some(&Value::Array(ref ary)) => {
|
||||||
for (i, element) in ary.iter().enumerate() {
|
for (i, element) in ary.iter().enumerate() {
|
||||||
let phonetype = match read_str_from_toml(element, "type", false) {
|
let phonetype = match read_str_from_toml(element, "type", false)? {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'phones.[{}].type' missing", i);
|
error!("Key 'phones.[{}].type' missing", i);
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Key 'phones.[{}].type' missing", i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let number = match read_str_from_toml(element, "number", false) {
|
let number = match read_str_from_toml(element, "number", false)? {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
error!("Key 'phones.[{}].number' missing", i);
|
error!("Key 'phones.[{}].number' missing", i);
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Key 'phones.[{}].number' missing", i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -375,10 +352,10 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Expected Array at 'phones'.");
|
error!("Expected Array at 'phones'.");
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Expected Array at 'phones'."))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -389,29 +366,29 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
{ // parse address
|
{ // parse address
|
||||||
debug!("Parsing address");
|
debug!("Parsing address");
|
||||||
match toml.read("addresses").map_err(Error::from).map_err_trace_exit_unwrap() {
|
match toml.read("addresses")? {
|
||||||
Some(&Value::Array(ref ary)) => {
|
Some(&Value::Array(ref ary)) => {
|
||||||
for (i, element) in ary.iter().enumerate() {
|
for (i, element) in ary.iter().enumerate() {
|
||||||
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);
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Key 'adresses.[{}].type' missing", i))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
};
|
};
|
||||||
trace!("adrtype = {:?}", adrtype);
|
trace!("adrtype = {:?}", adrtype);
|
||||||
|
|
||||||
let bx = read_str_from_toml(element, "box", false);
|
let bx = read_str_from_toml(element, "box", false)?;
|
||||||
let extended = read_str_from_toml(element, "extended", false);
|
let extended = read_str_from_toml(element, "extended", false)?;
|
||||||
let street = read_str_from_toml(element, "street", false);
|
let street = read_str_from_toml(element, "street", false)?;
|
||||||
let code = read_str_from_toml(element, "code", false);
|
let code = read_str_from_toml(element, "code", false)?;
|
||||||
let city = read_str_from_toml(element, "city", false);
|
let city = read_str_from_toml(element, "city", false)?;
|
||||||
let region = read_str_from_toml(element, "region", false);
|
let region = read_str_from_toml(element, "region", false)?;
|
||||||
let country = read_str_from_toml(element, "country", false);
|
let country = read_str_from_toml(element, "country", false)?;
|
||||||
|
|
||||||
trace!("bx = {:?}", bx);
|
trace!("bx = {:?}", bx);
|
||||||
trace!("extended = {:?}", extended);
|
trace!("extended = {:?}", extended);
|
||||||
|
@ -430,10 +407,10 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Type Error: Expected Array at 'addresses'");
|
error!("Type Error: Expected Array at 'addresses'");
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Type Error: Expected Array at 'addresses'"))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -444,28 +421,28 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
{ // parse email
|
{ // parse email
|
||||||
debug!("Parsing email");
|
debug!("Parsing email");
|
||||||
match toml.read("person.email").map_err(Error::from).map_err_trace_exit_unwrap() {
|
match toml.read("person.email")? {
|
||||||
Some(&Value::Array(ref ary)) => {
|
Some(&Value::Array(ref ary)) => {
|
||||||
for (i, element) in ary.iter().enumerate() {
|
for (i, element) in ary.iter().enumerate() {
|
||||||
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);
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Error: 'email.[{}].type' missing", i))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
}; // TODO: Unused, because unsupported by vobject
|
}; // TODO: Unused, because unsupported by vobject
|
||||||
|
|
||||||
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);
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Error: 'email.[{}].addr' missing", i))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
|
@ -480,10 +457,10 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
error!("Type Error: Expected Array at 'email'");
|
error!("Type Error: Expected Array at 'email'");
|
||||||
if ask_continue(input, output) {
|
if ask_continue(input, output)? {
|
||||||
return None
|
return Ok(None)
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return Err(format_err!("Type Error: Expected Array at 'email'"))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -494,19 +471,19 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
|
|
||||||
{ // parse others
|
{ // parse others
|
||||||
debug!("Parsing others");
|
debug!("Parsing others");
|
||||||
if let Some(categories) = read_strary_from_toml(&toml, "other.categories") {
|
if let Some(categories) = read_strary_from_toml(&toml, "other.categories")? {
|
||||||
vcard = vcard.with_categories(categories);
|
vcard = vcard.with_categories(categories);
|
||||||
} else {
|
} else {
|
||||||
debug!("No categories");
|
debug!("No categories");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(webpage) = read_str_from_toml(&toml, "other.webpage", false) {
|
if let Some(webpage) = read_str_from_toml(&toml, "other.webpage", false)? {
|
||||||
vcard = vcard.with_url(webpage);
|
vcard = vcard.with_url(webpage);
|
||||||
} else {
|
} else {
|
||||||
debug!("No webpage");
|
debug!("No webpage");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(note) = read_str_from_toml(&toml, "other.note", false) {
|
if let Some(note) = read_str_from_toml(&toml, "other.note", false)? {
|
||||||
vcard = vcard.with_note(note);
|
vcard = vcard.with_note(note);
|
||||||
} else {
|
} else {
|
||||||
debug!("No note");
|
debug!("No note");
|
||||||
|
@ -517,10 +494,10 @@ fn parse_toml_into_vcard(output: &mut dyn Write, input: &mut dyn Read, toml: Val
|
||||||
let vcard = vcard
|
let vcard = vcard
|
||||||
.build()
|
.build()
|
||||||
.unwrap(); // TODO: This unwrap does not fail with rust-vobject, why is there a Result<> returned?
|
.unwrap(); // TODO: This unwrap does not fail with rust-vobject, why is there a Result<> returned?
|
||||||
Some(vcard)
|
Ok(Some(vcard))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_strary_from_toml(toml: &Value, path: &'static str) -> Option<Vec<String>> {
|
fn read_strary_from_toml(toml: &Value, path: &'static str) -> Result<Option<Vec<String>>> {
|
||||||
match toml.read(path).map_err(Error::from).map_warn_err_str(&format!("Failed to read value at '{}'", path)) {
|
match toml.read(path).map_err(Error::from).map_warn_err_str(&format!("Failed to read value at '{}'", path)) {
|
||||||
Ok(Some(&Value::Array(ref vec))) => {
|
Ok(Some(&Value::Array(ref vec))) => {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
|
@ -528,48 +505,37 @@ fn read_strary_from_toml(toml: &Value, path: &'static str) -> Option<Vec<String>
|
||||||
match *elem {
|
match *elem {
|
||||||
Value::String(ref s) => v.push(s.clone()),
|
Value::String(ref s) => v.push(s.clone()),
|
||||||
_ => {
|
_ => {
|
||||||
error!("Type Error: '{}' must be Array<String>", path);
|
return Err(format_err!("Type Error: '{}' must be Array<String>", path))
|
||||||
return None
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(v)
|
Ok(Some(v))
|
||||||
}
|
}
|
||||||
Ok(Some(&Value::String(ref s))) => {
|
Ok(Some(&Value::String(ref s))) => {
|
||||||
warn!("Having String, wanting Array<String> ... going to auto-fix");
|
warn!("Having String, wanting Array<String> ... going to auto-fix");
|
||||||
Some(vec![s.clone()])
|
Ok(Some(vec![s.clone()]))
|
||||||
},
|
},
|
||||||
Ok(Some(_)) => {
|
Ok(Some(_)) => {
|
||||||
error!("Type Error: '{}' must be Array<String>", path);
|
return Err(format_err!("Type Error: '{}' must be Array<String>", path))
|
||||||
None
|
|
||||||
},
|
},
|
||||||
Ok(None) => None,
|
Ok(None) => Ok(None),
|
||||||
Err(_) => None,
|
Err(_) => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_str_from_toml(toml: &Value, path: &'static str, must_be_there: bool) -> Option<String> {
|
fn read_str_from_toml(toml: &Value, path: &'static str, must_be_there: bool) -> Result<Option<String>> {
|
||||||
let v = toml.read(path)
|
match toml.read(path)? {
|
||||||
.map_err(Error::from)
|
Some(&Value::String(ref s)) => Ok(Some(s.clone())),
|
||||||
.map_warn_err_str(&format!("Failed to read value at '{}'", path));
|
Some(_) => {
|
||||||
|
Err(format_err!("Type Error: '{}' must be String", path))
|
||||||
match v {
|
|
||||||
Ok(Some(&Value::String(ref s))) => Some(s.clone()),
|
|
||||||
Ok(Some(_)) => {
|
|
||||||
error!("Type Error: '{}' must be String", path);
|
|
||||||
None
|
|
||||||
},
|
},
|
||||||
Ok(None) => {
|
None => {
|
||||||
if must_be_there {
|
if must_be_there {
|
||||||
error!("Expected '{}' to be present, but is not.", path);
|
return Err(format_err!("Expected '{}' to be present, but is not.", path))
|
||||||
}
|
}
|
||||||
None
|
Ok(None)
|
||||||
},
|
},
|
||||||
Err(e) => {
|
|
||||||
trace_error(&e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +551,7 @@ mod test_parsing {
|
||||||
fn test_template_names() {
|
fn test_template_names() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
@ -603,7 +569,7 @@ mod test_parsing {
|
||||||
fn test_template_person() {
|
fn test_template_person() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
@ -622,7 +588,7 @@ mod test_parsing {
|
||||||
fn test_template_organization() {
|
fn test_template_organization() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
@ -640,7 +606,7 @@ mod test_parsing {
|
||||||
fn test_template_phone() {
|
fn test_template_phone() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
@ -656,7 +622,7 @@ mod test_parsing {
|
||||||
fn test_template_email() {
|
fn test_template_email() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
@ -672,7 +638,7 @@ mod test_parsing {
|
||||||
fn test_template_addresses() {
|
fn test_template_addresses() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
@ -690,7 +656,7 @@ mod test_parsing {
|
||||||
fn test_template_other() {
|
fn test_template_other() {
|
||||||
let uid = String::from("uid");
|
let uid = String::from("uid");
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid);
|
let vcard = parse_toml_into_vcard(&mut output, &mut empty(), ::toml::de::from_str(TEMPLATE).unwrap(), uid).unwrap();
|
||||||
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();
|
||||||
|
|
||||||
|
|
|
@ -32,16 +32,16 @@
|
||||||
while_true,
|
while_true,
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use failure::Error;
|
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use resiter::Filter;
|
||||||
|
use resiter::Map;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagcontact::store::ContactStore;
|
use libimagcontact::store::ContactStore;
|
||||||
use libimagentryref::reference::fassade::RefFassade;
|
use libimagentryref::reference::fassade::RefFassade;
|
||||||
|
@ -49,61 +49,56 @@ use libimagentryref::hasher::default::DefaultHasher;
|
||||||
use libimagentryref::reference::Ref;
|
use libimagentryref::reference::Ref;
|
||||||
use libimagentryref::reference::Config as RefConfig;
|
use libimagentryref::reference::Config as RefConfig;
|
||||||
|
|
||||||
pub fn edit(rt: &Runtime) {
|
pub fn edit(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("edit").unwrap();
|
let scmd = rt.cli().subcommand_matches("edit").unwrap();
|
||||||
let collection_name = rt.cli().value_of("contact-ref-collection-name").unwrap(); // default by clap
|
let collection_name = rt.cli().value_of("contact-ref-collection-name").unwrap(); // default by clap
|
||||||
let ref_config = libimagentryref::util::get_ref_config(&rt, "imag-contact").map_err_trace_exit_unwrap();
|
let ref_config = libimagentryref::util::get_ref_config(&rt, "imag-contact")?;
|
||||||
let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap
|
let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap
|
||||||
let force_override = true; // when editing, we want to override, right?
|
let force_override = true; // when editing, we want to override, right?
|
||||||
let retry = !scmd.is_present("fail-on-parse-error");
|
let retry = !scmd.is_present("fail-on-parse-error");
|
||||||
|
|
||||||
if rt.output_is_pipe() {
|
if rt.output_is_pipe() {
|
||||||
error!("Cannot spawn editor if output is a pipe!");
|
return Err(err_msg("Cannot spawn editor if output is a pipe!"))
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output = rt.stdout();
|
let mut output = rt.stdout();
|
||||||
let mut input = rt.stdin().unwrap_or_else(|| {
|
let mut input = rt.stdin().ok_or_else(|| {
|
||||||
error!("No input stream. Cannot ask for permission.");
|
err_msg("No input stream. Cannot ask for permission.")
|
||||||
exit(1)
|
})?;
|
||||||
});
|
|
||||||
|
|
||||||
crate::util::find_contact_by_hash(rt, hash)
|
crate::util::find_contact_by_hash(rt, hash)?
|
||||||
.for_each(|contact| {
|
.filter_ok(|tpl| tpl.0)
|
||||||
|
.map_ok(|tpl| tpl.1)
|
||||||
|
.and_then_ok(|contact| {
|
||||||
loop {
|
loop {
|
||||||
let res = edit_contact(&rt, &contact, &ref_config, collection_name, force_override);
|
let res = edit_contact(&rt, &contact, &ref_config, collection_name, force_override);
|
||||||
|
|
||||||
if !retry {
|
if !retry {
|
||||||
res.map_err_trace_exit_unwrap();
|
return res
|
||||||
} else if ask_continue(&mut input, &mut output) {
|
} else if ask_continue(&mut input, &mut output)? {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
exit(1)
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()
|
||||||
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_contact<'a>(rt: &Runtime, contact: &FileLockEntry<'a>, ref_config: &RefConfig, collection_name: &str, force_override: bool) -> Result<()> {
|
fn edit_contact<'a>(rt: &Runtime, contact: &FileLockEntry<'a>, ref_config: &RefConfig, collection_name: &str, force_override: bool) -> Result<()> {
|
||||||
let filepath = contact
|
let filepath = contact
|
||||||
.as_ref_with_hasher::<DefaultHasher>()
|
.as_ref_with_hasher::<DefaultHasher>()
|
||||||
.get_path(ref_config)
|
.get_path(ref_config)?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let success = rt.editor()
|
let success = rt.editor()?
|
||||||
.map_err_trace_exit_unwrap()
|
.ok_or_else(|| err_msg("I have no editor configured. Cannot continue!"))?
|
||||||
.ok_or_else(|| {
|
|
||||||
err_msg("I have no editor configured. Cannot continue!")
|
|
||||||
})
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.arg(&filepath)
|
.arg(&filepath)
|
||||||
.status()
|
.status()?
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.success();
|
.success();
|
||||||
|
|
||||||
if !success {
|
if !success {
|
||||||
error!("Editor failed!");
|
return Err(err_msg("Editor failed!"))
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.store()
|
rt.store()
|
||||||
|
@ -111,8 +106,7 @@ fn edit_contact<'a>(rt: &Runtime, contact: &FileLockEntry<'a>, ref_config: &RefC
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_continue(inputstream: &mut dyn Read, outputstream: &mut dyn Write) -> bool {
|
fn ask_continue(inputstream: &mut dyn Read, outputstream: &mut dyn Write) -> Result<bool> {
|
||||||
::libimaginteraction::ask::ask_bool("Edit vcard", Some(true), inputstream, outputstream)
|
::libimaginteraction::ask::ask_bool("Edit vcard", Some(true), inputstream, outputstream)
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ extern crate walkdir;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
#[macro_use] extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
extern crate resiter;
|
||||||
|
|
||||||
extern crate libimagcontact;
|
extern crate libimagcontact;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
@ -54,7 +55,6 @@ extern crate libimaginteraction;
|
||||||
extern crate libimagentryedit;
|
extern crate libimagentryedit;
|
||||||
extern crate libimagentryref;
|
extern crate libimagentryref;
|
||||||
|
|
||||||
use std::process::exit;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
@ -67,13 +67,13 @@ use walkdir::WalkDir;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
use resiter::AndThen;
|
||||||
|
use resiter::IterInnerOkOrElse;
|
||||||
|
use resiter::Map;
|
||||||
|
use resiter::Filter;
|
||||||
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagerror::io::ToExitCode;
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagcontact::store::ContactStore;
|
use libimagcontact::store::ContactStore;
|
||||||
use libimagcontact::contact::Contact;
|
use libimagcontact::contact::Contact;
|
||||||
use libimagcontact::deser::DeserVcard;
|
use libimagcontact::deser::DeserVcard;
|
||||||
|
@ -94,26 +94,22 @@ use crate::edit::edit;
|
||||||
pub enum ImagContact {}
|
pub enum ImagContact {}
|
||||||
impl ImagApplication for ImagContact {
|
impl ImagApplication for ImagContact {
|
||||||
fn run(rt: Runtime) -> Result<()> {
|
fn run(rt: Runtime) -> Result<()> {
|
||||||
if let Some(name) = rt.cli().subcommand_name() {
|
match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
|
||||||
debug!("Call {}", name);
|
"list" => list(&rt),
|
||||||
match name {
|
"import" => import(&rt),
|
||||||
"list" => list(&rt),
|
"show" => show(&rt),
|
||||||
"import" => import(&rt),
|
"edit" => edit(&rt),
|
||||||
"show" => show(&rt),
|
"find" => find(&rt),
|
||||||
"edit" => edit(&rt),
|
"create" => create(&rt),
|
||||||
"find" => find(&rt),
|
other => {
|
||||||
"create" => create(&rt),
|
debug!("Unknown command");
|
||||||
other => {
|
if rt.handle_unknown_subcommand("imag-contact", other, rt.cli())?.success() {
|
||||||
debug!("Unknown command");
|
Ok(())
|
||||||
let _ = rt.handle_unknown_subcommand("imag-contact", other, rt.cli())
|
} else {
|
||||||
.map_err_trace_exit_unwrap()
|
Err(err_msg("Failed to handle unknown subcommand"))
|
||||||
.code()
|
}
|
||||||
.map(::std::process::exit);
|
},
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
|
@ -133,128 +129,117 @@ impl ImagApplication for ImagContact {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(rt: &Runtime) {
|
fn list(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("list").unwrap();
|
let scmd = rt.cli().subcommand_matches("list").unwrap();
|
||||||
let list_format = get_contact_print_format("contact.list_format", rt, &scmd);
|
let list_format = get_contact_print_format("contact.list_format", rt, &scmd)?;
|
||||||
debug!("List format: {:?}", list_format);
|
debug!("List format: {:?}", list_format);
|
||||||
|
|
||||||
let iterator = rt
|
let iterator = rt
|
||||||
.store()
|
.store()
|
||||||
.all_contacts()
|
.all_contacts()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
|
||||||
.map(|fle| fle.ok_or_else(|| err_msg("StoreId not found".to_owned())))
|
.and_then_ok(|fle| {
|
||||||
.trace_unwrap_exit()
|
rt.report_touched(fle.get_location())?;
|
||||||
.map(|fle| {
|
Ok(fle)
|
||||||
rt.report_touched(fle.get_location()).unwrap_or_exit();
|
|
||||||
fle
|
|
||||||
})
|
})
|
||||||
.map(|e| e.deser())
|
.and_then_ok(|e| e.deser());
|
||||||
.trace_unwrap_exit()
|
|
||||||
.enumerate();
|
|
||||||
|
|
||||||
if scmd.is_present("json") {
|
if scmd.is_present("json") {
|
||||||
debug!("Listing as JSON");
|
debug!("Listing as JSON");
|
||||||
let v : Vec<DeserVcard> = iterator.map(|tpl| tpl.1).collect();
|
let v = iterator.collect::<Result<Vec<DeserVcard>>>()?;
|
||||||
|
let s = ::serde_json::to_string(&v)?;
|
||||||
match ::serde_json::to_string(&v) {
|
writeln!(rt.stdout(), "{}", s).map_err(Error::from)
|
||||||
Ok(s) => writeln!(rt.stdout(), "{}", s).to_exit_code().unwrap_or_exit(),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Error generating JSON: {:?}", e);
|
|
||||||
::std::process::exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
debug!("Not listing as JSON");
|
debug!("Not listing as JSON");
|
||||||
let output = rt.stdout();
|
let output = rt.stdout();
|
||||||
let mut output = output.lock();
|
let mut output = output.lock();
|
||||||
|
let mut i = 0;
|
||||||
iterator
|
iterator
|
||||||
.map(|(i, dvcard)| build_data_object_for_handlebars(i, &dvcard))
|
.map_ok(|dvcard| {
|
||||||
.map(|data| list_format.render("format", &data).map_err(Error::from))
|
i += 1;
|
||||||
.trace_unwrap_exit()
|
build_data_object_for_handlebars(i, &dvcard)
|
||||||
.for_each(|s| {
|
})
|
||||||
writeln!(output, "{}", s).to_exit_code().unwrap_or_exit()
|
.and_then_ok(|data| list_format.render("format", &data).map_err(Error::from))
|
||||||
});
|
.and_then_ok(|s| writeln!(output, "{}", s).map_err(Error::from))
|
||||||
|
.collect::<Result<Vec<_>>>()
|
||||||
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import(rt: &Runtime) {
|
fn import(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("import").unwrap(); // secured by main
|
let scmd = rt.cli().subcommand_matches("import").unwrap(); // secured by main
|
||||||
let force_override = scmd.is_present("force-override");
|
let force_override = scmd.is_present("force-override");
|
||||||
let path = scmd.value_of("path").map(PathBuf::from).unwrap(); // secured by clap
|
let path = scmd.value_of("path").map(PathBuf::from).unwrap(); // secured by clap
|
||||||
|
|
||||||
let collection_name = rt.cli().value_of("contact-ref-collection-name").unwrap(); // default by clap
|
let collection_name = rt.cli().value_of("contact-ref-collection-name").unwrap(); // default by clap
|
||||||
let ref_config = rt.config()
|
let ref_config = rt.config()
|
||||||
.ok_or_else(|| format_err!("No configuration, cannot continue!"))
|
.ok_or_else(|| format_err!("No configuration, cannot continue!"))?
|
||||||
.map_err_trace_exit_unwrap()
|
.read_partial::<libimagentryref::reference::Config>()?
|
||||||
.read_partial::<libimagentryref::reference::Config>()
|
.ok_or_else(|| format_err!("Configuration missing: {}", libimagentryref::reference::Config::LOCATION))?;
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.ok_or_else(|| format_err!("Configuration missing: {}", libimagentryref::reference::Config::LOCATION))
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
// TODO: Refactor the above to libimagutil or libimagrt?
|
// TODO: Refactor the above to libimagutil or libimagrt?
|
||||||
|
|
||||||
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
error!("Path does not exist");
|
return Err(format_err!("Path does not exist: {}", path.display()))
|
||||||
exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
let entry = rt
|
let entry = rt
|
||||||
.store()
|
.store()
|
||||||
.retrieve_from_path(&path, &ref_config, &collection_name, force_override)
|
.retrieve_from_path(&path, &ref_config, &collection_name, force_override)?;
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
rt.report_touched(entry.get_location()).map_err(Error::from)
|
||||||
} else if path.is_dir() {
|
} else if path.is_dir() {
|
||||||
for entry in WalkDir::new(path).min_depth(1).into_iter() {
|
WalkDir::new(path)
|
||||||
let entry = entry
|
.min_depth(1)
|
||||||
.map_err(Error::from)
|
.into_iter()
|
||||||
.map_err_trace_exit_unwrap();
|
.map(|r| r.map_err(Error::from))
|
||||||
|
.and_then_ok(|entry| {
|
||||||
|
if entry.file_type().is_file() {
|
||||||
|
let pb = PathBuf::from(entry.path());
|
||||||
|
let fle = rt
|
||||||
|
.store()
|
||||||
|
.retrieve_from_path(&pb, &ref_config, &collection_name, force_override)?;
|
||||||
|
|
||||||
if entry.file_type().is_file() {
|
rt.report_touched(fle.get_location())?;
|
||||||
let pb = PathBuf::from(entry.path());
|
info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
|
||||||
let fle = rt
|
Ok(())
|
||||||
.store()
|
} else {
|
||||||
.retrieve_from_path(&pb, &ref_config, &collection_name, force_override)
|
warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
|
||||||
.map_err_trace_exit_unwrap();
|
Ok(())
|
||||||
|
}
|
||||||
rt.report_touched(fle.get_location()).unwrap_or_exit();
|
})
|
||||||
info!("Imported: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
|
.collect::<Result<Vec<_>>>()
|
||||||
} else {
|
.map(|_| ())
|
||||||
warn!("Ignoring non-file: {}", entry.path().to_str().unwrap_or("<non UTF-8 path>"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error!("Path is neither directory nor file");
|
Err(err_msg("Path is neither directory nor file"))
|
||||||
exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(rt: &Runtime) {
|
fn show(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("show").unwrap();
|
let scmd = rt.cli().subcommand_matches("show").unwrap();
|
||||||
let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap
|
let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap
|
||||||
let show_format = get_contact_print_format("contact.show_format", rt, &scmd);
|
let show_format = get_contact_print_format("contact.show_format", rt, &scmd)?;
|
||||||
let out = rt.stdout();
|
let out = rt.stdout();
|
||||||
let mut outlock = out.lock();
|
let mut outlock = out.lock();
|
||||||
|
|
||||||
util::find_contact_by_hash(rt, hash)
|
util::find_contact_by_hash(rt, hash)?
|
||||||
|
.filter_ok(|tpl| tpl.0)
|
||||||
|
.map_ok(|tpl| tpl.1)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, elem)| {
|
.map(|(i, elem)| {
|
||||||
let elem = elem.deser().map_err_trace_exit_unwrap();
|
let elem = elem?.deser()?;
|
||||||
let data = build_data_object_for_handlebars(i, &elem);
|
let data = build_data_object_for_handlebars(i, &elem);
|
||||||
|
|
||||||
let s = show_format
|
let s = show_format.render("format", &data)?;
|
||||||
.render("format", &data)
|
writeln!(outlock, "{}", s).map_err(Error::from)
|
||||||
.map_err(Error::from)
|
})
|
||||||
.map_err_trace_exit_unwrap();
|
.collect::<Result<Vec<_>>>()
|
||||||
writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit();
|
.map(|_| ())
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find(rt: &Runtime) {
|
fn find(rt: &Runtime) -> Result<()> {
|
||||||
let scmd = rt.cli().subcommand_matches("find").unwrap();
|
let scmd = rt.cli().subcommand_matches("find").unwrap();
|
||||||
let grepstring = scmd
|
let grepstring = scmd
|
||||||
.values_of("string")
|
.values_of("string")
|
||||||
|
@ -263,24 +248,16 @@ fn find(rt: &Runtime) {
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
// We don't know yet which we need, but we pay that price for simplicity of the codebase
|
// We don't know yet which we need, but we pay that price for simplicity of the codebase
|
||||||
let show_format = get_contact_print_format("contact.show_format", rt, &scmd);
|
let show_format = get_contact_print_format("contact.show_format", rt, &scmd)?;
|
||||||
let list_format = get_contact_print_format("contact.list_format", rt, &scmd);
|
let list_format = get_contact_print_format("contact.list_format", rt, &scmd)?;
|
||||||
|
|
||||||
let iterator = rt
|
let iterator = rt
|
||||||
.store()
|
.store()
|
||||||
.all_contacts()
|
.all_contacts()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.map(|el| {
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
|
||||||
el.map_err_trace_exit_unwrap()
|
.and_then_ok(|entry| {
|
||||||
.ok_or_else(|| {
|
let card = entry.deser()?;
|
||||||
error!("Could not get StoreId from Store::all_contacts(). This is a BUG!");
|
|
||||||
::std::process::exit(1)
|
|
||||||
})
|
|
||||||
.unwrap() // safed above
|
|
||||||
})
|
|
||||||
.filter_map(|entry| {
|
|
||||||
let card = entry.deser().map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let str_contains_any = |s: &String, v: &Vec<String>| {
|
let str_contains_any = |s: &String, v: &Vec<String>| {
|
||||||
v.iter().any(|i| s.contains(i))
|
v.iter().any(|i| s.contains(i))
|
||||||
|
@ -291,91 +268,94 @@ fn find(rt: &Runtime) {
|
||||||
|| card.fullname().iter().any(|a| str_contains_any(a, &grepstring));
|
|| card.fullname().iter().any(|a| str_contains_any(a, &grepstring));
|
||||||
|
|
||||||
if take {
|
if take {
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
rt.report_touched(entry.get_location())?;
|
||||||
|
|
||||||
// optimization so we don't have to parse again in the next step
|
// optimization so we don't have to parse again in the next step
|
||||||
Some((entry, card))
|
Ok((true, entry, card))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok((false, entry, card))
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.enumerate();
|
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
if !rt.output_is_pipe() || rt.ignore_ids() {
|
if !rt.output_is_pipe() || rt.ignore_ids() {
|
||||||
if scmd.is_present("json") {
|
if scmd.is_present("json") {
|
||||||
let v : Vec<DeserVcard> = iterator.map(|(_, tlp)| tlp.1).collect();
|
iterator
|
||||||
|
.filter_ok(|tpl| tpl.0)
|
||||||
match ::serde_json::to_string(&v) {
|
.map_ok(|tpl| tpl.2)
|
||||||
Ok(s) => writeln!(rt.stdout(), "{}", s).to_exit_code().unwrap_or_exit(),
|
.and_then_ok(|v| {
|
||||||
Err(e) => {
|
let s = ::serde_json::to_string(&v)?;
|
||||||
error!("Error generating JSON: {:?}", e);
|
writeln!(rt.stdout(), "{}", s).map_err(Error::from)
|
||||||
::std::process::exit(1)
|
})
|
||||||
}
|
.collect::<Result<Vec<_>>>()
|
||||||
}
|
.map(|_| ())
|
||||||
} else if scmd.is_present("find-id") {
|
} else if scmd.is_present("find-id") {
|
||||||
iterator
|
iterator
|
||||||
.for_each(|(_i, (entry, _))| {
|
.and_then_ok(|(take, entry, _)| {
|
||||||
writeln!(rt.stdout(), "{}", entry.get_location())
|
if take {
|
||||||
.to_exit_code()
|
writeln!(rt.stdout(), "{}", entry.get_location()).map_err(Error::from)
|
||||||
.unwrap_or_exit();
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()
|
||||||
|
.map(|_| ())
|
||||||
} else if scmd.is_present("find-full-id") {
|
} else if scmd.is_present("find-full-id") {
|
||||||
let storepath = rt.store().path().display();
|
let storepath = rt.store().path().display();
|
||||||
iterator
|
iterator
|
||||||
.for_each(|(_i, (entry, _))| {
|
.and_then_ok(|(take, entry, _)| {
|
||||||
writeln!(rt.stdout(), "{}/{}", storepath, entry.get_location())
|
if take {
|
||||||
.to_exit_code()
|
writeln!(rt.stdout(), "{}/{}", storepath, entry.get_location()).map_err(Error::from)
|
||||||
.unwrap_or_exit();
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()
|
||||||
|
.map(|_| ())
|
||||||
} else {
|
} else {
|
||||||
iterator
|
iterator
|
||||||
.for_each(|(i, (_, card))| {
|
.and_then_ok(|(take, _, card)| {
|
||||||
let fmt = if scmd.is_present("find-show") {
|
if take {
|
||||||
&show_format
|
i += 1;
|
||||||
} else { // default: find-list
|
let fmt = if scmd.is_present("find-show") {
|
||||||
&list_format
|
&show_format
|
||||||
};
|
} else { // default: find-list
|
||||||
|
&list_format
|
||||||
|
};
|
||||||
|
|
||||||
let data = build_data_object_for_handlebars(i, &card);
|
let data = build_data_object_for_handlebars(i, &card);
|
||||||
let s = fmt
|
let s = fmt.render("format", &data)?;
|
||||||
.render("format", &data)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
writeln!(rt.stdout(), "{}", s)
|
writeln!(rt.stdout(), "{}", s).map_err(Error::from)
|
||||||
.to_exit_code()
|
} else {
|
||||||
.unwrap_or_exit();
|
Ok(())
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()
|
||||||
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
} else { // if not printing, we still have to consume the iterator to report the touched IDs
|
} else { // if not printing, we still have to consume the iterator to report the touched IDs
|
||||||
let _ = iterator.collect::<Vec<_>>();
|
let _ = iterator.collect::<Vec<_>>();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Handlebars {
|
fn get_contact_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Result<Handlebars> {
|
||||||
let fmt = scmd
|
let fmt = match scmd.value_of("format").map(String::from) {
|
||||||
.value_of("format")
|
Some(s) => Ok(s),
|
||||||
.map(String::from)
|
None => rt.config()
|
||||||
.unwrap_or_else(|| {
|
.ok_or_else(|| err_msg("No configuration file"))?
|
||||||
rt.config()
|
.read_string(config_value_path)?
|
||||||
.ok_or_else(|| err_msg("No configuration file"))
|
.ok_or_else(|| err_msg("Configuration 'contact.list_format' does not exist")),
|
||||||
.map_err_trace_exit_unwrap()
|
}?;
|
||||||
.read_string(config_value_path)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.ok_or_else(|| err_msg("Configuration 'contact.list_format' does not exist"))
|
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut hb = Handlebars::new();
|
let mut hb = Handlebars::new();
|
||||||
hb
|
hb.register_template_string("format", fmt)?;
|
||||||
.register_template_string("format", fmt)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
hb.register_escape_fn(::handlebars::no_escape);
|
hb.register_escape_fn(::handlebars::no_escape);
|
||||||
::libimaginteraction::format::register_all_color_helpers(&mut hb);
|
::libimaginteraction::format::register_all_color_helpers(&mut hb);
|
||||||
::libimaginteraction::format::register_all_format_helpers(&mut hb);
|
::libimaginteraction::format::register_all_format_helpers(&mut hb);
|
||||||
hb
|
Ok(hb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,15 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::process::exit;
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::err_msg;
|
||||||
|
use resiter::IterInnerOkOrElse;
|
||||||
|
use resiter::AndThen;
|
||||||
|
|
||||||
use libimagcontact::deser::DeserVcard;
|
use libimagcontact::deser::DeserVcard;
|
||||||
use libimagcontact::store::ContactStore;
|
use libimagcontact::store::ContactStore;
|
||||||
use libimagcontact::contact::Contact;
|
use libimagcontact::contact::Contact;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
|
||||||
use libimagerror::iter::TraceIterator;
|
|
||||||
use libimagerror::trace::MapErrTrace;
|
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
|
|
||||||
|
@ -85,34 +86,24 @@ pub fn build_data_object_for_handlebars(i: usize, vcard: &DeserVcard) -> BTreeMa
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_contact_by_hash<'a, H: AsRef<str>>(rt: &'a Runtime, hash: H)
|
pub fn find_contact_by_hash<'a, H: AsRef<str>>(rt: &'a Runtime, hash: H)
|
||||||
-> impl Iterator<Item = FileLockEntry<'a>>
|
-> Result<impl Iterator<Item = Result<(bool, FileLockEntry<'a>)>>>
|
||||||
{
|
{
|
||||||
rt.store()
|
Ok(rt.store()
|
||||||
.all_contacts()
|
.all_contacts()?
|
||||||
.map_err_trace_exit_unwrap()
|
|
||||||
.into_get_iter()
|
.into_get_iter()
|
||||||
.trace_unwrap_exit()
|
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
|
||||||
.map(|o| o.unwrap_or_else(|| {
|
.and_then_ok(move |entry| {
|
||||||
error!("Failed to get entry");
|
let deser = entry.deser()?;
|
||||||
exit(1)
|
|
||||||
}))
|
|
||||||
.filter(move |entry| {
|
|
||||||
let deser = entry.deser().map_err_trace_exit_unwrap();
|
|
||||||
|
|
||||||
let id_starts_with_hash = deser.uid()
|
let id_starts_with_hash = deser.uid()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| err_msg("Could not get StoreId from Store::all_contacts(). This is a BUG!"))?
|
||||||
error!("Could not get StoreId from Store::all_contacts(). This is a BUG!");
|
|
||||||
::std::process::exit(1)
|
|
||||||
})
|
|
||||||
.unwrap() // exited above
|
|
||||||
.starts_with(hash.as_ref());
|
.starts_with(hash.as_ref());
|
||||||
|
|
||||||
if id_starts_with_hash {
|
if id_starts_with_hash {
|
||||||
rt.report_touched(entry.get_location()).unwrap_or_exit();
|
rt.report_touched(entry.get_location())?;
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
Ok((id_starts_with_hash, entry))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue