~matthiasbeyer/imag

cdc90f7be777e8bfd6626109ced710aa3d183dbf — Matthias Beyer 2 years ago 59ddb70
Refactor: Remove notion of "external link"s

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
M lib/entry/libimagentryurl/src/iter.rs => lib/entry/libimagentryurl/src/iter.rs +32 -32
@@ 37,7 37,7 @@ use libimagutil::debug_result::DebugResult;
use failure::Fallible as Result;
use url::Url;

/// Helper for building `OnlyExternalIter` and `NoExternalIter`
/// Helper for building `OnlyUrlIter` and `NoUrlIter`
///
/// The boolean value defines, how to interpret the `is_external_link_storeid()` return value
/// (here as "pred"):


@@ 55,9 55,9 @@ use url::Url;
/// false... and so on.
///
/// As we can see, the operator between these two operants is `!(a ^ b)`.
pub struct ExternalFilterIter(LinkIter, bool);
pub struct UrlFilterIter(LinkIter, bool);

impl Iterator for ExternalFilterIter {
impl Iterator for UrlFilterIter {
    type Item = Link;

    fn next(&mut self) -> Option<Self::Item> {


@@ 78,24 78,24 @@ impl Iterator for ExternalFilterIter {
///
/// # See also
///
/// Also see `OnlyExternalIter` and `NoExternalIter` and the helper traits/functions
/// `OnlyInteralLinks`/`only_links()` and `OnlyExternalLinks`/`only_urls()`.
pub trait SelectExternal {
    fn select_urls(self, b: bool) -> ExternalFilterIter;
/// Also see `OnlyUrlIter` and `NoUrlIter` and the helper traits/functions
/// `OnlyInteralLinks`/`only_links()` and `OnlyUrlLinks`/`only_urls()`.
pub trait SelectUrl {
    fn select_urls(self, b: bool) -> UrlFilterIter;
}

impl SelectExternal for LinkIter {
    fn select_urls(self, b: bool) -> ExternalFilterIter {
        ExternalFilterIter(self, b)
impl SelectUrl for LinkIter {
    fn select_urls(self, b: bool) -> UrlFilterIter {
        UrlFilterIter(self, b)
    }
}


pub struct OnlyExternalIter(ExternalFilterIter);
pub struct OnlyUrlIter(UrlFilterIter);

impl OnlyExternalIter {
    pub fn new(li: LinkIter) -> OnlyExternalIter {
        OnlyExternalIter(ExternalFilterIter(li, true))
impl OnlyUrlIter {
    pub fn new(li: LinkIter) -> OnlyUrlIter {
        OnlyUrlIter(UrlFilterIter(li, true))
    }

    pub fn urls<'a>(self, store: &'a Store) -> UrlIter<'a> {


@@ 103,7 103,7 @@ impl OnlyExternalIter {
    }
}

impl Iterator for OnlyExternalIter {
impl Iterator for OnlyUrlIter {
    type Item = Link;

    fn next(&mut self) -> Option<Self::Item> {


@@ 111,15 111,15 @@ impl Iterator for OnlyExternalIter {
    }
}

pub struct NoExternalIter(ExternalFilterIter);
pub struct NoUrlIter(UrlFilterIter);

impl NoExternalIter {
    pub fn new(li: LinkIter) -> NoExternalIter {
        NoExternalIter(ExternalFilterIter(li, false))
impl NoUrlIter {
    pub fn new(li: LinkIter) -> NoUrlIter {
        NoUrlIter(UrlFilterIter(li, false))
    }
}

impl Iterator for NoExternalIter {
impl Iterator for NoUrlIter {
    type Item = Link;

    fn next(&mut self) -> Option<Self::Item> {


@@ 127,35 127,35 @@ impl Iterator for NoExternalIter {
    }
}

pub trait OnlyExternalLinks : Sized {
    fn only_urls(self) -> OnlyExternalIter ;
pub trait OnlyUrlLinks : Sized {
    fn only_urls(self) -> OnlyUrlIter ;

    fn no_links(self) -> OnlyExternalIter {
    fn no_links(self) -> OnlyUrlIter {
        self.only_urls()
    }
}

impl OnlyExternalLinks for LinkIter {
    fn only_urls(self) -> OnlyExternalIter {
        OnlyExternalIter::new(self)
impl OnlyUrlLinks for LinkIter {
    fn only_urls(self) -> OnlyUrlIter {
        OnlyUrlIter::new(self)
    }
}

pub trait OnlyInternalLinks : Sized {
    fn only_links(self) -> NoExternalIter;
    fn only_links(self) -> NoUrlIter;

    fn no_urls(self) -> NoExternalIter {
    fn no_urls(self) -> NoUrlIter {
        self.only_links()
    }
}

impl OnlyInternalLinks for LinkIter {
    fn only_links(self) -> NoExternalIter {
        NoExternalIter::new(self)
    fn only_links(self) -> NoUrlIter {
        NoUrlIter::new(self)
    }
}

pub struct UrlIter<'a>(OnlyExternalIter, &'a Store);
pub struct UrlIter<'a>(OnlyUrlIter, &'a Store);

impl<'a> Iterator for UrlIter<'a> {
    type Item = Result<Url>;


@@ 174,7 174,7 @@ impl<'a> Iterator for UrlIter<'a> {
                        .map_err(From::from)
                        .and_then(|f| {
                            debug!("Store::retrieve({:?}) succeeded", id);
                            debug!("getting external link from file now");
                            debug!("getting uri link from file now");
                            f.get_link_uri_from_filelockentry()
                                .map_dbg_str("Error happened while getting link URI from FLE")
                                .map_dbg_err(|e| format!("URL -> Err = {:?}", e))

M lib/entry/libimagentryurl/src/link.rs => lib/entry/libimagentryurl/src/link.rs +3 -3
@@ 40,8 40,8 @@ impl Link for Entry {

    fn get_link_uri_from_filelockentry(&self) -> Result<Option<Url>> {
        self.get_header()
            .read_string("links.external.content.url")
            .context(format_err!("Error reading header 'links.external.content.url' from '{}'", self.get_location()))
            .read_string("url.uri")
            .context(format_err!("Error reading header 'url.uri' from '{}'", self.get_location()))
            .context(EM::EntryHeaderReadError)
            .map_err(Error::from)
            .and_then(|opt| match opt {


@@ 61,7 61,7 @@ impl Link for Entry {
    }

    fn get_url(&self) -> Result<Option<Url>> {
        match self.get_header().read_string("links.external.url")? {
        match self.get_header().read_string("url.uri")? {
            None        => Ok(None),
            Some(ref s) => Url::parse(&s[..])
                .context(format_err!("Failed to parse URL: '{}'", s))

M lib/entry/libimagentryurl/src/linker.rs => lib/entry/libimagentryurl/src/linker.rs +16 -34
@@ 38,56 38,48 @@ use crate::iter::UrlIter;

pub trait UrlLinker : Linkable {

    /// Get the external links from the implementor object
    /// Get the urls from the implementor object
    fn get_urls<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>>;

    /// Set the external links for the implementor object
    /// Set the urls for the implementor object
    fn set_urls(&mut self, store: &Store, links: Vec<Url>) -> Result<Vec<StoreId>>;

    /// Add an external link to the implementor object
    /// Add an url to the implementor object
    fn add_url(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>>;

    /// Remove an external link from the implementor object
    /// Remove an url from the implementor object
    fn remove_url(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>>;

}

/// Implement `ExternalLinker` for `Entry`, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl UrlLinker for Entry {

    /// Get the external links from the implementor object
    fn get_urls<'a>(&self, store: &'a Store) -> Result<UrlIter<'a>> {
        use crate::iter::OnlyExternalLinks;
        use crate::iter::OnlyUrlLinks;

        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // /links/<SHA> -> load these files and get the url from their headers,
        // put them into the return vector.
        self.links()
            .map(|iter| {
                debug!("Getting external links");
                debug!("Getting urls");
                iter.only_urls().urls(store)
            })
    }

    /// Set the external links for the implementor object
    /// Set the url links for the implementor object
    ///
    /// # Return Value
    ///
    /// Returns the StoreIds which were newly created for the new external links, if there are more
    /// external links than before.
    /// If there are less external links than before, an empty vec![] is returned.
    /// Returns the StoreIds which were newly created for the new urls, if there are more
    /// urls than before.
    /// If there are less urls than before, an empty vec![] is returned.
    ///
    fn set_urls(&mut self, store: &Store, links: Vec<Url>) -> Result<Vec<StoreId>> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        debug!("Iterating {} links = {:?}", links.len(), links);
        links.into_iter().map(|link| {
            let hash = hex::encode(Sha1::digest(&link.as_str().as_bytes()));
            let file_id = crate::module_path::new_id(format!("external/{}", hash))
            let file_id = crate::module_path::new_id(format!("links/{}", hash))
                .map_dbg_err(|_| {
                    format!("Failed to build StoreId for this hash '{:?}'", hash)
                })?;


@@ 142,18 134,13 @@ impl UrlLinker for Entry {
        .collect()
    }

    /// Add an external link to the implementor object
    /// Add an url to the implementor object
    ///
    /// # Return Value
    ///
    /// (See ExternalLinker::set_urls())
    ///
    /// Returns the StoreIds which were newly created for the new external links, if there are more
    /// external links than before.
    /// If there are less external links than before, an empty vec![] is returned.
    /// (See UrlLinker::set_urls())
    ///
    fn add_url(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>> {
        // get external links, add this one, save them
        debug!("Getting links");
        self.get_urls(store)
            .and_then(|links| {


@@ 167,18 154,13 @@ impl UrlLinker for Entry {
            })
    }

    /// Remove an external link from the implementor object
    /// Remove an url from the implementor object
    ///
    /// # Return Value
    ///
    /// (See ExternalLinker::set_urls())
    ///
    /// Returns the StoreIds which were newly created for the new external links, if there are more
    /// external links than before.
    /// If there are less external links than before, an empty vec![] is returned.
    /// (See UrlLinker::set_urls())
    ///
    fn remove_url(&mut self, store: &Store, link: Url) -> Result<Vec<StoreId>> {
        // get external links, remove this one, save them
        self.get_urls(store)
            .and_then(|links| {
                debug!("Removing link = '{:?}'", link);

M lib/entry/libimagentryurl/src/util.rs => lib/entry/libimagentryurl/src/util.rs +3 -3
@@ 21,8 21,8 @@ use std::fmt::Debug;

use libimagstore::storeid::StoreId;

/// Check whether the StoreId starts with `/link/external/`
/// Check whether the StoreId starts with `/url/`
pub fn is_external_link_storeid<A: AsRef<StoreId> + Debug>(id: A) -> bool {
    debug!("Checking whether this is a 'url/external/': '{:?}'", id);
    id.as_ref().is_in_collection(&["url", "external"])
    debug!("Checking whether this is a 'url/': '{:?}'", id);
    id.as_ref().is_in_collection(&["url"])
}