use clap::{self, ErrorKind};
use entry;
use lich::{Data, OpenData};
use serde_json;
use std::error::Error;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::Path;
#[macro_export]
macro_rules! wlnerr {
($($args:tt)*) => {{
use ::std::io::Write;
let _ = writeln!(&mut ::std::io::stderr(), $($args)*);
}}
}
pub fn decode<R: Read>(file: R, path: &Path) -> Result<Data, clap::Error> {
serde_json::from_reader(file)
.map_err(|e| read_error(path, e))
}
pub fn unlock<'a, F, T>(data: &'a mut Data, cb: F) -> T
where F: for<'x> FnOnce(OpenData<'x>) -> T {
loop {
let password = entry::master_password();
if let Ok(unlocked) = data.unlock(&password) {
return cb(unlocked);
}
wlnerr!("Incorrect password; try again.");
}
}
pub fn create_error<E: Error>(path: &Path, e: E) -> clap::Error {
error(&format!(
"could not create {} - {}",
path.display(),
e.description()
))
}
pub fn read_error<E: Error>(path: &Path, e: E) -> clap::Error {
error(&format!(
"could not read {} - {}",
path.display(),
e.description()
))
}
pub fn write_error<E: Error>(path: &Path, e: E) -> clap::Error {
error(&format!(
"could not update {} - {}",
path.display(),
e.description()
))
}
pub fn error(msg: &str) -> clap::Error {
clap::Error::with_description(msg, ErrorKind::Io)
}
pub fn save(
file: &mut File,
path: &Path,
data: &Data
) -> Result<(), clap::Error> {
file.seek(SeekFrom::Start(0))
.and_then(|_| file.set_len(0))
.map_err(|e| write_error(path, e))?;
serde_json::to_writer(file, data)
.map_err(|e| write_error(path, e))?;
Ok(())
}