~matthiasbeyer/imag

1861f6545d9aded830a7f7f20c6fc51ebc639373 — Matthias Beyer 2 years ago a410486 + 9b7edfc
Merge branch 'libimagcontact-with-ref' into master
M bin/domain/imag-contact/Cargo.toml => bin/domain/imag-contact/Cargo.toml +6 -1
@@ 24,7 24,6 @@ maintenance                       = { status     = "actively-developed" }
[dependencies]
log = "0.4.0"
toml = "0.4"
toml-query = "0.8"
vobject    = "0.7"
handlebars = "1.0"
walkdir = "2"


@@ 46,3 45,9 @@ version = "^2.29"
default-features = false
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"

M bin/domain/imag-contact/src/create.rs => bin/domain/imag-contact/src/create.rs +17 -3
@@ 43,9 43,11 @@ use vobject::vcard::Vcard;
use vobject::vcard::VcardBuilder;
use vobject::write_component;
use toml_query::read::TomlValueReadExt;
use toml_query::read::Partial;
use toml::Value;
use uuid::Uuid;
use failure::Error;
use failure::err_msg;

use libimagcontact::store::ContactStore;
use libimagrt::runtime::Runtime;


@@ 80,8 82,20 @@ fn ask_continue(inputstream: &mut Read, outputstream: &mut Write) -> bool {
}

pub fn create(rt: &Runtime) {
    let scmd         = rt.cli().subcommand_matches("create").unwrap();
    let mut template = String::from(TEMPLATE);
    let scmd            = rt.cli().subcommand_matches("create").unwrap();
    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) = {
        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 !scmd.is_present("dont-track") {
            let entry = rt.store()
                .create_from_path(&location)
                .create_from_path(&location, &ref_config, &collection_name)
                .map_err_trace_exit_unwrap();

            let _ = rt.report_touched(entry.get_location()).unwrap_or_exit();

M bin/domain/imag-contact/src/main.rs => bin/domain/imag-contact/src/main.rs +17 -3
@@ 43,7 43,7 @@ extern crate handlebars;
extern crate walkdir;
extern crate uuid;
extern crate serde_json;
extern crate failure;
#[macro_use] extern crate failure;

extern crate libimagcontact;
extern crate libimagstore;


@@ 59,7 59,9 @@ use std::io::Write;

use handlebars::Handlebars;
use clap::ArgMatches;
use toml_query::read::TomlValueReadExt;
use toml_query::read::TomlValueReadTypeExt;
use toml_query::read::Partial;
use walkdir::WalkDir;
use failure::Error;
use failure::err_msg;


@@ 158,6 160,18 @@ fn import(rt: &Runtime) {
    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 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() {
        error!("Path does not exist");
        exit(1)


@@ 166,7 180,7 @@ fn import(rt: &Runtime) {
    if path.is_file() {
        let entry = rt
            .store()
            .retrieve_from_path(&path)
            .retrieve_from_path(&path, &ref_config, &collection_name)
            .map_err_trace_exit_unwrap();

        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 fle = rt
                    .store()
                    .retrieve_from_path(&pb)
                    .retrieve_from_path(&pb, &ref_config, &collection_name)
                    .map_err_trace_exit_unwrap();

                let _ = rt.report_touched(fle.get_location()).unwrap_or_exit();

M bin/domain/imag-contact/src/ui.rs => bin/domain/imag-contact/src/ui.rs +9 -0
@@ 21,6 21,14 @@ use clap::{Arg, App, SubCommand};

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    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")
                   .about("List contacts")
                   .version("0.1")


@@ 56,6 64,7 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
                        .multiple(false)
                        .value_name("PATH")
                        .help("Import from this file/directory"))

                   )

        .subcommand(SubCommand::with_name("show")

M imagrc.toml => imagrc.toml +1 -0
@@ 356,6 356,7 @@ execute_in_store = false
[ref.basepathes]
music = "/home/user/music"
mail = "/home/user/mail"
contacts = "/home/user/contacts"

[mail]
# The name of the mail reference collection

M lib/domain/libimagcontact/Cargo.toml => lib/domain/libimagcontact/Cargo.toml +2 -1
@@ 31,5 31,6 @@ serde_derive = "1"

libimagstore     = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
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/" }


M lib/domain/libimagcontact/src/lib.rs => lib/domain/libimagcontact/src/lib.rs +1 -0
@@ 48,6 48,7 @@ extern crate serde;

#[macro_use] extern crate libimagstore;
extern crate libimagerror;
extern crate libimagentryref;
#[macro_use] extern crate libimagentryutil;

module_entry_path_mod!("contact");

M lib/domain/libimagcontact/src/store.rs => lib/domain/libimagcontact/src/store.rs +82 -16
@@ 18,6 18,7 @@
//

use std::path::PathBuf;
use std::path::Path;

use toml::Value;
use toml::to_string as toml_to_string;


@@ 32,6 33,7 @@ use libimagstore::iter::Entries;
use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagentryutil::isa::Is;
use libimagentryref::reference::{MutRef, Config as RefConfig};

use contact::IsContact;
use deser::DeserVcard;


@@ 39,13 41,23 @@ use util;

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(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
    fn retrieve_from_path<CN>(&'a self, p: &PathBuf, rc: &RefConfig, collection_name: CN)
        -> Result<FileLockEntry<'a>>
        where CN: AsRef<str>;

    fn create_from_buf(&'a self, buf: &str)      -> Result<FileLockEntry<'a>>;
    fn retrieve_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)
        -> 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



@@ 55,23 67,58 @@ pub trait ContactStore<'a> {
/// The extension for the Store to work with contacts
impl<'a> ContactStore<'a> for Store {

    fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
        util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf))
    /// Create a contact from a filepath
    ///
    /// 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>> {
        util::read_to_string(p).and_then(|buf| self.retrieve_from_buf(&buf))
    /// Retrieve a contact from a filepath
    ///
    /// 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
    fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
    /// Create 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 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)?;
        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)?;
        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>> {


@@ 101,10 148,29 @@ fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
    Ok((sid, value))
}

/// Postprocess the entry just fetched from the store
fn postprocess_fetched_entry<'a>(mut entry: FileLockEntry<'a>, value: Value) -> Result<FileLockEntry<'a>> {
/// Postprocess the entry just fetched (created or retrieved) from the store
///
/// 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.get_header_mut().insert("contact.data", value)?;
    entry.as_ref_with_hasher_mut::<Sha1Hasher>().make_ref(path, collection_name, rc, false)?;

    Ok(entry)
}