Merge branch 'libimagcontact-with-ref' into master
This commit is contained in:
commit
1861f6545d
8 changed files with 135 additions and 24 deletions
|
@ -24,7 +24,6 @@ maintenance = { status = "actively-developed" }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.0"
|
log = "0.4.0"
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
toml-query = "0.8"
|
|
||||||
vobject = "0.7"
|
vobject = "0.7"
|
||||||
handlebars = "1.0"
|
handlebars = "1.0"
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
|
@ -46,3 +45,9 @@ version = "^2.29"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["color", "suggestions", "wrap_help"]
|
features = ["color", "suggestions", "wrap_help"]
|
||||||
|
|
||||||
|
[dependencies.toml-query]
|
||||||
|
#version = "0.8"
|
||||||
|
default-features = false
|
||||||
|
features = ["typed"]
|
||||||
|
git = "https://github.com/matthiasbeyer/toml-query"
|
||||||
|
branch = "master"
|
||||||
|
|
|
@ -43,9 +43,11 @@ use vobject::vcard::Vcard;
|
||||||
use vobject::vcard::VcardBuilder;
|
use vobject::vcard::VcardBuilder;
|
||||||
use vobject::write_component;
|
use vobject::write_component;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
use toml_query::read::Partial;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagcontact::store::ContactStore;
|
use libimagcontact::store::ContactStore;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
|
@ -80,8 +82,20 @@ fn ask_continue(inputstream: &mut Read, outputstream: &mut Write) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(rt: &Runtime) {
|
pub fn create(rt: &Runtime) {
|
||||||
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 = String::from(collection_name);
|
||||||
|
let ref_config = rt // TODO: Re-Deserialize to libimagentryref::reference::Config
|
||||||
|
.config()
|
||||||
|
.ok_or_else(|| err_msg("Configuration missing, cannot continue!"))
|
||||||
|
.map_err_trace_exit_unwrap()
|
||||||
|
.read_partial::<libimagentryref::reference::Config>()
|
||||||
|
.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?
|
||||||
|
|
||||||
let (mut dest, location, uuid) : (Box<Write>, Option<PathBuf>, String) = {
|
let (mut dest, location, uuid) : (Box<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) {
|
||||||
|
@ -202,7 +216,7 @@ 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)
|
.create_from_path(&location, &ref_config, &collection_name)
|
||||||
.map_err_trace_exit_unwrap();
|
.map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
let _ = rt.report_touched(entry.get_location()).unwrap_or_exit();
|
let _ = rt.report_touched(entry.get_location()).unwrap_or_exit();
|
||||||
|
|
|
@ -43,7 +43,7 @@ extern crate handlebars;
|
||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
extern crate libimagcontact;
|
extern crate libimagcontact;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
@ -59,7 +59,9 @@ use std::io::Write;
|
||||||
|
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
use toml_query::read::TomlValueReadExt;
|
||||||
use toml_query::read::TomlValueReadTypeExt;
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
|
use toml_query::read::Partial;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
@ -158,6 +160,18 @@ fn import(rt: &Runtime) {
|
||||||
let scmd = rt.cli().subcommand_matches("import").unwrap(); // secured by main
|
let scmd = rt.cli().subcommand_matches("import").unwrap(); // secured by main
|
||||||
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 ref_config = rt.config()
|
||||||
|
.ok_or_else(|| format_err!("No configuration, cannot continue!"))
|
||||||
|
.map_err_trace_exit_unwrap()
|
||||||
|
.read_partial::<libimagentryref::reference::Config>()
|
||||||
|
.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?
|
||||||
|
|
||||||
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
error!("Path does not exist");
|
error!("Path does not exist");
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -166,7 +180,7 @@ fn import(rt: &Runtime) {
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
let entry = rt
|
let entry = rt
|
||||||
.store()
|
.store()
|
||||||
.retrieve_from_path(&path)
|
.retrieve_from_path(&path, &ref_config, &collection_name)
|
||||||
.map_err_trace_exit_unwrap();
|
.map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
let _ = rt.report_touched(entry.get_location()).unwrap_or_exit();
|
let _ = rt.report_touched(entry.get_location()).unwrap_or_exit();
|
||||||
|
@ -180,7 +194,7 @@ fn import(rt: &Runtime) {
|
||||||
let pb = PathBuf::from(entry.path());
|
let pb = PathBuf::from(entry.path());
|
||||||
let fle = rt
|
let fle = rt
|
||||||
.store()
|
.store()
|
||||||
.retrieve_from_path(&pb)
|
.retrieve_from_path(&pb, &ref_config, &collection_name)
|
||||||
.map_err_trace_exit_unwrap();
|
.map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
let _ = rt.report_touched(fle.get_location()).unwrap_or_exit();
|
let _ = rt.report_touched(fle.get_location()).unwrap_or_exit();
|
||||||
|
|
|
@ -21,6 +21,14 @@ use clap::{Arg, App, SubCommand};
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
app
|
app
|
||||||
|
.arg(Arg::with_name("contact-ref-collection-name")
|
||||||
|
.long("ref-collection")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(false)
|
||||||
|
.multiple(false)
|
||||||
|
.default_value("contacts")
|
||||||
|
.help("Name (Key) of the basepath setting in the configuration file to use"))
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("list")
|
.subcommand(SubCommand::with_name("list")
|
||||||
.about("List contacts")
|
.about("List contacts")
|
||||||
.version("0.1")
|
.version("0.1")
|
||||||
|
@ -56,6 +64,7 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
.multiple(false)
|
.multiple(false)
|
||||||
.value_name("PATH")
|
.value_name("PATH")
|
||||||
.help("Import from this file/directory"))
|
.help("Import from this file/directory"))
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("show")
|
.subcommand(SubCommand::with_name("show")
|
||||||
|
|
|
@ -356,6 +356,7 @@ execute_in_store = false
|
||||||
[ref.basepathes]
|
[ref.basepathes]
|
||||||
music = "/home/user/music"
|
music = "/home/user/music"
|
||||||
mail = "/home/user/mail"
|
mail = "/home/user/mail"
|
||||||
|
contacts = "/home/user/contacts"
|
||||||
|
|
||||||
[mail]
|
[mail]
|
||||||
# The name of the mail reference collection
|
# The name of the mail reference collection
|
||||||
|
|
|
@ -31,5 +31,6 @@ serde_derive = "1"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
||||||
libimagentryutil = { version = "0.10.0", path = "../../../lib/entry/libimagentryutil/" }
|
libimagentryutil = { version = "0.10.0", path = "../../../lib/entry/libimagentryutil/" }
|
||||||
|
libimagentryref = { version = "0.10.0", path = "../../../lib/entry/libimagentryref/" }
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ extern crate serde;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagstore;
|
#[macro_use] extern crate libimagstore;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
|
extern crate libimagentryref;
|
||||||
#[macro_use] extern crate libimagentryutil;
|
#[macro_use] extern crate libimagentryutil;
|
||||||
|
|
||||||
module_entry_path_mod!("contact");
|
module_entry_path_mod!("contact");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use toml::to_string as toml_to_string;
|
use toml::to_string as toml_to_string;
|
||||||
|
@ -32,6 +33,7 @@ use libimagstore::iter::Entries;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagentryutil::isa::Is;
|
use libimagentryutil::isa::Is;
|
||||||
|
use libimagentryref::reference::{MutRef, Config as RefConfig};
|
||||||
|
|
||||||
use contact::IsContact;
|
use contact::IsContact;
|
||||||
use deser::DeserVcard;
|
use deser::DeserVcard;
|
||||||
|
@ -39,13 +41,23 @@ use util;
|
||||||
|
|
||||||
pub trait ContactStore<'a> {
|
pub trait ContactStore<'a> {
|
||||||
|
|
||||||
// creating
|
fn create_from_path<CN>(&'a self, p: &PathBuf, rc: &RefConfig, collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>;
|
||||||
|
|
||||||
fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
|
fn retrieve_from_path<CN>(&'a self, p: &PathBuf, rc: &RefConfig, collection_name: CN)
|
||||||
fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>;
|
||||||
|
|
||||||
fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
|
fn create_from_buf<CN, P>(&'a self, buf: &str, path: P, rc: &RefConfig, collection_name: CN)
|
||||||
fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>,
|
||||||
|
P: AsRef<Path>;
|
||||||
|
|
||||||
|
fn retrieve_from_buf<CN, P>(&'a self, buf: &str, path: P, rc: &RefConfig, collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>,
|
||||||
|
P: AsRef<Path>;
|
||||||
|
|
||||||
// getting
|
// getting
|
||||||
|
|
||||||
|
@ -55,23 +67,58 @@ pub trait ContactStore<'a> {
|
||||||
/// The extension for the Store to work with contacts
|
/// The extension for the Store to work with contacts
|
||||||
impl<'a> ContactStore<'a> for Store {
|
impl<'a> ContactStore<'a> for Store {
|
||||||
|
|
||||||
fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
|
/// Create a contact from a filepath
|
||||||
util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf))
|
///
|
||||||
|
/// Uses the collection with `collection_name` from RefConfig to store the reference to the
|
||||||
|
/// file.
|
||||||
|
fn create_from_path<CN>(&'a self, p: &PathBuf, rc: &RefConfig, collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>
|
||||||
|
{
|
||||||
|
util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf, p, rc, collection_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
|
/// Retrieve a contact from a filepath
|
||||||
util::read_to_string(p).and_then(|buf| self.retrieve_from_buf(&buf))
|
///
|
||||||
|
/// Uses the collection with `collection_name` from RefConfig to store the reference to the
|
||||||
|
/// file.
|
||||||
|
fn retrieve_from_path<CN>(&'a self, p: &PathBuf, rc: &RefConfig, collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>
|
||||||
|
{
|
||||||
|
util::read_to_string(p).and_then(|buf| self.retrieve_from_buf(&buf, p, rc, collection_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create contact ref from buffer
|
/// Create a contact from a buffer
|
||||||
fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
|
///
|
||||||
|
/// Uses the collection with `collection_name` from RefConfig to store the reference to the
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// Needs the `path` passed where the buffer was read from, because we want to create a
|
||||||
|
/// reference to it.
|
||||||
|
fn create_from_buf<CN, P>(&'a self, buf: &str, path: P, rc: &RefConfig, collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>,
|
||||||
|
P: AsRef<Path>
|
||||||
|
{
|
||||||
let (sid, value) = prepare_fetching_from_store(buf)?;
|
let (sid, value) = prepare_fetching_from_store(buf)?;
|
||||||
postprocess_fetched_entry(self.create(sid)?, value)
|
postprocess_fetched_entry(self.create(sid)?, value, path, rc, collection_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
|
/// Retrieve a contact from a buffer
|
||||||
|
///
|
||||||
|
/// Uses the collection with `collection_name` from RefConfig to store the reference to the
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// Needs the `path` passed where the buffer was read from, because we want to create a
|
||||||
|
/// reference to it.
|
||||||
|
fn retrieve_from_buf<CN, P>(&'a self, buf: &str, path: P, rc: &RefConfig, collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>,
|
||||||
|
P: AsRef<Path>
|
||||||
|
{
|
||||||
let (sid, value) = prepare_fetching_from_store(buf)?;
|
let (sid, value) = prepare_fetching_from_store(buf)?;
|
||||||
postprocess_fetched_entry(self.retrieve(sid)?, value)
|
postprocess_fetched_entry(self.retrieve(sid)?, value, path, rc, collection_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_contacts(&'a self) -> Result<Entries<'a>> {
|
fn all_contacts(&'a self) -> Result<Entries<'a>> {
|
||||||
|
@ -101,10 +148,29 @@ fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
|
||||||
Ok((sid, value))
|
Ok((sid, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Postprocess the entry just fetched from the store
|
/// Postprocess the entry just fetched (created or retrieved) from the store
|
||||||
fn postprocess_fetched_entry<'a>(mut entry: FileLockEntry<'a>, value: Value) -> Result<FileLockEntry<'a>> {
|
///
|
||||||
|
/// We need the path, the refconfig and the collection name passed here because we create a
|
||||||
|
/// reference here.
|
||||||
|
///
|
||||||
|
/// This is marked as inline because what it does is trivial, but repetitve in this module.
|
||||||
|
#[inline]
|
||||||
|
fn postprocess_fetched_entry<'a, CN, P>(mut entry: FileLockEntry<'a>,
|
||||||
|
value: Value,
|
||||||
|
path: P,
|
||||||
|
rc: &RefConfig,
|
||||||
|
collection_name: CN)
|
||||||
|
-> Result<FileLockEntry<'a>>
|
||||||
|
where CN: AsRef<str>,
|
||||||
|
P: AsRef<Path>
|
||||||
|
{
|
||||||
|
use libimagentryref::reference::RefFassade;
|
||||||
|
use libimagentryref::hasher::sha1::Sha1Hasher;
|
||||||
|
|
||||||
entry.set_isflag::<IsContact>()?;
|
entry.set_isflag::<IsContact>()?;
|
||||||
entry.get_header_mut().insert("contact.data", value)?;
|
entry.get_header_mut().insert("contact.data", value)?;
|
||||||
|
entry.as_ref_with_hasher_mut::<Sha1Hasher>().make_ref(path, collection_name, rc, false)?;
|
||||||
|
|
||||||
Ok(entry)
|
Ok(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue