Split "internal" module into several submodules
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
d02d53594e
commit
901502b67e
21 changed files with 447 additions and 383 deletions
|
@ -66,7 +66,7 @@ use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ use libimagerror::io::ToExitCode;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagentrylink::internal::*;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
|
|
@ -63,8 +63,8 @@ use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
|
||||||
use libimagentryurl::linker::UrlLinker;
|
use libimagentryurl::linker::UrlLinker;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagentrylink::internal::store_check::StoreLinkConsistentExt;
|
use libimagentrylink::storecheck::StoreLinkConsistentExt;
|
||||||
use libimagerror::trace::{MapErrTrace, trace_error};
|
use libimagerror::trace::{MapErrTrace, trace_error};
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
|
|
|
@ -56,7 +56,7 @@ use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
use libimagstore::iter::get::StoreIdGetIteratorExtension;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -61,7 +61,7 @@ use libimagerror::trace::{MapErrTrace, trace_error};
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagutil::debug_result::DebugResult;
|
use libimagutil::debug_result::DebugResult;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
|
@ -252,7 +252,7 @@ fn show(rt: &Runtime, wiki_name: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(rt: &Runtime, wiki_name: &str) {
|
fn delete(rt: &Runtime, wiki_name: &str) {
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
let scmd = rt.cli().subcommand_matches("delete").unwrap(); // safed by clap
|
let scmd = rt.cli().subcommand_matches("delete").unwrap(); // safed by clap
|
||||||
let name = String::from(scmd.value_of("delete-name").unwrap()); // safe by clap
|
let name = String::from(scmd.value_of("delete-name").unwrap()); // safe by clap
|
||||||
|
|
|
@ -36,8 +36,8 @@ use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagentryurl::linker::UrlLinker;
|
use libimagentryurl::linker::UrlLinker;
|
||||||
use libimagentryurl::iter::UrlIter;
|
use libimagentryurl::iter::UrlIter;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagentrylink::internal::Link as StoreLink;
|
use libimagentrylink::link::Link as StoreLink;
|
||||||
|
|
||||||
use crate::link::Link;
|
use crate::link::Link;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ use crate::util::IsHabitCheck;
|
||||||
use crate::util::get_string_header_from_entry;
|
use crate::util::get_string_header_from_entry;
|
||||||
use crate::instance::IsHabitInstance;
|
use crate::instance::IsHabitInstance;
|
||||||
|
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::path::PathBuf;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::iter::Entries;
|
use libimagstore::iter::Entries;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
|
|
@ -24,7 +24,7 @@ use libimagstore::store::Entry;
|
||||||
use libimagstore::store::FileLockEntry;
|
use libimagstore::store::FileLockEntry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagentryutil::isa::Is;
|
use libimagentryutil::isa::Is;
|
||||||
use libimagentryutil::isa::IsKindHeaderPathProvider;
|
use libimagentryutil::isa::IsKindHeaderPathProvider;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use libimagentryutil::isa::IsKindHeaderPathProvider;
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::storeid::StoreIdIterator;
|
use libimagstore::storeid::StoreIdIterator;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
use toml_query::read::TomlValueReadTypeExt;
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ use toml_query::read::TomlValueReadTypeExt;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagerror::errors::ErrorMsg as EM;
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl CategoryStore for Store {
|
||||||
///
|
///
|
||||||
/// Automatically removes all category settings from entries which are linked to this category.
|
/// Automatically removes all category settings from entries which are linked to this category.
|
||||||
fn delete_category(&self, name: &str) -> Result<()> {
|
fn delete_category(&self, name: &str) -> Result<()> {
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use crate::category::Category;
|
use crate::category::Category;
|
||||||
|
|
||||||
trace!("Deleting category: '{}'", name);
|
trace!("Deleting category: '{}'", name);
|
||||||
|
|
97
lib/entry/libimagentrylink/src/iter.rs
Normal file
97
lib/entry/libimagentrylink/src/iter.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
//
|
||||||
|
// imag - the personal information management suite for the commandline
|
||||||
|
// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; version
|
||||||
|
// 2.1 of the License.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
|
use failure::Error;
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use toml::Value;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use libimagstore::store::Store;
|
||||||
|
use libimagstore::store::FileLockEntry;
|
||||||
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
|
|
||||||
|
use crate::link::Link;
|
||||||
|
|
||||||
|
pub struct LinkIter(IntoIter<Link>);
|
||||||
|
|
||||||
|
impl LinkIter {
|
||||||
|
|
||||||
|
pub fn new(v: Vec<Link>) -> LinkIter {
|
||||||
|
LinkIter(v.into_iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_getter(self, store: &Store) -> GetIter {
|
||||||
|
GetIter(self.0, store)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for LinkIter {
|
||||||
|
type Item = Link;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoValues {
|
||||||
|
fn into_values(self) -> Vec<Result<Value>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = Link>> IntoValues for I {
|
||||||
|
fn into_values(self) -> Vec<Result<Value>> {
|
||||||
|
self.map(|s| s.without_base())
|
||||||
|
.unique()
|
||||||
|
.sorted()
|
||||||
|
.into_iter() // Cannot sort toml::Value, hence uglyness here
|
||||||
|
.map(|link| link.to_value().context(EM::ConversionError).map_err(Error::from))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An Iterator that `Store::get()`s the Entries from the store while consumed
|
||||||
|
pub struct GetIter<'a>(IntoIter<Link>, &'a Store);
|
||||||
|
|
||||||
|
impl<'a> GetIter<'a> {
|
||||||
|
pub fn new(i: IntoIter<Link>, store: &'a Store) -> GetIter<'a> {
|
||||||
|
GetIter(i, store)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store(&self) -> &Store {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for GetIter<'a> {
|
||||||
|
type Item = Result<FileLockEntry<'a>>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next().and_then(|id| match self.1.get(id) {
|
||||||
|
Ok(None) => None,
|
||||||
|
Ok(Some(x)) => Some(Ok(x)),
|
||||||
|
Err(e) => Some(Err(e).map_err(From::from)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -56,5 +56,8 @@ extern crate libimagutil;
|
||||||
|
|
||||||
module_entry_path_mod!("links");
|
module_entry_path_mod!("links");
|
||||||
|
|
||||||
pub mod internal;
|
pub mod iter;
|
||||||
|
pub mod linker;
|
||||||
|
pub mod link;
|
||||||
|
pub mod storecheck;
|
||||||
|
|
||||||
|
|
150
lib/entry/libimagentrylink/src/link.rs
Normal file
150
lib/entry/libimagentrylink/src/link.rs
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
//
|
||||||
|
// imag - the personal information management suite for the commandline
|
||||||
|
// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; version
|
||||||
|
// 2.1 of the License.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
|
||||||
|
use libimagstore::storeid::StoreId;
|
||||||
|
use libimagstore::storeid::IntoStoreId;
|
||||||
|
use libimagstore::store::Store;
|
||||||
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
|
|
||||||
|
use toml::Value;
|
||||||
|
use toml::map::Map;
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
|
||||||
|
#[derive(Eq, PartialOrd, Ord, Hash, Debug, Clone)]
|
||||||
|
pub enum Link {
|
||||||
|
Id { link: StoreId },
|
||||||
|
Annotated { link: StoreId, annotation: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Link {
|
||||||
|
|
||||||
|
pub fn exists(&self, store: &Store) -> Result<bool> {
|
||||||
|
match *self {
|
||||||
|
Link::Id { ref link } => store.exists(link.clone()),
|
||||||
|
Link::Annotated { ref link, .. } => store.exists(link.clone()),
|
||||||
|
}
|
||||||
|
.map_err(From::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_str(&self) -> Result<String> {
|
||||||
|
match *self {
|
||||||
|
Link::Id { ref link } => link.to_str(),
|
||||||
|
Link::Annotated { ref link, .. } => link.to_str(),
|
||||||
|
}
|
||||||
|
.map_err(From::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) fn eq_store_id(&self, id: &StoreId) -> bool {
|
||||||
|
match self {
|
||||||
|
&Link::Id { link: ref s } => s.eq(id),
|
||||||
|
&Link::Annotated { link: ref s, .. } => s.eq(id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the StoreId inside the Link, which is always present
|
||||||
|
pub fn get_store_id(&self) -> &StoreId {
|
||||||
|
match self {
|
||||||
|
&Link::Id { link: ref s } => s,
|
||||||
|
&Link::Annotated { link: ref s, .. } => s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper wrapper around Link for StoreId
|
||||||
|
pub(crate) fn without_base(self) -> Link {
|
||||||
|
match self {
|
||||||
|
Link::Id { link: s } => Link::Id { link: s },
|
||||||
|
Link::Annotated { link: s, annotation: ann } =>
|
||||||
|
Link::Annotated { link: s, annotation: ann },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_value(&self) -> Result<Value> {
|
||||||
|
match self {
|
||||||
|
&Link::Id { link: ref s } =>
|
||||||
|
s.to_str()
|
||||||
|
.map(Value::String)
|
||||||
|
.context(EM::ConversionError)
|
||||||
|
.map_err(Error::from),
|
||||||
|
&Link::Annotated { ref link, annotation: ref anno } => {
|
||||||
|
link.to_str()
|
||||||
|
.map(Value::String)
|
||||||
|
.context(EM::ConversionError)
|
||||||
|
.map_err(Error::from)
|
||||||
|
.map(|link| {
|
||||||
|
let mut tab = Map::new();
|
||||||
|
|
||||||
|
tab.insert("link".to_owned(), link);
|
||||||
|
tab.insert("annotation".to_owned(), Value::String(anno.clone()));
|
||||||
|
Value::Table(tab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::cmp::PartialEq for Link {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(&Link::Id { link: ref a }, &Link::Id { link: ref b }) => a.eq(&b),
|
||||||
|
(&Link::Annotated { link: ref a, annotation: ref ann1 },
|
||||||
|
&Link::Annotated { link: ref b, annotation: ref ann2 }) =>
|
||||||
|
(a, ann1).eq(&(b, ann2)),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StoreId> for Link {
|
||||||
|
|
||||||
|
fn from(s: StoreId) -> Link {
|
||||||
|
Link::Id { link: s }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<StoreId> for Link {
|
||||||
|
fn into(self) -> StoreId {
|
||||||
|
match self {
|
||||||
|
Link::Id { link } => link,
|
||||||
|
Link::Annotated { link, .. } => link,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoStoreId for Link {
|
||||||
|
fn into_storeid(self) -> Result<StoreId> {
|
||||||
|
match self {
|
||||||
|
Link::Id { link } => Ok(link),
|
||||||
|
Link::Annotated { link, .. } => Ok(link),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<StoreId> for Link {
|
||||||
|
fn as_ref(&self) -> &StoreId {
|
||||||
|
match self {
|
||||||
|
&Link::Id { ref link } => &link,
|
||||||
|
&Link::Annotated { ref link, .. } => &link,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,144 +18,23 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::storeid::IntoStoreId;
|
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagerror::errors::ErrorMsg as EM;
|
use libimagerror::errors::ErrorMsg as EM;
|
||||||
|
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
use toml_query::insert::TomlValueInsertExt;
|
use toml_query::insert::TomlValueInsertExt;
|
||||||
use toml::map::Map;
|
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::err_msg;
|
use failure::err_msg;
|
||||||
|
|
||||||
use self::iter::LinkIter;
|
use crate::iter::LinkIter;
|
||||||
use self::iter::IntoValues;
|
use crate::iter::IntoValues;
|
||||||
|
use crate::link::Link;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
#[derive(Eq, PartialOrd, Ord, Hash, Debug, Clone)]
|
|
||||||
pub enum Link {
|
|
||||||
Id { link: StoreId },
|
|
||||||
Annotated { link: StoreId, annotation: String },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Link {
|
|
||||||
|
|
||||||
pub fn exists(&self, store: &Store) -> Result<bool> {
|
|
||||||
match *self {
|
|
||||||
Link::Id { ref link } => store.exists(link.clone()),
|
|
||||||
Link::Annotated { ref link, .. } => store.exists(link.clone()),
|
|
||||||
}
|
|
||||||
.map_err(From::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_str(&self) -> Result<String> {
|
|
||||||
match *self {
|
|
||||||
Link::Id { ref link } => link.to_str(),
|
|
||||||
Link::Annotated { ref link, .. } => link.to_str(),
|
|
||||||
}
|
|
||||||
.map_err(From::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn eq_store_id(&self, id: &StoreId) -> bool {
|
|
||||||
match self {
|
|
||||||
&Link::Id { link: ref s } => s.eq(id),
|
|
||||||
&Link::Annotated { link: ref s, .. } => s.eq(id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the StoreId inside the Link, which is always present
|
|
||||||
pub fn get_store_id(&self) -> &StoreId {
|
|
||||||
match self {
|
|
||||||
&Link::Id { link: ref s } => s,
|
|
||||||
&Link::Annotated { link: ref s, .. } => s,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper wrapper around Link for StoreId
|
|
||||||
fn without_base(self) -> Link {
|
|
||||||
match self {
|
|
||||||
Link::Id { link: s } => Link::Id { link: s },
|
|
||||||
Link::Annotated { link: s, annotation: ann } =>
|
|
||||||
Link::Annotated { link: s, annotation: ann },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(&self) -> Result<Value> {
|
|
||||||
match self {
|
|
||||||
&Link::Id { link: ref s } =>
|
|
||||||
s.to_str()
|
|
||||||
.map(Value::String)
|
|
||||||
.context(EM::ConversionError)
|
|
||||||
.map_err(Error::from),
|
|
||||||
&Link::Annotated { ref link, annotation: ref anno } => {
|
|
||||||
link.to_str()
|
|
||||||
.map(Value::String)
|
|
||||||
.context(EM::ConversionError)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map(|link| {
|
|
||||||
let mut tab = Map::new();
|
|
||||||
|
|
||||||
tab.insert("link".to_owned(), link);
|
|
||||||
tab.insert("annotation".to_owned(), Value::String(anno.clone()));
|
|
||||||
Value::Table(tab)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq for Link {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
match (self, other) {
|
|
||||||
(&Link::Id { link: ref a }, &Link::Id { link: ref b }) => a.eq(&b),
|
|
||||||
(&Link::Annotated { link: ref a, annotation: ref ann1 },
|
|
||||||
&Link::Annotated { link: ref b, annotation: ref ann2 }) =>
|
|
||||||
(a, ann1).eq(&(b, ann2)),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<StoreId> for Link {
|
|
||||||
|
|
||||||
fn from(s: StoreId) -> Link {
|
|
||||||
Link::Id { link: s }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<StoreId> for Link {
|
|
||||||
fn into(self) -> StoreId {
|
|
||||||
match self {
|
|
||||||
Link::Id { link } => link,
|
|
||||||
Link::Annotated { link, .. } => link,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoStoreId for Link {
|
|
||||||
fn into_storeid(self) -> Result<StoreId> {
|
|
||||||
match self {
|
|
||||||
Link::Id { link } => Ok(link),
|
|
||||||
Link::Annotated { link, .. } => Ok(link),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<StoreId> for Link {
|
|
||||||
fn as_ref(&self) -> &StoreId {
|
|
||||||
match self {
|
|
||||||
&Link::Id { ref link } => &link,
|
|
||||||
&Link::Annotated { ref link, .. } => &link,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait InternalLinker {
|
pub trait InternalLinker {
|
||||||
|
|
||||||
/// Get the internal links from the implementor object
|
/// Get the internal links from the implementor object
|
||||||
|
@ -174,85 +53,6 @@ pub trait InternalLinker {
|
||||||
fn add_internal_annotated_link(&mut self, link: &mut Entry, annotation: String) -> Result<()>;
|
fn add_internal_annotated_link(&mut self, link: &mut Entry, annotation: String) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod iter {
|
|
||||||
use std::vec::IntoIter;
|
|
||||||
use super::Link;
|
|
||||||
|
|
||||||
use failure::Error;
|
|
||||||
use failure::Fallible as Result;
|
|
||||||
use failure::ResultExt;
|
|
||||||
use toml::Value;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
use libimagstore::store::FileLockEntry;
|
|
||||||
use libimagerror::errors::ErrorMsg as EM;
|
|
||||||
|
|
||||||
pub struct LinkIter(IntoIter<Link>);
|
|
||||||
|
|
||||||
impl LinkIter {
|
|
||||||
|
|
||||||
pub fn new(v: Vec<Link>) -> LinkIter {
|
|
||||||
LinkIter(v.into_iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_getter(self, store: &Store) -> GetIter {
|
|
||||||
GetIter(self.0, store)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for LinkIter {
|
|
||||||
type Item = Link;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.0.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IntoValues {
|
|
||||||
fn into_values(self) -> Vec<Result<Value>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator<Item = Link>> IntoValues for I {
|
|
||||||
fn into_values(self) -> Vec<Result<Value>> {
|
|
||||||
self.map(|s| s.without_base())
|
|
||||||
.unique()
|
|
||||||
.sorted()
|
|
||||||
.into_iter() // Cannot sort toml::Value, hence uglyness here
|
|
||||||
.map(|link| link.to_value().context(EM::ConversionError).map_err(Error::from))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An Iterator that `Store::get()`s the Entries from the store while consumed
|
|
||||||
pub struct GetIter<'a>(IntoIter<Link>, &'a Store);
|
|
||||||
|
|
||||||
impl<'a> GetIter<'a> {
|
|
||||||
pub fn new(i: IntoIter<Link>, store: &'a Store) -> GetIter<'a> {
|
|
||||||
GetIter(i, store)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store(&self) -> &Store {
|
|
||||||
self.1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for GetIter<'a> {
|
|
||||||
type Item = Result<FileLockEntry<'a>>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.0.next().and_then(|id| match self.1.get(id) {
|
|
||||||
Ok(None) => None,
|
|
||||||
Ok(Some(x)) => Some(Ok(x)),
|
|
||||||
Err(e) => Some(Err(e).map_err(From::from)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InternalLinker for Entry {
|
impl InternalLinker for Entry {
|
||||||
|
|
||||||
fn get_internal_links(&self) -> Result<LinkIter> {
|
fn get_internal_links(&self) -> Result<LinkIter> {
|
||||||
|
@ -452,164 +252,6 @@ fn process_rw_result(links: Result<Option<Value>>) -> Result<LinkIter> {
|
||||||
Ok(LinkIter::new(links))
|
Ok(LinkIter::new(links))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod store_check {
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
|
|
||||||
use failure::ResultExt;
|
|
||||||
use failure::Fallible as Result;
|
|
||||||
use failure::Error;
|
|
||||||
use failure::err_msg;
|
|
||||||
|
|
||||||
pub trait StoreLinkConsistentExt {
|
|
||||||
fn check_link_consistency(&self) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StoreLinkConsistentExt for Store {
|
|
||||||
fn check_link_consistency(&self) -> Result<()> {
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::internal::InternalLinker;
|
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
|
||||||
use libimagutil::debug_result::DebugResult;
|
|
||||||
|
|
||||||
// Helper data structure to collect incoming and outgoing links for each StoreId
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct Linking {
|
|
||||||
outgoing: Vec<StoreId>,
|
|
||||||
incoming: Vec<StoreId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to aggregate the Link network
|
|
||||||
//
|
|
||||||
// This function aggregates a HashMap which maps each StoreId object in the store onto
|
|
||||||
// a Linking object, which contains a list of StoreIds which this entry links to and a
|
|
||||||
// list of StoreIds which link to the current one.
|
|
||||||
//
|
|
||||||
// The lambda returns an error if something fails
|
|
||||||
let aggregate_link_network = |store: &Store| -> Result<HashMap<StoreId, Linking>> {
|
|
||||||
store
|
|
||||||
.entries()?
|
|
||||||
.into_get_iter()
|
|
||||||
.fold(Ok(HashMap::new()), |map, element| {
|
|
||||||
map.and_then(|mut map| {
|
|
||||||
debug!("Checking element = {:?}", element);
|
|
||||||
let entry = element?.ok_or_else(|| err_msg("TODO: Not yet handled"))?;
|
|
||||||
|
|
||||||
debug!("Checking entry = {:?}", entry.get_location());
|
|
||||||
|
|
||||||
let internal_links = entry
|
|
||||||
.get_internal_links()?
|
|
||||||
.into_getter(store); // get the FLEs from the Store
|
|
||||||
|
|
||||||
let mut linking = Linking::default();
|
|
||||||
for internal_link in internal_links {
|
|
||||||
debug!("internal link = {:?}", internal_link);
|
|
||||||
|
|
||||||
linking.outgoing.push(internal_link?.get_location().clone());
|
|
||||||
linking.incoming.push(entry.get_location().clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
map.insert(entry.get_location().clone(), linking);
|
|
||||||
Ok(map)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper to check whethre all StoreIds in the network actually exists
|
|
||||||
//
|
|
||||||
// Because why not?
|
|
||||||
let all_collected_storeids_exist = |network: &HashMap<StoreId, Linking>| -> Result<()> {
|
|
||||||
for (id, _) in network.iter() {
|
|
||||||
if is_match!(self.get(id.clone()), Ok(Some(_))) {
|
|
||||||
debug!("Exists in store: {:?}", id);
|
|
||||||
|
|
||||||
if !self.exists(id.clone())? {
|
|
||||||
warn!("Does exist in store but not on FS: {:?}", id);
|
|
||||||
return Err(err_msg("Link target does not exist"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!("Does not exist in store: {:?}", id);
|
|
||||||
return Err(err_msg("Link target does not exist"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to create a SLCECD::OneDirectionalLink error object
|
|
||||||
let mk_one_directional_link_err = |src: StoreId, target: StoreId| -> Error {
|
|
||||||
Error::from(format_err!("Dead link: {} -> {}",
|
|
||||||
src.local_display_string(),
|
|
||||||
target.local_display_string()))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper lambda to check whether the _incoming_ links of each entry actually also
|
|
||||||
// appear in the _outgoing_ list of the linked entry
|
|
||||||
let incoming_links_exists_as_outgoing_links =
|
|
||||||
|src: &StoreId, linking: &Linking, network: &HashMap<StoreId, Linking>| -> Result<()> {
|
|
||||||
for link in linking.incoming.iter() {
|
|
||||||
// Check whether the links which are _incoming_ on _src_ are outgoing
|
|
||||||
// in each of the links in the incoming list.
|
|
||||||
let incoming_consistent = network.get(link)
|
|
||||||
.map(|l| l.outgoing.contains(src))
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if !incoming_consistent {
|
|
||||||
return Err(mk_one_directional_link_err(src.clone(), link.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper lambda to check whether the _outgoing links of each entry actually also
|
|
||||||
// appear in the _incoming_ list of the linked entry
|
|
||||||
let outgoing_links_exist_as_incoming_links =
|
|
||||||
|src: &StoreId, linking: &Linking, network: &HashMap<StoreId, Linking>| -> Result<()> {
|
|
||||||
for link in linking.outgoing.iter() {
|
|
||||||
// Check whether the links which are _outgoing_ on _src_ are incoming
|
|
||||||
// in each of the links in the outgoing list.
|
|
||||||
let outgoing_consistent = network.get(link)
|
|
||||||
.map(|l| l.incoming.contains(src))
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if !outgoing_consistent {
|
|
||||||
return Err(mk_one_directional_link_err(link.clone(), src.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
aggregate_link_network(&self)
|
|
||||||
.map_dbg_str("Aggregated")
|
|
||||||
.map_dbg(|nw| {
|
|
||||||
let mut s = String::new();
|
|
||||||
for (k, v) in nw {
|
|
||||||
s.push_str(&format!("{}\n in: {:?}\n out: {:?}", k, v.incoming, v.outgoing));
|
|
||||||
}
|
|
||||||
s
|
|
||||||
})
|
|
||||||
.and_then(|nw| {
|
|
||||||
all_collected_storeids_exist(&nw)
|
|
||||||
.map(|_| nw)
|
|
||||||
.context(err_msg("Link handling error"))
|
|
||||||
.map_err(Error::from)
|
|
||||||
})
|
|
||||||
.and_then(|nw| {
|
|
||||||
for (id, linking) in nw.iter() {
|
|
||||||
incoming_links_exists_as_outgoing_links(id, linking, &nw)?;
|
|
||||||
outgoing_links_exist_as_incoming_links(id, linking, &nw)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.map(|_| ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -852,4 +494,3 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
173
lib/entry/libimagentrylink/src/storecheck.rs
Normal file
173
lib/entry/libimagentrylink/src/storecheck.rs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
//
|
||||||
|
// imag - the personal information management suite for the commandline
|
||||||
|
// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; version
|
||||||
|
// 2.1 of the License.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use libimagstore::store::Store;
|
||||||
|
use libimagstore::storeid::StoreId;
|
||||||
|
use libimagutil::debug_result::DebugResult;
|
||||||
|
|
||||||
|
use failure::ResultExt;
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
|
||||||
|
use crate::linker::*;
|
||||||
|
|
||||||
|
pub trait StoreLinkConsistentExt {
|
||||||
|
fn check_link_consistency(&self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StoreLinkConsistentExt for Store {
|
||||||
|
fn check_link_consistency(&self) -> Result<()> {
|
||||||
|
// Helper data structure to collect incoming and outgoing links for each StoreId
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct Linking {
|
||||||
|
outgoing: Vec<StoreId>,
|
||||||
|
incoming: Vec<StoreId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to aggregate the Link network
|
||||||
|
//
|
||||||
|
// This function aggregates a HashMap which maps each StoreId object in the store onto
|
||||||
|
// a Linking object, which contains a list of StoreIds which this entry links to and a
|
||||||
|
// list of StoreIds which link to the current one.
|
||||||
|
//
|
||||||
|
// The lambda returns an error if something fails
|
||||||
|
let aggregate_link_network = |store: &Store| -> Result<HashMap<StoreId, Linking>> {
|
||||||
|
store
|
||||||
|
.entries()?
|
||||||
|
.into_get_iter()
|
||||||
|
.fold(Ok(HashMap::new()), |map, element| {
|
||||||
|
map.and_then(|mut map| {
|
||||||
|
debug!("Checking element = {:?}", element);
|
||||||
|
let entry = element?.ok_or_else(|| err_msg("TODO: Not yet handled"))?;
|
||||||
|
|
||||||
|
debug!("Checking entry = {:?}", entry.get_location());
|
||||||
|
|
||||||
|
let internal_links = entry
|
||||||
|
.get_internal_links()?
|
||||||
|
.into_getter(store); // get the FLEs from the Store
|
||||||
|
|
||||||
|
let mut linking = Linking::default();
|
||||||
|
for internal_link in internal_links {
|
||||||
|
debug!("internal link = {:?}", internal_link);
|
||||||
|
|
||||||
|
linking.outgoing.push(internal_link?.get_location().clone());
|
||||||
|
linking.incoming.push(entry.get_location().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
map.insert(entry.get_location().clone(), linking);
|
||||||
|
Ok(map)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to check whethre all StoreIds in the network actually exists
|
||||||
|
//
|
||||||
|
// Because why not?
|
||||||
|
let all_collected_storeids_exist = |network: &HashMap<StoreId, Linking>| -> Result<()> {
|
||||||
|
for (id, _) in network.iter() {
|
||||||
|
if is_match!(self.get(id.clone()), Ok(Some(_))) {
|
||||||
|
debug!("Exists in store: {:?}", id);
|
||||||
|
|
||||||
|
if !self.exists(id.clone())? {
|
||||||
|
warn!("Does exist in store but not on FS: {:?}", id);
|
||||||
|
return Err(err_msg("Link target does not exist"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Does not exist in store: {:?}", id);
|
||||||
|
return Err(err_msg("Link target does not exist"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to create a SLCECD::OneDirectionalLink error object
|
||||||
|
let mk_one_directional_link_err = |src: StoreId, target: StoreId| -> Error {
|
||||||
|
Error::from(format_err!("Dead link: {} -> {}",
|
||||||
|
src.local_display_string(),
|
||||||
|
target.local_display_string()))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper lambda to check whether the _incoming_ links of each entry actually also
|
||||||
|
// appear in the _outgoing_ list of the linked entry
|
||||||
|
let incoming_links_exists_as_outgoing_links =
|
||||||
|
|src: &StoreId, linking: &Linking, network: &HashMap<StoreId, Linking>| -> Result<()> {
|
||||||
|
for link in linking.incoming.iter() {
|
||||||
|
// Check whether the links which are _incoming_ on _src_ are outgoing
|
||||||
|
// in each of the links in the incoming list.
|
||||||
|
let incoming_consistent = network.get(link)
|
||||||
|
.map(|l| l.outgoing.contains(src))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !incoming_consistent {
|
||||||
|
return Err(mk_one_directional_link_err(src.clone(), link.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper lambda to check whether the _outgoing links of each entry actually also
|
||||||
|
// appear in the _incoming_ list of the linked entry
|
||||||
|
let outgoing_links_exist_as_incoming_links =
|
||||||
|
|src: &StoreId, linking: &Linking, network: &HashMap<StoreId, Linking>| -> Result<()> {
|
||||||
|
for link in linking.outgoing.iter() {
|
||||||
|
// Check whether the links which are _outgoing_ on _src_ are incoming
|
||||||
|
// in each of the links in the outgoing list.
|
||||||
|
let outgoing_consistent = network.get(link)
|
||||||
|
.map(|l| l.incoming.contains(src))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !outgoing_consistent {
|
||||||
|
return Err(mk_one_directional_link_err(link.clone(), src.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
aggregate_link_network(&self)
|
||||||
|
.map_dbg_str("Aggregated")
|
||||||
|
.map_dbg(|nw| {
|
||||||
|
let mut s = String::new();
|
||||||
|
for (k, v) in nw {
|
||||||
|
s.push_str(&format!("{}\n in: {:?}\n out: {:?}", k, v.incoming, v.outgoing));
|
||||||
|
}
|
||||||
|
s
|
||||||
|
})
|
||||||
|
.and_then(|nw| {
|
||||||
|
all_collected_storeids_exist(&nw)
|
||||||
|
.map(|_| nw)
|
||||||
|
.context(err_msg("Link handling error"))
|
||||||
|
.map_err(Error::from)
|
||||||
|
})
|
||||||
|
.and_then(|nw| {
|
||||||
|
for (id, linking) in nw.iter() {
|
||||||
|
incoming_links_exists_as_outgoing_links(id, linking, &nw)?;
|
||||||
|
outgoing_links_exist_as_incoming_links(id, linking, &nw)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ use failure::Error;
|
||||||
use crate::link::extract_links;
|
use crate::link::extract_links;
|
||||||
|
|
||||||
use libimagentryurl::linker::UrlLinker;
|
use libimagentryurl::linker::UrlLinker;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
use libimagentryref::reference::MutRef;
|
use libimagentryref::reference::MutRef;
|
||||||
use libimagentryref::reference::RefFassade;
|
use libimagentryref::reference::RefFassade;
|
||||||
use libimagentryref::hasher::sha1::Sha1Hasher;
|
use libimagentryref::hasher::sha1::Sha1Hasher;
|
||||||
|
@ -286,7 +286,7 @@ mod tests {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
fn setup_logging() {
|
fn setup_logging() {
|
||||||
let _ = ::env_logger::try_init();
|
let _ = ::env_logger::try_init();
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
//! Not to confuse with `external::Link` which is a real `FileLockEntry` under the hood.
|
//! Not to confuse with `external::Link` which is a real `FileLockEntry` under the hood.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use libimagentrylink::internal::Link;
|
use libimagentrylink::link::Link;
|
||||||
use libimagentrylink::internal::iter::LinkIter;
|
use libimagentrylink::iter::LinkIter;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagutil::debug_result::DebugResult;
|
use libimagutil::debug_result::DebugResult;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::store::Store;
|
use libimagstore::store::Store;
|
||||||
use libimagstore::store::Entry;
|
use libimagstore::store::Entry;
|
||||||
use libimagutil::debug_result::DebugResult;
|
use libimagutil::debug_result::DebugResult;
|
||||||
use libimagentrylink::internal::InternalLinker;
|
use libimagentrylink::linker::InternalLinker;
|
||||||
|
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
Loading…
Reference in a new issue