summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-06-07 11:45:02 +0200
committerGitHub <noreply@github.com>2017-06-07 11:45:02 +0200
commitbb9ff5bfd824bd1c09f98fc9f77348965f7f1573 (patch)
tree1771e1bcc37f78ce2eea1a6d841ad28d4cc68a53
parentdd24ce810a80222a625b5f24e6e2b7cb132a91c1 (diff)
parent72f0664976863bb8ae10c4851a8247e8854c9c98 (diff)
downloadimag-bb9ff5bfd824bd1c09f98fc9f77348965f7f1573.zip
imag-bb9ff5bfd824bd1c09f98fc9f77348965f7f1573.tar.gz
Merge pull request #951 from matthiasbeyer/remove-hooks
libimagstore: Remove hook support
-rw-r--r--.imag-documentation/Cargo.toml3
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Cargo.toml1
-rw-r--r--doc/src/05100-lib-rt.md1
-rw-r--r--doc/src/05100-lib-store-std-hook.md17
-rw-r--r--doc/src/05100-lib-store.md4
-rw-r--r--imagrc.toml145
-rw-r--r--libimagentrylink/src/internal.rs259
-rw-r--r--libimagerror/src/error_gen.rs18
-rw-r--r--libimagrt/Cargo.toml3
-rw-r--r--libimagrt/src/lib.rs1
-rw-r--r--libimagrt/src/runtime.rs55
-rw-r--r--libimagstore/Cargo.toml5
-rw-r--r--libimagstore/src/configuration.rs596
-rw-r--r--libimagstore/src/error.rs21
-rw-r--r--libimagstore/src/hook/accessor.rs49
-rw-r--r--libimagstore/src/hook/aspect.rs151
-rw-r--r--libimagstore/src/hook/error.rs65
-rw-r--r--libimagstore/src/hook/mod.rs36
-rw-r--r--libimagstore/src/hook/position.rs32
-rw-r--r--libimagstore/src/hook/result.rs22
-rw-r--r--libimagstore/src/lib.rs1
-rw-r--r--libimagstore/src/store.rs904
-rw-r--r--libimagstorestdhook/Cargo.toml36
l---------libimagstorestdhook/README.md1
-rw-r--r--libimagstorestdhook/src/debug.rs134
-rw-r--r--libimagstorestdhook/src/denylinkeddelete.rs119
-rw-r--r--libimagstorestdhook/src/flock.rs167
-rw-r--r--libimagstorestdhook/src/lib.rs52
-rw-r--r--libimagstorestdhook/src/linkverify.rs93
-rw-r--r--libimagstorestdhook/src/vcs/git/action.rs69
-rw-r--r--libimagstorestdhook/src/vcs/git/config.rs241
-rw-r--r--libimagstorestdhook/src/vcs/git/delete.rs242
-rw-r--r--libimagstorestdhook/src/vcs/git/error.rs97
-rw-r--r--libimagstorestdhook/src/vcs/git/mod.rs29
-rw-r--r--libimagstorestdhook/src/vcs/git/result.rs24
-rw-r--r--libimagstorestdhook/src/vcs/git/runtime.rs178
-rw-r--r--libimagstorestdhook/src/vcs/git/store_unload.rs264
-rw-r--r--libimagstorestdhook/src/vcs/git/update.rs263
-rw-r--r--libimagstorestdhook/src/vcs/git/util.rs42
-rw-r--r--libimagstorestdhook/src/vcs/mod.rs20
41 files changed, 340 insertions, 4122 deletions
diff --git a/.imag-documentation/Cargo.toml b/.imag-documentation/Cargo.toml
index 307987e..bbe8bf5 100644
--- a/.imag-documentation/Cargo.toml
+++ b/.imag-documentation/Cargo.toml
@@ -60,9 +60,6 @@ path = "../libimagrt"
[dependencies.libimagstore]
path = "../libimagstore"
-[dependencies.libimagstorestdhook]
-path = "../libimagstorestdhook"
-
[dependencies.libimagtimeui]
path = "../libimagtimeui"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3f4615d..a471d49 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -184,7 +184,6 @@ from the others by `"/`". See below:
| part/lib/imagnotes | Targets library: imagnotes | [search][search-part/lib/imagnotes] |
| part/lib/imagrt | Targets library: imagrt | [search][search-part/lib/imagrt] |
| part/lib/imagstore | Targets library: imagstore | [search][search-part/lib/imagstore] |
-| part/lib/imagstorestdhook | Targets library: imagstorestdhook | [search][search-part/lib/imagstorestdhook] |
| part/lib/imagutil | Targets library: | [search][search-part/lib/imagutil] |
| part/_new_binary | Introduces new binary | [search][search-part/_new_binary] |
| part/_new_library | Introduces new library | [search][search-part/_new_library] |
@@ -283,7 +282,6 @@ _to be written_
[search-part/lib/imagnotes]: https://github.com/matthiasbeyer/imag/labels/part%2Flib%2Fimagnotes
[search-part/lib/imagrt]: https://github.com/matthiasbeyer/imag/labels/part%2Flib%2Fimagrt
[search-part/lib/imagstore]: https://github.com/matthiasbeyer/imag/labels/part%2Flib%2Fimagstore
-[search-part/lib/imagstorestdhook]: https://github.com/matthiasbeyer/imag/labels/part%2Flib%2Fimagstorestdhook
[search-part/lib/imagutil]: https://github.com/matthiasbeyer/imag/labels/part%2Flib%2Fimagutil
[search-part/_new_binary]: https://github.com/matthiasbeyer/imag/labels/part%2F_new_binary
[search-part/_new_library]: https://github.com/matthiasbeyer/imag/labels/part%2F_new_library
diff --git a/Cargo.toml b/Cargo.toml
index c5212cd..56298a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,7 +31,6 @@ members = [
"libimagref",
"libimagrt",
"libimagstore",
- "libimagstorestdhook",
"libimagtimeui",
"libimagtodo",
"libimagutil",
diff --git a/doc/src/05100-lib-rt.md b/doc/src/05100-lib-rt.md
index b296ba7..ca22256 100644
--- a/doc/src/05100-lib-rt.md
+++ b/doc/src/05100-lib-rt.md
@@ -12,5 +12,4 @@ to live in a imag binary.
### Long-term TODO
- [ ] Merge with `libimagstore`
-- [ ] Merge with `libimagstorestdhook`
diff --git a/doc/src/05100-lib-store-std-hook.md b/doc/src/05100-lib-store-std-hook.md
deleted file mode 100644
index 72972b0..0000000
--- a/doc/src/05100-lib-store-std-hook.md
+++ /dev/null
@@ -1,17 +0,0 @@
-## libimagstorestdhook
-
-The `libimagstorestdhook` is a library for default store hooks which are shipped
-with the imag store.
-Hooks are actions which can be performed before and after certain store actions,
-for example before a file is created, or after a file is removed.
-
-### Long-term TODO
-
-- [ ] Merge with `libimagrt`
-- [ ] Merge with `libimagstorestdhook`
-- [ ] Create Runtime-wide "Store meta data" storage in the Runtime, which can be
- set by users during the runtime of imag and then used by the hooks to get meta
- information about their own runtime.
-- [ ] Implement parallel store hook execution
-- [ ] Implement Non-Mutable store hook execution
-
diff --git a/doc/src/05100-lib-store.md b/doc/src/05100-lib-store.md
index 2055038..d4119a3 100644
--- a/doc/src/05100-lib-store.md
+++ b/doc/src/05100-lib-store.md
@@ -3,8 +3,7 @@
The store is the heart of everything. Here lives the data, the complexity and
the performance bottleneck.
-The store offeres read/write access to all entries, a hook system to do
-on-the-fly modification of incoming/outgoing files and so on.
+The store offeres read/write access to all entries.
The store itself does not offer functionality, but has a commandline interface
"imag-store" which can do basic things with the store.
@@ -13,5 +12,4 @@ The store itself does not offer functionality, but has a commandline interface
### Long-term TODO
- [ ] Merge with `libimagrt`
-- [ ] Merge with `libimagstorestdhook`
diff --git a/imagrc.toml b/imagrc.toml
index 37a940d..5c5598b 100644
--- a/imagrc.toml
+++ b/imagrc.toml
@@ -33,148 +33,3 @@ readline_prompt = ">> "
# lives implicitely
implicit-create = false
-# Hooks which get executed right before the Store is closed.
-# They get the store path as StoreId passed, so they can alter the complete
-# store, so these hooks should be chosen carefully.
-store-unload-hook-aspects = [ "debug", "vcs" ]
-
-pre-create-hook-aspects = [ "debug", "vcs" ]
-post-create-hook-aspects = [ "debug", "vcs" ]
-
-pre-move-hook-aspects = [ "debug" ]
-post-move-hook-aspects = [ "debug" ]
-
-pre-retrieve-hook-aspects = [ "debug", "vcs" ]
-post-retrieve-hook-aspects = [ "debug", "vcs" ]
-
-pre-update-hook-aspects = [ "debug", "vcs" ]
-post-update-hook-aspects = [ "debug", "vcs" ]
-
-pre-delete-hook-aspects = [ "debug", "vcs" ]
-post-delete-hook-aspects = [ "debug", "vcs" ]
-
-[store.aspects.debug]
-parallel = false
-mutable_hooks = true
-
-[store.aspects.vcs]
-parallel = false
-mutable_hooks = false
-
-[store.hooks.stdhook_debug]
-aspect = "debug"
-
-[store.hooks.stdhook_git_update]
-aspect = "vcs"
-
-# set to false to disable
-enabled = true
-
-# Fail if the repository cannot be opened. If this is set to `false`, the error
-# will be printed, but will not abort the store operation. `true` will print the
-# error and abort the store action.
-abort_on_repo_init_failure = true
-
-# Ensure to be on this branche before doing anything.
-ensure_branch = "refs/heads/master"
-
-# Try to checkout the ensure_branch if it isn't checked out
-try_checkout_ensure_branch = true
-
-# Commit configuration
-[store.hooks.stdhook_git_update.commit]
-
-# Enable committing here. If not enabled, the "stdhook_git_storeunload" hook
-# will commit all changes in one commit when the store is closed.
-enabled = false
-
-# Whether to do the commit interactively
-interactive = false
-
-# Set to true to use the $EDITOR for the commit, to false to do on commandline
-# When committing without editor, only a single line is allowed as commit
-# message
-interactive_editor = false
-
-# Commit message if the commit is not interactive
-message = "Update"
-
-[store.hooks.stdhook_git_delete]
-aspect = "vcs"
-
-# set to false to disable
-enabled = true
-
-# Fail if the repository cannot be opened. If this is set to `false`, the error
-# will be printed, but will not abort the store operation. `true` will print the
-# error and abort the store action.
-abort_on_repo_init_failure = true
-
-# Ensure to be on this branche before doing anything.
-ensure_branch = "refs/heads/master"
-
-# Try to checkout the ensure_branch if it isn't checked out
-try_checkout_ensure_branch = true
-
-# Commit configuration
-[store.hooks.stdhook_git_delete.commit]
-
-# Enable committing here. If not enabled, the "stdhook_git_storeunload" hook
-# will commit all changes in one commit when the store is closed.
-enabled = false
-
-# Whether to do the commit interactively
-interactive = false
-
-# Set to true to use the $EDITOR for the commit, to false to do on commandline
-# When committing without editor, only a single line is allowed as commit
-# message
-interactive_editor = false
-
-# Commit message if the commit is not interactive
-message = "Deleted"
-
-[store.hooks.stdhook_git_storeunload]
-aspect = "vcs"
-
-# set to false to disable
-enabled = true
-
-# Fail if the repository cannot be opened. If this is set to `false`, the error
-# will be printed, but will not abort the store operation. `true` will print the
-# error and abort the store action.
-abort_on_repo_init_failure = true
-
-# Ensure to be on this branche before doing anything.
-ensure_branch = "refs/heads/master"
-
-# Try to checkout the ensure_branch if it isn't checked out
-try_checkout_ensure_branch = true
-
-# Commit configuration
-[store.hooks.stdhook_git_storeunload.commit]
-
-# Enable on-unload-committing, causing the store-unload hook to commit the
-# changes to the store. This has no effect if the changes were already committed
-# by the other git hooks.
-enabled = true
-
-# Do a git-add on all files that are not in the index yet, before committing.
-# This must be turned on, as we do not support adding with "Update" hooks and
-# only committing with the "Drop" hook, yet.
-# So, effectively, disabling this will disable committing.
-#
-# If not set: false
-add_wt_changes = true
-
-# Whether to do the commit interactively
-interactive = false
-
-# Set to true to use the $EDITOR for the commit, to false to do on commandline
-# When committing without editor, only a single line is allowed as commit
-# message
-interactive_editor = false
-
-# Commit message if the commit is not interactive
-message = "Commit on drop"
-
diff --git a/libimagentrylink/src/internal.rs b/libimagentrylink/src/internal.rs
index 5949495..99205a3 100644
--- a/libimagentrylink/src/internal.rs
+++ b/libimagentrylink/src/internal.rs
@@ -585,6 +585,265 @@ fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<LinkIter> {
Ok(LinkIter::new(links))
}
+pub mod store_check {
+ use libimagstore::store::Store;
+
+ pub mod error {
+ generate_error_imports!();
+
+ use libimagstore::storeid::StoreId;
+
+ #[derive(Debug)]
+ pub enum StoreLinkConsistencyErrorCustomData {
+ DeadLink {
+ target: StoreId
+ },
+ OneDirectionalLink {
+ source: StoreId,
+ target: StoreId
+ },
+ }
+
+ impl Display for StoreLinkConsistencyErrorCustomData {
+
+ fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
+ use self::StoreLinkConsistencyErrorCustomData as SLCECD;
+ match self {
+ &SLCECD::DeadLink { ref target } => {
+ try!(write!(fmt, "Dead Link to '{}'", target))
+ },
+
+ &SLCECD::OneDirectionalLink { ref source, ref target } => {
+ try!(write!(fmt,
+ "Link from '{}' to '{}' does exist, but not other way round",
+ source, target))
+ }
+ };
+ Ok(())
+ }
+
+ }
+
+ generate_custom_error_types!(
+ StoreLinkConsistencyError,
+ StoreLinkConsistencyErrorKind,
+ StoreLinkConsistencyErrorCustomData,
+ StoreLinkConsistencyError => "Links in the store are not consistent",
+ LinkHandlingError => "Error in link handling",
+ StoreError => "Error while talking to the store"
+ );
+
+ generate_result_helper!(StoreLinkConsistencyError, StoreLinkConsistencyErrorKind);
+ generate_option_helper!(StoreLinkConsistencyError, StoreLinkConsistencyErrorKind);
+ }
+
+ pub use self::error::StoreLinkConsistencyError;
+ pub use self::error::StoreLinkConsistencyErrorKind;
+ pub use self::error::MapErrInto;
+
+ pub mod result {
+ use std::result::Result as RResult;
+ use internal::store_check::error::StoreLinkConsistencyError as SLCE;
+
+ pub type Result<T> = RResult<T, SLCE>;
+ }
+
+ use self::result::Result;
+
+ pub trait StoreLinkConsistentExt {
+ fn check_link_consistency(&self) -> Result<()>;
+ }
+
+ impl StoreLinkConsistentExt for Store {
+ fn check_link_consistency(&self) -> Result<()> {
+ use std::collections::HashMap;
+
+ use self::error::StoreLinkConsistencyErrorKind as SLCEK;
+ use self::error::StoreLinkConsistencyError as SLCE;
+ use self::error::StoreLinkConsistencyErrorCustomData as SLCECD;
+ use error::LinkErrorKind as LEK;
+ use result::Result as LResult;
+ use internal::InternalLinker;
+
+ use libimagstore::store::StoreObject;
+ use libimagstore::storeid::StoreId;
+ use libimagerror::iter::TraceIterator;
+ use libimagerror::into::IntoError;
+ use libimagutil::iter::FoldResult;
+
+ // 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
+ .walk("") // this is a hack... I know...
+ .filter_map(|obj: StoreObject| match obj {
+ StoreObject::Id(id) => Some(id),
+ _ => None
+ }) // Only ids are interesting
+ .fold(Ok(HashMap::new()), |acc, sid| {
+ acc.and_then(|mut state| {
+ debug!("Checking entry: '{}'", sid);
+
+ match try!(self.get(sid).map_err_into(SLCEK::StoreError)) {
+ Some(fle) => {
+ debug!("Found FileLockEntry");
+
+ let fle_loc = fle.get_location();
+
+ let internal_links = fle
+ .get_internal_links()
+ .map_err_into(SLCEK::StoreError)?
+ .into_getter(self) // get the FLEs from the Store
+ .trace_unwrap(); // trace all Err(e)s and get the Ok(fle)s
+
+ for internal_link in internal_links {
+ let il_loc = internal_link.get_location();
+
+ state
+ .entry(il_loc.clone())
+ .or_insert(Linking::default())
+ .incoming
+ .push(fle_loc.clone());
+
+ // Make sure an empty linking object is present for the
+ // current StoreId object
+ state
+ .entry(fle_loc.clone())
+ .or_insert(Linking::default())
+ .outgoing
+ .push(il_loc.clone());
+ }
+
+ Ok(state)
+ },
+ None => {
+ debug!("No entry");
+ Ok(state)
+ }
+ }
+ })
+ })
+ };
+
+ /// Helper to check whethre all StoreIds in the network actually exists
+ ///
+ /// Because why not?
+ let all_collected_storeids_exist = |network: &HashMap<StoreId, Linking>| -> LResult<()> {
+ network
+ .iter()
+ .fold_result(|(id, _)| {
+ if is_match!(self.get(id.clone()), Ok(Some(_))) {
+ debug!("Exists in store: {:?}", id);
+
+ let exists = {
+ use error::MapErrInto as MEI;
+ try!(MEI::map_err_into(id.exists(), LEK::StoreReadError))
+ };
+
+ if !exists {
+ warn!("Does exist in store but not on FS: {:?}", id);
+ Err(LEK::LinkTargetDoesNotExist.into_error())
+ } else {
+ Ok(())
+ }
+ } else {
+ warn!("Does not exist in store: {:?}", id);
+ Err(LEK::LinkTargetDoesNotExist.into_error())
+ }
+ })
+ };
+
+ /// Helper function to create a SLCECD::OneDirectionalLink error object
+ #[inline]
+ let mk_one_directional_link_err = |src: StoreId, target: StoreId| -> SLCE {
+ // construct the error
+ let custom = SLCECD::OneDirectionalLink {
+ source: src,
+ target: target,
+ };
+
+ SLCEK::StoreLinkConsistencyError
+ .into_error()
+ .with_custom_data(custom)
+ };
+
+ /// 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<()> {
+ linking
+ .incoming
+ .iter()
+ .fold_result(|link| {
+
+ // 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 {
+ Err(mk_one_directional_link_err(src.clone(), link.clone()))
+ } else {
+ 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<()> {
+ linking
+ .outgoing
+ .iter()
+ .fold_result(|link| {
+
+ // 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 {
+ Err(mk_one_directional_link_err(link.clone(), src.clone()))
+ } else {
+ Ok(())
+ }
+ })
+ };
+
+ aggregate_link_network(&self)
+ .and_then(|nw| {
+ all_collected_storeids_exist(&nw)
+ .map(|_| nw)
+ .map_err_into(SLCEK::LinkHandlingError)
+ })
+ .and_then(|nw| {
+ nw.iter().fold_result(|(id, linking)| {
+ try!(incoming_links_exists_as_outgoing_links(id, linking, &nw));
+ try!(outgoing_links_exist_as_incoming_links(id, linking, &nw));
+ Ok(())
+ })
+ })
+ .map(|_| ())
+ }
+ }
+
+}
+
#[cfg(test)]
mod test {
use std::path::PathBuf;
diff --git a/libimagerror/src/error_gen.rs b/libimagerror/src/error_gen.rs
index 7a9fc18..ccfd157 100644
--- a/libimagerror/src/error_gen.rs
+++ b/libimagerror/src/error_gen.rs
@@ -118,7 +118,10 @@ macro_rules! generate_custom_error_types {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
try!(write!(fmt, "[{}]", self.err_type));
- Ok(())
+ match self.custom_data {
+ Some(ref c) => write!(fmt, "{}", c),
+ None => Ok(()),
+ }
}
}
@@ -215,6 +218,13 @@ macro_rules! generate_error_types {
) => {
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
+
+ impl Display for SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {
+ fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> {
+ Ok(())
+ }
+ }
+
generate_custom_error_types!($name, $kindname,
SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
$($kind => $string),*);
@@ -241,6 +251,12 @@ mod test {
pub othr: i64,
}
+ impl Display for CustomData {
+ fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
+ Ok(())
+ }
+ }
+
generate_error_imports!();
#[allow(dead_code)]
diff --git a/libimagrt/Cargo.toml b/libimagrt/Cargo.toml
index 29cf995..a812e69 100644
--- a/libimagrt/Cargo.toml
+++ b/libimagrt/Cargo.toml
@@ -26,9 +26,6 @@ ansi_term = "0.9"
[dependencies.libimagstore]
path = "../libimagstore"
-[dependencies.libimagstorestdhook]
-path = "../libimagstorestdhook"
-
[dependencies.libimagutil]
path = "../libimagutil"
diff --git a/libimagrt/src/lib.rs b/libimagrt/src/lib.rs
index 93dc23e..1670418 100644
--- a/libimagrt/src/lib.rs
+++ b/libimagrt/src/lib.rs
@@ -44,7 +44,6 @@ extern crate clap;
extern crate toml;
extern crate libimagstore;
-extern crate libimagstorestdhook;
extern crate libimagutil;
#[macro_use] extern crate libimagerror;
diff --git a/libimagrt/src/runtime.rs b/libimagrt/src/runtime.rs
index 07cd86c..33bcfd5 100644
--- a/libimagrt/src/runtime.rs
+++ b/libimagrt/src/runtime.rs
@@ -61,15 +61,7 @@ impl<'a> Runtime<'a> {
use clap::Shell;
- use libimagstore::hook::position::HookPosition as HP;
- use libimagstore::hook::Hook;
- use libimagstore::error::StoreErrorKind;
- use libimagstorestdhook::debug::DebugHook;
- use libimagstorestdhook::vcs::git::delete::DeleteHook as GitDeleteHook;
- use libimagstorestdhook::vcs::git::update::UpdateHook as GitUpdateHook;
- use libimagstorestdhook::vcs::git::store_unload::StoreUnloadHook as GitStoreUnloadHook;
use libimagerror::trace::trace_error;
- use libimagerror::trace::trace_error_dbg;
use libimagerror::into::IntoError;
use configuration::error::ConfigErrorKind;
@@ -142,52 +134,7 @@ impl<'a> Runtime<'a> {
write!(stderr(), "Store-config: {:?}\n", store_config).ok();
}
- Store::new(storepath.clone(), store_config).map(|mut store| {
- // If we are debugging, generate hooks for all positions
- if is_debugging {
- let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
- (Box::new(DebugHook::new(HP::PreCreate)) , "debug", HP::PreCreate),
- (Box::new(DebugHook::new(HP::PostCreate)) , "debug", HP::PostCreate),
- (Box::new(DebugHook::new(HP::PreRetrieve)) , "debug", HP::PreRetrieve),
- (Box::new(DebugHook::new(HP::PostRetrieve)) , "debug", HP::PostRetrieve),
- (Box::new(DebugHook::new(HP::PreUpdate)) , "debug", HP::PreUpdate),
- (Box::new(DebugHook::new(HP::PostUpdate)) , "debug", HP::PostUpdate),
- (Box::new(DebugHook::new(HP::PreDelete)) , "debug", HP::PreDelete),
- (Box::new(DebugHook::new(HP::PostDelete)) , "debug", HP::PostDelete),
- ];
-
- // If hook registration fails, trace the error and warn, but continue.
- for (hook, aspectname, position) in hooks {
- if let Err(e) = store.register_hook(position, &String::from(aspectname), hook) {
- if e.err_type() == StoreErrorKind::HookRegisterError {
- trace_error_dbg(&e);
- warn!("Registering debug hook with store failed");
- } else {
- trace_error(&e);
- };
- }
- }
- }
-
- let sp = storepath;
-
- let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
- (Box::new(GitDeleteHook::new(sp.clone(), HP::PostDelete)), "vcs", HP::PostDelete),
- (Box::new(GitUpdateHook::new(sp.clone(), HP::PostUpdate)), "vcs", HP::PostUpdate),
- (Box::new(GitStoreUnloadHook::new(sp)), "vcs", HP::StoreUnload),
- ];
-
- for (hook, aspectname, position) in hooks {
- if let Err(e) = store.register_hook(position, &String::from(aspectname), hook) {
- if e.err_type() == StoreErrorKind::HookRegisterError {
- trace_error_dbg(&e);
- warn!("Registering git hook with store failed");
- } else {
- trace_error(&e);
- };
- }
- }
-
+ Store::new(storepath.clone(), store_config).map(|store| {
Runtime {
cli_matches: matches,
configuration: cfg,
diff --git a/libimagstore/Cargo.toml b/libimagstore/Cargo.toml
index 4089fed..acee580 100644
--- a/libimagstore/Cargo.toml
+++ b/libimagstore/Cargo.toml
@@ -66,3 +66,8 @@ verify = []
#
early-panic=[]
+# File system locking
+#
+# Enable this feature to enable file-system locking in the store.
+fs-locking = []
+
diff --git a/libimagstore/src/configuration.rs b/libimagstore/src/configuration.rs
index 06e0d3c..0dfc049 100644
--- a/libimagstore/src/configuration.rs
+++ b/libimagstore/src/configuration.rs
@@ -20,160 +20,19 @@
use toml::Value;
use libimagerror::into::IntoError;
-use libimagutil::iter::FoldResult;
use store::Result;
/// Check whether the configuration is valid for the store
-///
-/// The passed `Value` _must be_ the `[store]` sub-tree of the configuration. Otherwise this will
-/// fail.
-///
-/// It checks whether the configuration looks like the store wants it to be:
-///
-/// ```toml
-/// [store]
-/// pre-create-hook-aspects = [ "misc", "encryption", "version-control"]
-///
-/// [store.aspects.misc]
-/// parallel = true
-///
-/// [store.aspects.encryption]
-/// parallel = false
-///
-/// [store.aspects.version-control]
-/// parallel = false
-///
-/// [store.hooks.gnupg]
-/// aspect = "encryption"
-/// key = "0x123456789"
-///
-/// [store.hooks.git]
-/// aspect = "version-control"
-/// ```
-///
-/// It checks:
-/// * Whether all the maps are there (whether store, store.aspects, store.aspects.example are all
-/// maps)
-/// * Whether each aspect configuration has a "parallel = <Boolean>" setting
-/// * Whether each hook congfiguration has a "aspect = <String>" setting
-///
-/// It does NOT check:
-/// * Whether all aspects which are used in the hook configuration are also configured
-///
-/// No configuration is a valid configuration, as the store will use the most conservative settings
-/// automatically. This has also performance impact, as all hooks run in no-parallel mode then.
-/// You have been warned!
-///
-///
pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
- use std::collections::BTreeMap;
use error::StoreErrorKind as SEK;
if config.is_none() {
return Ok(());
}
- /// Check whether the config has a key with a string array.
- /// The `key` is the key which is checked
- /// The `kind` is the error kind which is used as `cause` if there is an error, so we can
- /// indicate via error type which key is missing
- fn has_key_with_string_ary(v: &BTreeMap<String, Value>, key: &str,
- kind: SEK) -> Result<()> {
- v.get(key)
- .ok_or_else(|| {
- warn!("Required key '{}' is not in store config", key);
- SEK::ConfigKeyMissingError.into_error_with_cause(Box::new(kind.into_error()))
- })
- .and_then(|t| match *t {
- Value::Array(ref a) => {
- a.iter().fold_result(|elem| if is_match!(*elem, Value::String(_)) {
- Ok(())
- } else {
- let cause = Box::new(kind.into_error());
- Err(SEK::ConfigTypeError.into_error_with_cause(cause))
- })
- },
- _ => {
- warn!("Key '{}' in store config should contain an array", key);
- Err(SEK::ConfigTypeError.into_error_with_cause(Box::new(kind.into_error())))
- }
- })
- }
-
- /// Check that
- /// * the top-level configuration
- /// * is a table
- /// * where all entries of a key `section` (eg. "hooks" or "aspects")
- /// * Are maps
- /// * where each has a key `key` (eg. "aspect" or "parallel")
- /// * which fullfills constraint `f` (typecheck)
- fn check_all_inner_maps_have_key_with<F>(store_config: &BTreeMap<String, Value>,
- section: &str,
- key: &str,
- f: F)
- -> Result<()>
- where F: Fn(&Value) -> bool
- {
- store_config.get(section) // The store config has the section `section`
- .ok_or_else(|| {
- warn!("Store config expects section '{}' to be present, but isn't.", section);
- SEK::ConfigKeyMissingError.into_error()
- })
- .and_then(|section_table| match *section_table { // which is
- Value::Table(ref section_table) => // a table
- section_table.iter().fold_result(|(inner_key, cfg)| {
- match *cfg {
- Value::Table(ref hook_config) => { // are tables
- // with a key
- let hook_aspect_is_valid = try!(hook_config.get(key)
- .map(|hook_aspect| f(&hook_aspect))
- .ok_or(SEK::ConfigKeyMissingError.into_error())
- );
-
- if !hook_aspect_is_valid {
- Err(SEK::ConfigTypeError.into_error())
- } else {
- Ok(())
- }
- },
- _ => {
- warn!("Store config expects '{}' to be in '{}.{}', but isn't.",
- key, section, inner_key);
- Err(SEK::ConfigKeyMissingError.into_error())
- }
- }
- }),
- _ => {
- warn!("Store config expects '{}' to be a Table, but isn't.", section);
- Err(SEK::ConfigTypeError.into_error())
- }
- })
- }
-
match *config {
- Some(Value::Table(ref t)) => {
- try!(has_key_with_string_ary(t, "store-unload-hook-aspects", SEK::ConfigKeyUnloadAspectsError));
-
- try!(has_key_with_string_ary(t, "pre-create-hook-aspects", SEK::ConfigKeyPreCreateAspectsError));
- try!(has_key_with_string_ary(t, "post-create-hook-aspects", SEK::ConfigKeyPostCreateAspectsError));
- try!(has_key_with_string_ary(t, "pre-retrieve-hook-aspects", SEK::ConfigKeyPreRetrieveAspectsError));
- try!(has_key_with_string_ary(t, "post-retrieve-hook-aspects", SEK::ConfigKeyPostRetrieveAspectsError));
- try!(has_key_with_string_ary(t, "pre-update-hook-aspects", SEK::ConfigKeyPreUpdateAspectsError));
- try!(has_key_with_string_ary(t, "post-update-hook-aspects", SEK::ConfigKeyPostUpdateAspectsError));
- try!(has_key_with_string_ary(t, "pre-delete-hook-aspects", SEK::ConfigKeyPreDeleteAspectsError));
- try!(has_key_with_string_ary(t, "post-delete-hook-aspects", SEK::ConfigKeyPostDeleteAspectsError));
-
- // The section "hooks" has maps which have a key "aspect" which has a value of type
- // String
- try!(check_all_inner_maps_have_key_with(t, "hooks", "aspect",
- |asp| is_match!(asp, &Value::String(_))));
-
- // The section "aspects" has maps which have a key "parllel" which has a value of type
- // Boolean
- check_all_inner_maps_have_key_with(t, "aspects", "parallel",
- |asp| is_match!(asp, &Value::Boolean(_)))
- }
+ Some(Value::Table(_)) => Ok(()),
_ => {
warn!("Store config is no table");
Err(SEK::ConfigTypeError.into_error())
@@ -207,152 +66,6 @@ pub fn config_implicit_store_create_allowed(config: Option<&Value>) -> bool {
}).unwrap_or(false)
}
-pub fn get_store_unload_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("store-unload-hook-aspects", value)
-}
-
-pub fn get_pre_create_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("pre-create-hook-aspects", value)
-}
-
-pub fn get_post_create_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("post-create-hook-aspects", value)
-}
-
-pub fn get_pre_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("pre-retrieve-hook-aspects", value)
-}
-
-pub fn get_post_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("post-retrieve-hook-aspects", value)
-}
-
-pub fn get_pre_update_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("pre-update-hook-aspects", value)
-}
-
-pub fn get_post_update_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("post-update-hook-aspects", value)
-}
-
-pub fn get_pre_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("pre-delete-hook-aspects", value)
-}
-
-pub fn get_post_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("post-delete-hook-aspects", value)
-}
-
-pub fn get_pre_move_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("pre-move-hook-aspects", value)
-}
-
-pub fn get_post_move_aspect_names(value: &Option<Value>) -> Vec<String> {
- get_aspect_names_for_aspect_position("post-move-hook-aspects", value)
-}
-
-#[derive(Debug)]
-pub struct AspectConfig {
- parallel: bool,
- mutable_hooks: bool,
- config: Value,
-}
-
-impl AspectConfig {
-
- pub fn new(init: Value) -> AspectConfig {
- debug!("Trying to parse AspectConfig from: {:?}", init);
- let parallel = AspectConfig::is_parallel(&init);
- let muthooks = AspectConfig::allows_mutable_hooks(&init);
- AspectConfig {
- config: init,
- mutable_hooks: muthooks,
- parallel: parallel,
- }
- }
-
- fn is_parallel(init: &Value) -> bool {
- match *init {
- Value::Table(ref t) =>
- t.get("parallel")
- .map_or(false, |value| {
- match *value {
- Value::Boolean(b) => b,
- _ => false,
- }
- }),
- _ => false,
- }
- }
-
- fn allows_mutable_hooks(init: &Value) -> bool {
- match *init {
- Value::Table(ref t) =>
- t.get("mutable_hooks")
- .map_or(false, |value| {
- match *value {
- Value::Boolean(b) => b,
- _ => false,
- }
- }),
- _ => false,
- }
- }
-
- pub fn allow_mutable_hooks(&self) -> bool {
- self.mutable_hooks
- }
-
- /// Get the aspect configuration for an aspect.
- ///
- /// Pass the store configuration object, this searches in `[aspects][<aspect_name>]`.
- ///
- /// Returns `None` if one of the keys in the chain is not available
- pub fn get_for(v: &Option<Value>, a_name: String) -> Option<AspectConfig> {
- debug!("Get aspect configuration for {:?} from {:?}", a_name, v);
- let res = match *v {
- Some(Value::Table(ref tabl)) => {
- match tabl.get("aspects") {
- Some(&Value::Table(ref tabl)) => {
- tabl.get(&a_name[..]).map(|asp| AspectConfig::new(asp.clone()))
- },
-
- _ => None,
- }
- },
- _ => None,
- };
- debug!("Found aspect configuration for {:?}: {:?}", a_name, res);
- res
- }
-
-}
-
-fn get_aspect_names_for_aspect_position(config_name: &'static str, value: &Option<Value>) -> Vec<String> {
- use itertools::Itertools;
- let mut v = vec![];
-
- match *value {
- Some(Value::Table(ref t)) => {
- match t.get(config_name) {
- Some(&Value::Array(ref a)) => {
- for elem in a {
- match *elem {
- Value::String(ref s) => v.push(s.clone()),
- _ => warn!("Non-String in configuration, inside '{}'", config_name),
- }
- }
- },
- _ => warn!("'{}' configuration key should contain Array, does not", config_name),
- };
- },
- None => warn!("No store configuration, cannot get '{}'", config_name),
- _ => warn!("Configuration is not a table"),
- }
-
- v.into_iter().unique().collect()
-}
-
#[cfg(test)]
mod tests {
use toml::de::from_str as toml_from_str;
@@ -387,312 +100,5 @@ mod tests {
assert!(config_implicit_store_create_allowed(Some(config).as_ref()));
}
- #[test]
- fn test_get_store_unload_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- let names = get_store_unload_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_store_unload_aspect_names_empty() {
- let config = toml_from_str(r#"
- store-unload-hook-aspects = [ ]
- "#).unwrap();
- let names = get_store_unload_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_store_unload_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- store-unload-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_store_unload_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_pre_create_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_pre_create_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_pre_create_aspect_names_empty() {
- let config = toml_from_str(r#"
- pre-create-hook-aspects = [ ]
- "#).unwrap();
- let names = get_pre_create_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_pre_create_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- pre-create-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_pre_create_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_post_create_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_post_create_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_post_create_aspect_names_empty() {
- let config = toml_from_str(r#"
- post-create-hook-aspects = [ ]
- "#).unwrap();
- let names = get_post_create_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_post_create_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- post-create-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_post_create_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_pre_retrieve_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_pre_retrieve_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_pre_retrieve_aspect_names_empty() {
- let config = toml_from_str(r#"
- pre-retrieve-hook-aspects = [ ]
- "#).unwrap();
- let names = get_pre_retrieve_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_pre_retrieve_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- pre-retrieve-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_pre_retrieve_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_post_retrieve_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_post_retrieve_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_post_retrieve_aspect_names_empty() {
- let config = toml_from_str(r#"
- post-retrieve-hook-aspects = [ ]
- "#).unwrap();
- let names = get_post_retrieve_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_post_retrieve_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- post-retrieve-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_post_retrieve_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_pre_update_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_pre_update_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_pre_update_aspect_names_empty() {
- let config = toml_from_str(r#"
- pre-update-hook-aspects = [ ]
- "#).unwrap();
- let names = get_pre_update_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_pre_update_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- pre-update-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_pre_update_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_post_update_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_post_update_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_post_update_aspect_names_empty() {
- let config = toml_from_str(r#"
- post-update-hook-aspects = [ ]
- "#).unwrap();
- let names = get_post_update_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_post_update_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- post-update-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_post_update_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_pre_delete_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_pre_delete_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_pre_delete_aspect_names_empty() {
- let config = toml_from_str(r#"
- pre-delete-hook-aspects = [ ]
- "#).unwrap();
- let names = get_pre_delete_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_pre_delete_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- pre-delete-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_pre_delete_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_post_delete_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_post_delete_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_post_delete_aspect_names_empty() {
- let config = toml_from_str(r#"
- post-delete-hook-aspects = [ ]
- "#).unwrap();
- let names = get_post_delete_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_post_delete_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- post-delete-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_post_delete_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_pre_move_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_pre_move_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_pre_move_aspect_names_empty() {
- let config = toml_from_str(r#"
- pre-move-hook-aspects = [ ]
- "#).unwrap();
- let names = get_pre_move_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_pre_move_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- pre-move-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_pre_move_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_post_move_aspect_names_not_existent() {
- let config = toml_from_str("").unwrap();
- assert!(get_post_move_aspect_names(&Some(config)).is_empty());
- }
-
- #[test]
- fn test_get_post_move_aspect_names_empty() {
- let config = toml_from_str(r#"
- post-move-hook-aspects = [ ]
- "#).unwrap();
- let names = get_post_move_aspect_names(&Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_post_move_aspect_names_one_elem() {
- let config = toml_from_str(r#"
- post-move-hook-aspects = [ "example" ]
- "#).unwrap();
- let names = get_post_move_aspect_names(&Some(config));
- assert_eq!(1, names.len());
- assert_eq!("example", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_aspect_names_for_aspect_position_arbitrary_empty() {
- let config = toml_from_str(r#"
- test-key = [ ]
- "#).unwrap();
- let names = get_aspect_names_for_aspect_position("test-key", &Some(config));
- assert!(names.is_empty());
- }
-
- #[test]
- fn test_get_aspect_names_for_aspect_position_arbitrary_one() {
- let config = toml_from_str(r#"
- test-key = [ "test-value" ]
- "#).unwrap();
- let names = get_aspect_names_for_aspect_position("test-key", &Some(config));
- assert_eq!(1, names.len());
- assert_eq!("test-value", names.iter().next().unwrap());
- }
-
- #[test]
- fn test_get_aspect_names_for_aspect_position_arbitrary_duplicated() {
- let config = toml_from_str(r#"
- test-key = [ "test-value", "test-value" ]
- "#).unwrap();
- let names = get_aspect_names_for_aspect_position("test-key", &Some(config));
- assert_eq!(1, names.len());
- let mut iter = names.iter();
- assert_eq!("test-value", iter.next().unwrap());
- assert!(iter.next().is_none());
- }
-
}
diff --git a/libimagstore/src/error.rs b/libimagstore/src/error.rs
index 09ed092..178a5e8 100644
--- a/libimagstore/src/error.rs
+++ b/libimagstore/src/error.rs
@@ -23,21 +23,17 @@ use std::convert::From;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}
+impl Display for CustomErrorData {
+ fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> {
+ Ok(()) // Do nothing here, we don't need to print smth
+ }
+}
+
generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
ConfigurationError => "Store Configuration Error",
ConfigTypeError => "Store configuration type error",
ConfigKeyMissingError => "Configuration Key missing",
- ConfigKeyUnloadAspectsError => "Config Key 'store-unload-hook-aspects' caused an error",
- ConfigKeyPreCreateAspectsError => "Config Key 'pre-create-hook-aspects' caused an error",
- ConfigKeyPostCreateAspectsError => "Config Key 'post-create-hook-aspects' caused an error",
- ConfigKeyPreRetrieveAspectsError => "Config Key 'pre-retrieve-hook-aspect' caused an error",
- ConfigKeyPostRetrieveAspectsError => "Config Key 'post-retrieve-hook-aspec' caused an error",
- ConfigKeyPreUpdateAspectsError => "Config Key 'pre-update-hook-aspects' caused an error",
- ConfigKeyPostUpdateAspectsError => "Config Key 'post-update-hook-aspects' caused an error",
- ConfigKeyPreDeleteAspectsError => "Config Key 'pre-delete-hook-aspects' caused an error",
- ConfigKeyPostDeleteAspectsError => "Config Key 'post-delete-hook-aspects' caused an error",
-
CreateStoreDirDenied => "Creating store directory implicitely denied",
FileError => "File Error",
IoError => "IO Error",
@@ -63,11 +59,6 @@ generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
HeaderPathTypeFailure => "Header has wrong type for path",
HeaderKeyNotFound => "Header Key not found",
HeaderTypeFailure => "Header type is wrong",
- HookRegisterError => "Hook register error",
- AspectNameNotFoundError => "Aspect name not found",
- HookExecutionError => "Hook execution error",
- PreHookExecuteError => "Pre-Hook execution error",
- PostHookExecuteError => "Post-Hook execution error",
StorePathLacksVersion => "The supplied store path has no version part",
GlobError => "glob() error",
EncodingError => "Encoding error",
diff --git a/libimagstore/src/hook/accessor.rs b/libimagstore/src/hook/accessor.rs
deleted file mode 100644
index 8bcca25..0000000
--- a/libimagstore/src/hook/accessor.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::fmt::Debug;
-
-use hook::result::HookResult;
-use store::FileLockEntry;
-use storeid::StoreId;
-
-pub trait StoreIdAccessor : Debug + Send {
- fn access(&self, &StoreId) -> HookResult<()>;
-}
-
-pub trait MutableHookDataAccessor : Debug + Send {
- fn access_mut(&self, &mut FileLockEntry) -> HookResult<()>;
-}
-
-pub trait NonMutableHookDataAccessor : Debug + Send {
- fn access(&self, &FileLockEntry) -> HookResult<()>;
-}
-
-#[derive(Debug)]
-pub enum HookDataAccessor<'a> {
- StoreIdAccess(&'a StoreIdAccessor),
- MutableAccess(&'a MutableHookDataAccessor),
- NonMutableAccess(&'a NonMutableHookDataAccessor),
-}
-
-pub trait HookDataAccessorProvider {
- fn accessor(&self) -> HookDataAccessor;
-}
-
-
diff --git a/libimagstore/src/hook/aspect.rs b/libimagstore/src/hook/aspect.rs
deleted file mode 100644
index 75cd595..0000000
--- a/libimagstore/src/hook/aspect.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 libimagerror::trace::trace_error;
-use libimagutil::iter::FoldResult;
-
-use store::FileLockEntry;
-use storeid::StoreId;
-use hook::Hook;
-use hook::result::HookResult;
-use hook::accessor::{StoreIdAccessor, MutableHookDataAccessor, NonMutableHookDataAccessor};
-use hook::accessor::HookDataAccessor as HDA;
-
-use hook::error::HookError as HE;
-use hook::error::HookErrorKind as HEK;
-use configuration::AspectConfig;
-
-#[derive(Debug)]
-pub struct Aspect {
- cfg: Option<AspectConfig>,
- name: String,
- hooks: Vec<Box<Hook>>,
-}
-
-impl Aspect {
-
- pub fn new(name: String, cfg: Option<AspectConfig>) -> Aspect {
- Aspect {
- cfg: cfg,
- name: name,
- hooks: vec![],
- }
- }
-
- pub fn name(&self) -> &String {
- &self.name
- }
-
- pub fn register_hook(&mut self, h: Box<Hook>) {
- self.hooks.push(h);
- }
-
-}
-
-impl StoreIdAccessor for Aspect {
- fn access(&self, id: &StoreId) -> HookResult<()> {
- let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect();
- if !accessors.iter().all(|a| {
- let x = is_match!(*a, HDA::StoreIdAccess(_));
- if !x {
- warn!("Denied execution of None-StoreId-Accessing Hook");
- debug!("Accessor: {:?}", a);
- debug!("in StoreIdAccess-Aspect execution: {:?}", self);
- }
- x
- }) {
- return Err(HE::new(HEK::AccessTypeViolation, None));
- }
-
- accessors.iter().fold_result(|accessor| {
- let res = match accessor {
- &HDA::StoreIdAccess(accessor) => accessor.access(id),
- _ => unreachable!(),
- };
- trace_hook_errors(res)
- })
- }
-}
-
-impl MutableHookDataAccessor for Aspect {
- fn access_mut(&self, fle: &mut FileLockEntry) -> HookResult<()> {
- debug!("Checking whether mutable hooks are allowed");
- debug!("-> config = {:?}", self.cfg);
-
- let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect();
-
- // TODO: Naiive implementation.
- // More sophisticated version would check whether there are _chunks_ of
- // NonMutableAccess accessors and execute these chunks in parallel. We do not have
- // performance concerns yet, so this is okay.
- accessors.iter().fold_result(|accessor| {
- let res = match accessor {
- &HDA::StoreIdAccess(ref accessor) => accessor.access(fle.get_location()),
- &HDA::NonMutableAccess(ref accessor) => accessor.access(fle),
- &HDA::MutableAccess(ref accessor) => {
- if !self.cfg.as_ref().map(|c| c.allow_mutable_hooks()).unwrap_or(false) {
- debug!("Apparently mutable hooks are not allowed... failing now.");
- return Err(HE::new(HEK::MutableHooksNotAllowed, None));
- }
-
- accessor.access_mut(fle)
- },
- };
- trace_hook_errors(res)
- })
- }
-}
-
-impl NonMutableHookDataAccessor for Aspect {
- fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
- let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect();
- if !accessors.iter().all(|a| {
- let x = is_match!(*a, HDA::NonMutableAccess(_));
- if !x {
- warn!("Denied execution of Non-Mutable-Accessing Hook");
- debug!("Accessor: {:?}", a);
- debug!("in StoreIdAccess-Aspect execution: {:?}", self);
- }
- x
- }) {
- return Err(HE::new(HEK::AccessTypeViolation, None));
- }
-
- accessors.iter().fold_result(|accessor| {
- let res = match accessor {
- &HDA::NonMutableAccess(accessor) => accessor.access(fle),
- _ => unreachable!(),
- };
- trace_hook_errors(res)
- })
- }
-}
-
-fn trace_hook_errors(res: HookResult<()>) -> HookResult<()> {
- res.or_else(|e| {
- if !e.is_aborting() {
- trace_error(&e);
- // ignore error if it is not aborting, as we printed it already
- Ok(())
- } else {
- Err(e)
- }
- })
-}
-
diff --git a/libimagstore/src/hook/error.rs b/libimagstore/src/hook/error.rs
deleted file mode 100644
index 0d890bf..0000000
--- a/libimagstore/src/hook/error.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::default::Default;
-
-generate_error_imports!();
-
-generate_custom_error_types!(HookError, HookErrorKind, CustomData,
- HookExecutionError => "Hook exec error",
- AccessTypeViolation => "Hook access type violation",
- MutableHooksNotAllowed => "Mutable Hooks are denied"
-);
-
-generate_result_helper!(HookError, HookErrorKind);
-
-#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
-pub struct CustomData {
- aborting: bool,
-}
-
-impl CustomData {
-
- pub fn aborting(mut self, b: bool) -> CustomData {
- self.aborting = b;
- self
- }
-
-}
-
-impl Default for CustomData {
-
- fn default() -> CustomData {
- CustomData {
- aborting: true
- }
- }
-
-}
-
-impl HookError {
-
- pub fn is_aborting(&self) -> bool {
- match self.custom_data {
- Some(b) => b.aborting,
- None => true
- }
- }
-
-}
diff --git a/libimagstore/src/hook/mod.rs b/libimagstore/src/hook/mod.rs
deleted file mode 100644
index 5c8e50f..0000000
--- a/libimagstore/src/hook/mod.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::fmt::Debug;
-
-use toml::Value;
-
-pub mod accessor;
-pub mod aspect;
-pub mod error;
-pub mod position;
-pub mod result;
-
-use hook::accessor::HookDataAccessorProvider;
-
-pub trait Hook : HookDataAccessorProvider + Debug + Send {
- fn name(&self) -> &'static str;
- fn set_config(&mut self, cfg: &Value);
-}
-
diff --git a/libimagstore/src/hook/position.rs b/libimagstore/src/hook/position.rs
deleted file mode 100644
index 8b9f926..0000000
--- a/libimagstore/src/hook/position.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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
-//
-
-#[derive(Debug, Clone)]
-pub enum HookPosition {
- StoreUnload,
-
- PreCreate,
- PostCreate,
- PreRetrieve,
- PostRetrieve,
- PreUpdate,
- PostUpdate,
- PreDelete,
- PostDelete,
-}
diff --git a/libimagstore/src/hook/result.rs b/libimagstore/src/hook/result.rs
deleted file mode 100644
index e25c722..0000000
--- a/libimagstore/src/hook/result.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 hook::error::HookError;
-
-pub type HookResult<T> = Result<T, HookError>;
diff --git a/libimagstore/src/lib.rs b/libimagstore/src/lib.rs
index 44fecc3..948865f 100644
--- a/libimagstore/src/lib.rs
+++ b/libimagstore/src/lib.rs
@@ -52,7 +52,6 @@ extern crate libimagutil;
pub mod storeid;
pub mod error;
-pub mod hook;
pub mod store;
mod configuration;
mod file_abstraction;
diff --git a/libimagstore/src/store.rs b/libimagstore/src/store.rs
index ef5725f..5b3ef6d 100644
--- a/libimagstore/src/store.rs
+++ b/libimagstore/src/store.rs
@@ -26,7 +26,6 @@ use std::sync::RwLock;
use std::io::Read;
use std::convert::From;
use std::convert::Into;
-use std::sync::Mutex;
use std::ops::Deref;
use std::ops::DerefMut;
use std::fmt::Formatter;
@@ -45,17 +44,8 @@ use storeid::{IntoStoreId, StoreId, StoreIdIterator};
use file_abstraction::FileAbstraction;
use toml_ext::*;
-use hook::aspect::Aspect;
-use hook::error::HookErrorKind;
-use hook::result::HookResult;
-use hook::accessor::{ MutableHookDataAccessor,
- StoreIdAccessor};
-use hook::position::HookPosition;
-use hook::Hook;
-
use libimagerror::into::IntoError;
use libimagerror::trace::trace_error;
-use libimagutil::iter::FoldResult;
use libimagutil::debug_result::*;
use self::glob_store_iter::*;
@@ -140,11 +130,18 @@ impl Iterator for Walk {
}
}
-
impl StoreEntry {
fn new(id: StoreId) -> Result<StoreEntry> {
let pb = try!(id.clone().into_pathbuf());
+
+ #[cfg(feature = "fs-lock")]
+ {
+ try!(open_file(pb.clone())
+ .and_then(|f| f.lock_exclusive().map_err_into(SEK::FileError))
+ .map_err_into(SEK::IoError));
+ }
+
Ok(StoreEntry {
id: id,
file: FileAbstraction::Absent(pb),
@@ -186,6 +183,19 @@ impl StoreEntry {
}
}
+#[cfg(feature = "fs-lock")]
+impl Drop for StoreEntry {
+
+ fn drop(self) {
+ self.get_entry()
+ .and_then(|entry| open_file(entry.get_location().clone()).map_err_into(SEK::IoError))
+ .and_then(|f| f.unlock().map_err_into(SEK::FileError))
+ .map_err_into(SEK::IoError)
+ }
+
+}
+
+
/// The Store itself, through this object one can interact with IMAG's entries
pub struct Store {
location: PathBuf,
@@ -195,23 +205,6 @@ pub struct Store {
///
configuration: Option<Value>,
- //
- // Registered hooks
- //
-
- store_unload_aspects : Arc<Mutex<Vec<Aspect>>>,
-
- pre_create_aspects : Arc<Mutex<Vec<Aspect>>>,
- post_create_aspects : Arc<Mutex<Vec<Aspect>>>,
- pre_retrieve_aspects : Arc<Mutex<Vec<Aspect>>>,
- post_retrieve_aspects : Arc<Mutex<Vec<Aspect>>>,
- pre_update_aspects : Arc<Mutex<Vec<Aspect>>>,
- post_update_aspects : Arc<Mutex<Vec<Aspect>>>,
- pre_delete_aspects : Arc<Mutex<Vec<Aspect>>>,
- post_delete_aspects : Arc<Mutex<Vec<Aspect>>>,
- pre_move_aspects : Arc<Mutex<Vec<Aspect>>>,
- post_move_aspects : Arc<Mutex<Vec<Aspect>>>,
-
///
/// Internal Path->File cache map
///
@@ -237,8 +230,6 @@ impl Store {
///
/// If the path exists and is a file, the operation is aborted as well, an error is returned.
///
- /// After that, the store hook aspects are created and registered in the store.
- ///
/// # Return values
///
/// - On success: Store object
@@ -273,88 +264,9 @@ impl Store {
return Err(SEK::StorePathExists.into_error());
}
- let store_unload_aspects = get_store_unload_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let pre_create_aspects = get_pre_create_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let post_create_aspects = get_post_create_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let pre_retrieve_aspects = get_pre_retrieve_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let post_retrieve_aspects = get_post_retrieve_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let pre_update_aspects = get_pre_update_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let post_update_aspects = get_post_update_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let pre_delete_aspects = get_pre_delete_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let post_delete_aspects = get_post_delete_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let pre_move_aspects = get_pre_move_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
- let post_move_aspects = get_post_move_aspect_names(&store_config)
- .into_iter().map(|n| {
- let cfg = AspectConfig::get_for(&store_config, n.clone());
- Aspect::new(n, cfg)
- }).collect();
-
let store = Store {
location: location.clone(),
configuration: store_config,
-
- store_unload_aspects : Arc::new(Mutex::new(store_unload_aspects)),
-
- pre_create_aspects : Arc::new(Mutex::new(pre_create_aspects)),
- post_create_aspects : Arc::new(Mutex::new(post_create_aspects)),
- pre_retrieve_aspects : Arc::new(Mutex::new(pre_retrieve_aspects)),
- post_retrieve_aspects : Arc::new(Mutex::new(post_retrieve_aspects)),
- pre_update_aspects : Arc::new(Mutex::new(pre_update_aspects)),
- post_update_aspects : Arc::new(Mutex::new(post_update_aspects)),
- pre_delete_aspects : Arc::new(Mutex::new(pre_delete_aspects)),
- post_delete_aspects : Arc::new(Mutex::new(post_delete_aspects)),
- pre_move_aspects : Arc::new(Mutex::new(pre_move_aspects)),
- post_move_aspects : Arc::new(Mutex::new(post_move_aspects)),
entries: Arc::new(RwLock::new(HashMap::new())),
};
@@ -429,32 +341,19 @@ impl Store {
/// Creates the Entry at the given location (inside the entry)
///
- /// # Executed Hooks
- ///
- /// - Pre create aspects
- /// - post create aspects
- ///
/// # Return value
///
/// On success: FileLockEntry
///
/// On error:
/// - Errors StoreId::into_storeid() might return
- /// - CreateCallError(HookExecutionError(PreHookExecuteError(_)))
- /// of the first failing pre hook.
- /// - CreateCallError(HookExecutionError(PostHookExecuteError(_)))
- /// of the first failing post hook.
/// - CreateCallError(LockPoisoned()) if the internal lock is poisened.
/// - CreateCallError(EntryAlreadyExists()) if the entry exists already.
///
pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
let id = try!(id.into_storeid()).with_base(self.path().clone());
- if let Err(e) = self.execute_hooks_for_id(self.pre_create_aspects.clone(), &id) {
- return Err(e)
- .map_err_into(SEK::PreHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::CreateCallError)
- }
+
+ debug!("Creating id: '{}'", id);
{
let mut hsmap = match self.entries.write() {
@@ -463,21 +362,20 @@ impl Store {
};
if hsmap.contains_key(&id) {
+ debug!("Cannot create, internal cache already contains: '{}'", id);
return Err(SEK::EntryAlreadyExists.into_error()).map_err_into(SEK::CreateCallError);
}
hsmap.insert(id.clone(), {
+ debug!("Creating: '{}'", id);
let mut se = try!(StoreEntry::new(id.clone()));
se.status = StoreEntryStatus::Borrowed;
se
});
}
- let mut fle = FileLockEntry::new(self, Entry::new(id));
- self.execute_hooks_for_mut_file(self.post_create_aspects.clone(), &mut fle)
- .map_err_into(SEK::PostHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::CreateCallError)
- .map(|_| fle)
+ debug!("Constructing FileLockEntry: '{}'", id);
+
+ Ok(FileLockEntry::new(self, Entry::new(id)))
}
/// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
@@ -486,32 +384,17 @@ impl Store {
/// Implicitely creates a entry in the store if there is no entry with the id `id`. For a
/// non-implicitely-create look at `Store::get`.
///
- /// # Executed Hooks
- ///
- /// - Pre retrieve aspects
- /// - post retrieve aspects
- ///
/// # Return value
///
/// On success: FileLockEntry
///
/// On error:
/// - Errors StoreId::into_storeid() might return
- /// - RetrieveCallError(HookExecutionError(PreHookExecuteError(_)))
- /// of the first failing pre hook.
- /// - RetrieveCallError(HookExecutionError(PostHookExecuteError(_)))
- /// of the first failing post hook.
/// - RetrieveCallError(LockPoisoned()) if the internal lock is poisened.
///
pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
let id = try!(id.into_storeid()).with_base(self.path().clone());
- if let Err(e) = self.execute_hooks_for_id(self.pre_retrieve_aspects.clone(), &id) {
- return Err(e)
- .map_err_into(SEK::PreHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::RetrieveCallError)
- }
-
+ debug!("Retrieving id: '{}'", id);
let entry = try!({
self.entries
.write()
@@ -526,21 +409,12 @@ impl Store {
.map_err_into(SEK::RetrieveCallError)
});
- let mut fle = FileLockEntry::new(self, entry);
- self.execute_hooks_for_mut_file(self.post_retrieve_aspects.clone(), &mut fle)
- .map_err_into(SEK::PostHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::RetrieveCallError)
- .and(Ok(fle))
+ debug!("Constructing FileLockEntry: '{}'", id);
+ Ok(FileLockEntry::new(self, entry))
}
/// Get an entry from the store if it exists.
///
- /// # Executed Hooks
- ///
- /// - Pre get aspects
- /// - post get aspects
- ///
/// # Return value
///
/// On success: Some(FileLockEntry) or None
@@ -552,6 +426,8 @@ impl Store {
pub fn get<'a, S: IntoStoreId + Clone>(&'a self, id: S) -> Result<Option<FileLockEntry<'a>>> {
let id = try!(id.into_storeid()).with_base(self.path().clone());
+ debug!("Getting id: '{}'", id);
+
let exists = try!(id.exists()) || try!(self.entries
.read()
.map(|map| map.contains_key(&id))
@@ -582,6 +458,8 @@ impl Store {
let mut path = self.path().clone();
path.push(mod_name);
+ debug!("Retrieving for module: '{}'", mod_name);
+
path.to_str()
.ok_or(SE::new(SEK::EncodingError, None))
.and_then(|path| {
@@ -599,6 +477,7 @@ impl Store {
/// The difference between a `Walk` and a `StoreIdIterator` is that with a `Walk`, one can find
/// "collections" (folders).
pub fn walk<'a>(&'a self, mod_name: &str) -> Walk {
+ debug!("Creating Walk object for {}", mod_name);
Walk::new(self.path().clone(), mod_name)
}
@@ -607,6 +486,7 @@ impl Store {
/// See `Store::_update()`.
///
pub fn update<'a>(&'a self, entry: &mut FileLockEntry<'a>) -> Result<()> {
+ debug!("Updating FileLockEntry at '{}'", entry.get_location());
self._update(entry, false).map_err_into(SEK::UpdateCallError)
}
@@ -617,32 +497,17 @@ impl Store {
/// This method assumes that entry is dropped _right after_ the call, hence
/// it is not public.
///
- /// # Executed Hooks
- ///
- /// - Pre update aspects
- /// - post update aspects
- ///
/// # Return value
///
/// On success: Entry
///
/// On error:
- /// - UpdateCallError(HookExecutionError(PreHookExecuteError(_)))
- /// of the first failing pre hook.
- /// - UpdateCallError(HookExecutionError(PostHookExecuteError(_)))
- /// of the first failing post hook.
/// - UpdateCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - IdNotFound() if the entry was not found in the stor
/// - Errors Entry::verify() might return
/// - Errors StoreEntry::write_entry() might return
///
- fn _update<'a>(&'a self, mut entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
- let _ = try!(self.execute_hooks_for_mut_file(self.pre_update_aspects.clone(), &mut entry)
- .map_err_into(SEK::PreHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::UpdateCallError)
- );
-
+ fn _update<'a>(&'a self, entry: &mut FileLockEntry<'a>, modify_presence: bool) -> Result<()> {
let mut hsmap = match self.entries.write() {
Err(_) => return Err(SE::new(SEK::LockPoisoned, None)),
Ok(e) => e,
@@ -661,21 +526,12 @@ impl Store {
se.status = StoreEntryStatus::Present;
}
- self.execute_hooks_for_mut_file(self.post_update_aspects.clone(), &mut entry)
- .map_err_into(SEK::PostHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::UpdateCallError)
+ Ok(())
}
/// Retrieve a copy of a given entry, this cannot be used to mutate
/// the one on disk
///
- /// TODO: Create Hooks for retrieving a copy
- ///
- /// # Executed Hooks
- ///
- /// - (none yet)
- ///
/// # Return value
///
/// On success: Entry
@@ -687,6 +543,7 @@ impl Store {
///
pub fn retrieve_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
let id = try!(id.into_storeid()).with_base(self.path().clone());
+ debug!("Retrieving copy of '{}'", id);
let entries = match self.entries.write() {
Err(_) => {
return Err(SE::new(SEK::LockPoisoned, None))
@@ -705,32 +562,19 @@ impl Store {
/// Delete an entry
///
- /// # Executed Hooks
- ///
- /// - Pre delete aspects, if the id can be used
- /// - Post delete aspects, if the operation succeeded
- ///
/// # Return value
///
/// On success: ()
///
/// On error:
- /// - DeleteCallError(HookExecutionError(PreHookExecuteError(_)))
- /// of the first failing pre hook.
- /// - DeleteCallError(HookExecutionError(PostHookExecuteError(_)))
- /// of the first failing post hook.
/// - DeleteCallError(LockPoisoned()) if the internal write lock cannot be aquierd.
/// - DeleteCallError(FileNotFound()) if the StoreId refers to a non-existing entry.
/// - DeleteCallError(FileError()) if the internals failed to remove the file.
///
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
let id = try!(id.into_storeid()).with_base(self.path().clone());
- if let Err(e) = self.execute_hooks_for_id(self.pre_delete_aspects.clone(), &id) {
- return Err(e)
- .map_err_into(SEK::PreHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::DeleteCallError)
- }
+
+ debug!("Deleting id: '{}'", id);
{
let mut entries = match self.entries.write() {
@@ -758,26 +602,20 @@ impl Store {
}
}
- self.execute_hooks_for_id(self.post_delete_aspects.clone(), &id)
- .map_err_into(SEK::PostHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::DeleteCallError)
+ debug!("Deleted");
+ Ok(())
}
/// Save a copy of the Entry in another place
- /// Executes the post_move_aspects for the new id
- ///
- /// TODO: Introduce new aspect for `save_to()`.
pub fn save_to(&self, entry: &FileLockEntry, new_id: StoreId) -> Result<()> {
+ debug!("Saving '{}' to '{}'", entry.get_location(), new_id);
self.save_to_other_location(entry, new_id, false)
}
/// Save an Entry in another place
/// Removes the original entry
- /// Executes the post_move_aspects for the new id
- ///
- /// TODO: Introduce new aspect for `save_as()`.
pub fn save_as(&self, entry: FileLockEntry, new_id: StoreId) -> Result<()> {
+ debug!("Saving '{}' as '{}'", entry.get_location(), new_id);
self.save_to_other_location(&entry, new_id, true)
}
@@ -803,15 +641,13 @@ impl Store {
FileAbstraction::copy(&old_id_as_path, &new_id_as_path)
.and_then(|_| {
if remove_old {
+ debug!("Removing old '{:?}'", old_id_as_path);
FileAbstraction::remove_file(&old_id_as_path)
} else {
Ok(())
}
})
.map_err_into(SEK::FileError)
- .and_then(|_| self.execute_hooks_for_id(self.post_move_aspects.clone(), &new_id)
- .map_err_into(SEK::PostHookExecuteError)
- .map_err_into(SEK::HookExecutionError))
.map_err_into(SEK::MoveCallError)
}
@@ -826,14 +662,11 @@ impl Store {
///
/// This function returns an error in certain cases:
///
- /// * If pre-move-hooks error (if they return an error which indicates that the action should be
- /// aborted)
/// * If the about-to-be-moved entry is borrowed
/// * If the lock on the internal data structure cannot be aquired
/// * If the new path already exists
/// * If the about-to-be-moved entry does not exist
/// * If the FS-operation failed
- /// * If the post-move-hooks error (though the operation has succeeded then).
///
/// # Warnings
///
@@ -855,12 +688,7 @@ impl Store {
let new_id = new_id.with_base(self.path().clone());
let old_id = old_id.with_base(self.path().clone());
- if let Err(e) = self.execute_hooks_for_id(self.pre_move_aspects.clone(), &old_id) {
- return Err(e)
- .map_err_into(SEK::PreHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::MoveByIdCallError)
- }
+ debug!("Moving '{}' to '{}'", old_id, new_id);
{
let mut hsmap = match self.entries.write() {
@@ -900,10 +728,8 @@ impl Store {
}
- self.execute_hooks_for_id(self.pre_move_aspects.clone(), &new_id)
- .map_err_into(SEK::PostHookExecuteError)
- .map_err_into(SEK::HookExecutionError)
- .map_err_into(SEK::MoveByIdCallError)
+ debug!("Moved");
+ Ok(())
}
/// Gets the path where this store is on the disk
@@ -911,127 +737,6 @@ impl Store {
&self.location
}
- /// Register a hook in the store.
- ///
- /// A hook is registered by a position (when should the hook be executed) and an aspect name.
- /// The aspect name must be in the configuration file, so the configuration for the hook can be
- /// passed to the `Hook` object.
- ///
- /// # Available Hook positions
- ///
- /// The hook positions are described in the type description of `HookPosition`.
- ///
- /// # Aspect names
- ///
- /// Aspect names are arbitrary, though sane things like "debug" or "vcs" are encouraged.
- /// Refer to the documentation for more information.
- ///
- pub fn register_hook(&mut self,
- position: HookPosition,
- aspect_name: &str,
- mut h: Box<Hook>)
- -> Result<()>
- {
- debug!("Registering hook: {:?}", h);
- debug!(" in position: {:?}", position);
- debug!(" with aspect: {:?}", aspect_name);
-
- let guard = match position {
- HookPosition::StoreUnload => self.store_unload_aspects.clone(),
-
- HookPosition::PreCreate => self.pre_create_aspects.clone(),
- HookPosition::PostCreate => self.post_create_aspects.clone(),
- HookPosition::PreRetrieve => self.pre_retrieve_aspects.clone(),
- HookPosition::PostRetrieve => self.post_retrieve_aspects.clone(),
- HookPosition::PreUpdate => self.pre_update_aspects.clone(),
- HookPosition::PostUpdate => self.post_update_aspects.clone(),
- HookPosition::PreDelete => self.pre_delete_aspects.clone(),
- HookPosition::PostDelete => self.post_delete_aspects.clone(),
- };
-
- let mut guard = match guard.deref().lock().map_err(|_| SE::new(SEK::LockError, None)) {
- Err(e) => return Err(SEK::HookRegisterError.into_error_with_cause(Box::new(e))),
- Ok(g) => g,
- };
-
- for mut aspect in guard.deref_mut() {
- if aspect.name().clone() == aspect_name.clone() {
- debug!("Trying to find configuration for hook: {:?}", h);
- self.get_config_for_hook(h.name()).map(|config| h.set_config(config));
- debug!("Trying to register hook in aspect: {:?} <- {:?}", aspect, h);
- aspect.register_hook(h);
- return Ok(());
- }
- }
-
- let annfe = SEK::AspectNameNotFoundError.into_error();
- Err(SEK::HookRegisterError.into_error_with_cause(Box::new(annfe)))
- }
-
- /// Get the configuration for a hook by the name of the hook, from the configuration file.
- fn get_config_for_hook(&self, name: &str) -> Option<&Value> {
- match self.configuration {
- Some(Value::Table(ref tabl)) => {
- debug!("Trying to head 'hooks' section from {:?}", tabl);
- tabl.get("hooks")
- .map(|hook_section| {
- debug!("Found hook section: {:?}", hook_section);
- debug!("Reading section key: {:?}", name);
- match *hook_section {
- Value::Table(ref tabl) => tabl.get(name),
- _ => None
- }
- })
- .unwrap_or(None)
- },
- _ => None,
- }
- }
-
- /// Execute all hooks from all aspects for a Store Id object.
- ///
- /// # Return value
- ///
- /// - () on success
- /// - Error on the first failing hook.
- ///
- fn execute_hooks_for_id(&self,
- aspects: Arc<Mutex<Vec<Aspect>>>,
- id: &StoreId)
- -> HookResult<()>
- {
- match aspects.lock() {
- Err(_) => return Err(HookErrorKind::HookExecutionError.into()),
- Ok(g) => g
- }.iter().fold_result(|aspect| {
- debug!("[Aspect][exec]: {:?}", aspect);
- (aspect as &StoreIdAccessor).access(id)
- }).map_err(Box::new)
- .map_err(|e| HookErrorKind::HookExecutionError.into_error_with_cause(e))
- }
-
- /// Execute all hooks from all aspects for a mutable `FileLockEntry` object.
- ///
- /// # Return value
- ///
- /// - () on success
- /// - Error on the first failing hook.
- ///
- fn execute_hooks_for_mut_file(&self,
- aspects: Arc<Mutex<Vec<Aspect>>>,
- fle: &mut FileLockEntry)
- -> HookResult<()>
- {
- match aspects.lock() {
- Err(_) => return Err(HookErrorKind::HookExecutionError.into()),
- Ok(g) => g
- }.iter().fold_result(|aspect| {
- debug!("[Aspect][exec]: {:?}", aspect);
- aspect.access_mut(fle)
- }).map_err(Box::new)
- .map_err(|e| HookErrorKind::HookExecutionError.into_error_with_cause(e))
- }
-
}
impl Debug for Store {
@@ -1042,14 +747,6 @@ impl Debug for Store {
try!(write!(fmt, "\n"));
try!(write!(fmt, " - location : {:?}\n", self.location));
try!(write!(fmt, " - configuration : {:?}\n", self.configuration));
- try!(write!(fmt, " - pre_create_aspects : {:?}\n", self.pre_create_aspects ));
- try!(write!(fmt, " - post_create_aspects : {:?}\n", self.post_create_aspects ));
- try!(write!(fmt, " - pre_retrieve_aspects : {:?}\n", self.pre_retrieve_aspects ));
- try!(write!(fmt, " - post_retrieve_aspects : {:?}\n", self.post_retrieve_aspects ));
- try!(write!(fmt, " - pre_update_aspects : {:?}\n", self.pre_update_aspects ));
- try!(write!(fmt, " - post_update_aspects : {:?}\n", self.post_update_aspects ));
- try!(write!(fmt, " - pre_delete_aspects : {:?}\n", self.pre_delete_aspects ));
- try!(write!(fmt, " - post_delete_aspects : {:?}\n", self.post_delete_aspects ));
try!(write!(fmt, "\n"));
try!(write!(fmt, "Entries:\n"));
try!(write!(fmt, "{:?}", self.entries));
@@ -1065,23 +762,8 @@ impl Drop for Store {
/// Unlock all files on drop
//
/// TODO: Unlock them
- /// TODO: Resolve this dirty hack with the StoreId for the Store drop hooks.
///
fn drop(&mut self) {
- match StoreId::new(Some(self.location.clone()), PathBuf::from(".")) {
- Err(e) => {
- trace_error(&e);
- warn!("Cannot construct StoreId for Store to execute hooks!");
- warn!("Will close Store without executing hooks!");
- },
- Ok(store_id) => {
- if let Err(e) = self.execute_hooks_for_id(self.store_unload_aspects.clone(), &store_id) {
- debug!("Store-load hooks execution failed. Cannot create store object.");
- warn!("Store Unload Hook error: {:?}", e);
- }
- },
- };
-
debug!("Dropping store");
}
@@ -1541,19 +1223,6 @@ mod store_tests {
assert_eq!(store.location, PathBuf::from("/"));
assert!(store.entries.read().unwrap().is_empty());
-
- assert!(store.store_unload_aspects.lock().unwrap().is_empty());
-
- assert!(store.pre_create_aspects.lock().unwrap().is_empty());
- assert!(store.post_create_aspects.lock().unwrap().is_empty());
- assert!(store.pre_retrieve_aspects.lock().unwrap().is_empty());
- assert!(store.post_retrieve_aspects.lock().unwrap().is_empty());
- assert!(store.pre_update_aspects.lock().unwrap().is_empty());
- assert!(store.post_update_aspects.lock().unwrap().is_empty());
- assert!(store.pre_delete_aspects.lock().unwrap().is_empty());
- assert!(store.post_delete_aspects.lock().unwrap().is_empty());
- assert!(store.pre_move_aspects.lock().unwrap().is_empty());
- assert!(store.post_move_aspects.lock().unwrap().is_empty());
}
#[test]
@@ -1775,476 +1444,3 @@ mod store_tests {
}
-#[cfg(test)]
-mod store_hook_tests {
-
- mod test_hook {
- use hook::Hook;
- use hook::accessor::HookDataAccessor;
- use hook::accessor::HookDataAccessorProvider;
- use hook::position::HookPosition;
-
- use self::accessor::TestHookAccessor as DHA;
-
- use toml::Value;
-
- #[derive(Debug)]
- pub struct TestHook {
- position: HookPosition,
- accessor: DHA,
- }
-
- impl TestHook {
-
- pub fn new(pos: HookPosition, succeed: bool, error_aborting: bool) -> TestHook {
- TestHook { position: pos.clone(), accessor: DHA::new(pos, succeed, error_aborting) }
- }
-
- }
-
- impl Hook for TestHook {
- fn name(&self) -> &'static str { "testhook_succeeding" }
- fn set_config(&mut self, _: &Value) { }
- }
-
- impl HookDataAccessorProvider for TestHook {
-
- fn accessor(&self) -> HookDataAccessor {
- use hook::position::HookPosition as HP;
- use hook::accessor::HookDataAccessor as HDA;
-
- match self.position {
- HP::StoreUnload |
- HP::PreCreate |
- HP::PreRetrieve |
- HP::PreDelete |
- HP::PostDelete => HDA::StoreIdAccess(&self.accessor),
- HP::PostCreate |
- HP::PostRetrieve |
- HP::PreUpdate |
- HP::PostUpdate => HDA::MutableAccess(&self.accessor),
- }
- }
-
- }
-
- pub mod accessor {
- use hook::result::HookResult;
- use hook::accessor::MutableHookDataAccessor;
- use hook::accessor::NonMutableHookDataAccessor;
- use hook::accessor::StoreIdAccessor;
- use hook::position::HookPosition;
- use store::FileLockEntry;
- use storeid::StoreId;
- use hook::error::HookErrorKind as HEK;
- use hook::error::CustomData;
- use libimagerror::into::IntoError;
-
- #[derive(Debug)]
- pub struct TestHookAccessor {
- pos: HookPosition,
- succeed: bool,
- error_aborting: bool
- }
-
- impl TestHookAccessor {
-
- pub fn new(position: HookPosition, succeed: bool, error_aborting: bool)
- -> TestHookAccessor
- {
- TestHookAccessor {
- pos: position,
- succeed: succeed,
- error_aborting: error_aborting,
- }
- }
-
- }
-
- fn get_result(succeed: bool, abort: bool) -> HookResult<()> {
- println!("Generting result: succeed = {}, abort = {}", succeed, abort);
- if succeed {
- println!("Generating result: Ok(())");
- Ok(())
- } else {
- if abort {
- println!("Generating result: Err(_), aborting");
- Err(HEK::HookExecutionError.into_error())
- } else {
- println!("Generating result: Err(_), not aborting");
- let custom = CustomData::default().aborting(false);
- Err(HEK::HookExecutionError.into_error().with_custom_data(custom))
- }
- }
- }
-
- impl StoreIdAccessor for TestHookAccessor {
-
- fn access(&self, _: &StoreId) -> HookResult<()> {
- get_result(self.succeed, self.error_aborting)
- }
-
- }
-
- impl MutableHookDataAccessor for TestHookAccessor {
-
- fn access_mut(&self, _: &mut FileLockEntry) -> HookResult<()> {
- get_result(self.succeed, self.error_aborting)
- }
-
- }
-
- impl NonMutableHookDataAccessor for TestHookAccessor {
-
- fn access(&self, _: &FileLockEntry) -> HookResult<()> {
- get_result(self.succeed, self.error_aborting)
- }
-
- }
-
- }
-
- }
-
- use std::path::PathBuf;
-
- use hook::position::HookPosition as HP;
- use storeid::StoreId;
- use store::Store;
-
- use self::test_hook::TestHook;
-
- fn get_store_with_config() -> Store {
- use toml::de::from_str;
-
- let cfg : ::toml::Value = from_str(mini_config()).unwrap();
- println!("Config parsed: {:?}", cfg);
- Store::new(PathBuf::from("/"), Some(cfg.get("store").cloned().unwrap())).unwrap()
- }
-
- fn mini_config() -> &'static str {
- r#"
-[store]
-store-unload-hook-aspects = [ "test" ]
-pre-create-hook-aspects = [ "test" ]
-post-create-hook-aspects = [ "test" ]
-pre-move-hook-aspects = [ "test" ]
-post-move-hook-aspects = [ "test" ]
-pre-retrieve-hook-aspects = [ "test" ]
-post-retrieve-hook-aspects = [ "test" ]
-pre-update-hook-aspects = [ "test" ]
-post-update-hook-aspects = [ "test" ]
-pre-delete-hook-aspects = [ "test" ]
-post-delete-hook-aspects = [ "test" ]
-
-[store.aspects.test]
-parallel = false
-mutable_hooks = true
-
-[store.hooks.testhook_succeeding]
-aspect = "test"
- "#
- }
-
- fn test_hook_execution(hook_positions: &[HP], storeid_name: &str) {
- let mut store = get_store_with_config();
-
- println!("Registering hooks...");
- for pos in hook_positions {
- let hook = TestHook::new(pos.clone(), true, false);
- println!("\tRegistering: {:?}", pos);
- assert!(store.register_hook(pos.clone(), "test", Box::new(hook))
- .map_err(|e| println!("{:?}", e))
- .is_ok()
- );
- }
- println!("... done.");
-
- let pb = StoreId::new_baseless(PathBuf::from(storeid_name)).unwrap();
- let pb_moved = StoreId::new_baseless(PathBuf::from(format!("{}-moved", storeid_name))).unwrap();
-
- println!("Creating {:?}", pb);
- assert!(store.create(pb.clone()).is_ok());
-
- {
- println!("Getting {:?} -> Some?", pb);
- assert!(match store.get(pb.clone()) {
- Ok(Some(_)) => true,
- _ => false,
- });
- }
-
- {
- println!("Getting {:?} -> None?", pb_moved);
- assert!(match store.get(pb_moved.clone()) {
- Ok(None) => true,
- _ => false,
- });
- }
-
- {
- println!("Moving {:?} -> {:?}", pb, pb_moved);
- assert!(store.move_by_id(pb.clone(), pb_moved.clone()).map_err(|e| println!("ERROR MOVING: {:?}", e)).is_ok());
- }
-
- {
- println!("Getting {:?} -> None", pb);
- assert!(match store.get(pb.clone()) {
- Ok(None) => true,
- _ => false,
- });
- }
-
- {
- println!("Getting {:?} -> Some", pb_moved);
- assert!(match store.get(pb_moved.clone()) {
- Ok(Some(_)) => true,
- _ => false,
- });
- }
-
- {
- println!("Getting {:?} -> Some -> updating", pb_moved);
- assert!(match store.get(pb_moved.clone()).map_err(|e| println!("ERROR GETTING: {:?}", e)) {
- Ok(Some(mut fle)) => store.update(&mut fle)
- .map_err(|e| println!("ERROR UPDATING: {:?}", e)).is_ok(),
- _ => false,
- });
- }
-
- println!("Deleting {:?}", pb_moved);
- assert!(store.delete(pb_moved).is_ok());
- }
-
- #[test]
- fn test_storeunload() {
- test_hook_execution(&[HP::StoreUnload], "test_storeunload");
- }
-
- #[test]
- fn test_precreate() {
- test_hook_execution(&[HP::PreCreate], "test_precreate");
- }
-
- #[test]
- fn test_postcreate() {
- test_hook_execution(&[HP::PostCreate], "test_postcreate");
- }
-
- #[test]
- fn test_preretrieve() {
- test_hook_execution(&[HP::PreRetrieve], "test_preretrieve");
- }
-
- #[test]
- fn test_postretrieve() {
- test_hook_execution(&[HP::PostRetrieve], "test_postretrieve");
- }
-
- #[test]
- fn test_preupdate() {
- test_hook_execution(&[HP::PreUpdate], "test_preupdate");
- }
-
- #[test]
- fn test_postupdate() {
- test_hook_execution(&[HP::PostUpdate], "test_postupdate");
- }
-
- #[test]
- fn test_predelete() {
- test_hook_execution(&[HP::PreDelete], "test_predelete");
- }
-
- #[test]
- fn test_postdelete() {
- test_hook_execution(&[HP::PostDelete], "test_postdelete");
- }
-
- #[test]
- fn test_multiple_same_position() {
- let positions = [ HP::StoreUnload, HP::PreCreate, HP::PostCreate, HP::PreRetrieve,
- HP::PostRetrieve, HP::PreUpdate, HP::PostUpdate, HP::PreDelete, HP::PostDelete ];
-
- for position in positions.iter() {
- for n in 2..10 {
- let mut v = Vec::with_capacity(n);
- for _ in 0..n { v.push(position.clone()); }
-
- test_hook_execution(&v, "test_multiple_same_position");
- }
- }
- }
-
-
- fn get_store_with_aborting_hook_at_pos(pos: HP) -> Store {
- let mut store = get_store_with_config();
- let hook = TestHook::new(pos.clone(), false, true);
-
- assert!(store.register_hook(pos, "test", Box::new(hook)).map_err(|e| println!("{:?}", e)).is_ok());
- store
- }
-
- #[test]
- fn test_pre_create_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_create_error")).unwrap();
- let store = get_store_with_aborting_hook_at_pos(HP::PreCreate);
- assert!(store.create(storeid).is_err());
- }
-
- #[test]
- fn test_pre_retrieve_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_retrieve_error")).unwrap();
- let store = get_store_with_aborting_hook_at_pos(HP::PreRetrieve);
- assert!(store.retrieve(storeid).is_err());
- }
-
- #[test]
- fn test_pre_delete_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_delete_error")).unwrap();
- let store = get_store_with_aborting_hook_at_pos(HP::PreDelete);
- assert!(store.delete(storeid).is_err());
- }
-
- #[test]
- fn test_pre_update_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_update_error")).unwrap();
- let store = get_store_with_aborting_hook_at_pos(HP::PreUpdate);
- let mut fle = store.create(storeid).unwrap();
-
- assert!(store.update(&mut fle).is_err());
- }
-
- #[test]
- fn test_post_create_error() {
- let store = get_store_with_aborting_hook_at_pos(HP::PostCreate);
- let pb = StoreId::new_baseless(PathBuf::from("test_post_create_error")).unwrap();
-
- assert!(store.create(pb.clone()).is_err());
-
- // But the entry exists, as the hook fails post-create
- assert!(store.entries.read().unwrap().get(&pb.with_base(store.path().clone())).is_some());
- }
-
- #[test]
- fn test_post_retrieve_error() {
- let store = get_store_with_aborting_hook_at_pos(HP::PostRetrieve);
- let pb = StoreId::new_baseless(PathBuf::from("test_post_retrieve_error")).unwrap();
-
- assert!(store.retrieve(pb.clone()).is_err());
-
- // But the entry exists, as the hook fails post-retrieve
- assert!(store.entries.read().unwrap().get(&pb.with_base(store.path().clone())).is_some());
- }
-
- #[test]
- fn test_post_delete_error() {
- let store = get_store_with_aborting_hook_at_pos(HP::PostDelete);
- let pb = StoreId::new_baseless(PathBuf::from("test_post_delete_error")).unwrap();
-
- assert!(store.create(pb.clone()).is_ok());
- let pb = pb.with_base(store.path().clone());
- assert!(store.entries.read().unwrap().get(&pb).is_some());
-
- assert!(store.delete(pb.clone()).is_err());
- // But the entry is removed, as we fail post-delete
- assert!(store.entries.read().unwrap().get(&pb).is_none());
- }
-
- #[test]
- fn test_post_update_error() {
- let store = get_store_with_aborting_hook_at_pos(HP::PostUpdate);
- let pb = StoreId::new_baseless(PathBuf::from("test_post_update_error")).unwrap();
- let mut fle = store.create(pb.clone()).unwrap();
- let pb = pb.with_base(store.path().clone());
-
- assert!(store.entries.read().unwrap().get(&pb).is_some());
- assert!(store.update(&mut fle).is_err());
- }
-
- fn get_store_with_allowed_error_hook_at_pos(pos: HP) -> Store {
- let mut store = get_store_with_config();
- let hook = TestHook::new(pos.clone(), false, false);
-
- assert!(store.register_hook(pos, "test", Box::new(hook)).map_err(|e| println!("{:?}", e)).is_ok());
- store
- }
-
- #[test]
- fn test_pre_create_allowed_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_create_allowed_error")).unwrap();
- let store = get_store_with_allowed_error_hook_at_pos(HP::PreCreate);
- assert!(store.create(storeid).is_ok());
- }
-
- #[test]
- fn test_pre_retrieve_allowed_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_retrieve_allowed_error")).unwrap();
- let store = get_store_with_allowed_error_hook_at_pos(HP::PreRetrieve);
- assert!(store.retrieve(storeid).is_ok());
- }
-
- #[test]
- fn test_pre_delete_allowed_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_delete_allowed_error")).unwrap();
- let store = get_store_with_allowed_error_hook_at_pos(HP::PreDelete);
- assert!(store.retrieve(storeid.clone()).is_ok());
- assert!(store.delete(storeid).map_err(|e| println!("{:?}", e)).is_ok());
- }
-
- #[test]
- fn test_pre_update_allowed_error() {
- let storeid = StoreId::new_baseless(PathBuf::from("test_pre_update_allowed_error")).unwrap();
- let store = get_store_with_allowed_error_hook_at_pos(HP::PreUpdate);
- let mut fle = store.create(storeid).unwrap();
-
- assert!(store.update(&mut fle).is_ok());
- }
-
- #[test]
- fn test_post_create_allowed_error() {
- let store = get_store_with_allowed_error_hook_at_pos(HP::PostCreate);
- let pb = StoreId::new_baseless(PathBuf::from("test_pre_create_allowed_error")).unwrap();
-
- assert!(store.create(pb.clone()).is_ok());
-
- // But the entry exists, as the hook fails post-create
- assert!(store.entries.read().unwrap().get(&pb.with_base(store.path().clone())).is_some());
- }
-
- #[test]
- fn test_post_retrieve_allowed_error() {
- let store = get_store_with_allowed_error_hook_at_pos(HP::PostRetrieve);
- let pb = StoreId::new_baseless(PathBuf::from("test_pre_retrieve_allowed_error")).unwrap();
-
- assert!(store.retrieve(pb.clone()).is_ok());
-
- // But the entry exists, as the hook fails post-retrieve
- assert!(store.entries.read().unwrap().get(&pb.with_base(store.path().clone())).is_some());
- }
-
- #[test]
- fn test_post_delete_allowed_error() {
- let store = get_store_with_allowed_error_hook_at_pos(HP::PostDelete);
- let pb = StoreId::new_baseless(PathBuf::from("test_post_delete_allowed_error")).unwrap();
-
- assert!(store.create(pb.clone()).is_ok());
- let pb = pb.with_base(store.path().clone());
- assert!(store.entries.read().unwrap().get(&pb).is_some());
-
- assert!(store.delete(pb.clone()).is_ok());
- // But the entry is removed, as we fail post-delete
- assert!(store.entries.read().unwrap().get(&pb).is_none());
- }
-
- #[test]
- fn test_post_update_allowed_error() {
- let store = get_store_with_allowed_error_hook_at_pos(HP::PostUpdate);
- let pb = StoreId::new_baseless(PathBuf::from("test_pre_update_allowed_error")).unwrap();
- let mut fle = store.create(pb.clone()).unwrap();
- let pb = pb.with_base(store.path().clone());
-
- assert!(store.entries.read().unwrap().get(&pb).is_some());
- assert!(store.update(&mut fle).is_ok());
- }
-}
diff --git a/libimagstorestdhook/Cargo.toml b/libimagstorestdhook/Cargo.toml
deleted file mode 100644
index 3e70f61..0000000
--- a/libimagstorestdhook/Cargo.toml
+++ /dev/null
@@ -1,36 +0,0 @@
-[package]
-name = "libimagstorestdhook"
-version = "0.3.0"
-authors = ["Matthias Beyer <mail@beyermatthias.de>"]
-
-description = "Library for the imag core distribution"
-
-keywords = ["imag", "PIM", "personal", "information", "management"]
-readme = "../README.md"
-license = "LGPL-2.1"
-
-documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
-repository = "https://github.com/matthiasbeyer/imag"
-homepage = "http://imag-pim.org"
-
-[dependencies]
-toml = "^0.4"
-log = "0.3"
-fs2 = "0.3"
-git2 = "0.5"
-
-[dependencies.libimagstore]
-path = "../libimagstore"
-
-[dependencies.libimagentrylink]
-path = "../libimagentrylink"
-
-[dependencies.libimaginteraction]
-path = "../libimaginteraction"
-
-[dependencies.libimagerror]
-path = "../libimagerror"
-
-[dependencies.libimagutil]
-path = "../libimagutil"
-
diff --git a/libimagstorestdhook/README.md b/libimagstorestdhook/README.md
deleted file mode 120000
index 495accc..0000000
--- a/libimagstorestdhook/README.md
+++ /dev/null
@@ -1 +0,0 @@
-../doc/src/05100-lib-store-std-hook.md \ No newline at end of file
diff --git a/libimagstorestdhook/src/debug.rs b/libimagstorestdhook/src/debug.rs
deleted file mode 100644
index af20f33..0000000
--- a/libimagstorestdhook/src/debug.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 toml::Value;
-
-use libimagstore::hook::Hook;
-use libimagstore::hook::accessor::HookDataAccessor;
-use libimagstore::hook::accessor::HookDataAccessorProvider;
-use libimagstore::hook::position::HookPosition;
-
-use self::accessor::DebugHookAccessor as DHA;
-
-#[derive(Debug)]
-pub struct DebugHook {
- position: HookPosition,
- accessor: DHA,
-}
-
-impl DebugHook {
-
- pub fn new(pos: HookPosition) -> DebugHook {
- DebugHook {
- position: pos.clone(),
- accessor: DHA::new(pos),
- }
- }
-
-}
-
-impl Hook for DebugHook {
-
- fn name(&self) -> &'static str {
- "stdhook_debug"
- }
-
- fn set_config(&mut self, c: &Value) {
- debug!("Trying to set configuration in debug hook: {:?}", c);
- debug!("Ignoring configuration in debug hook, we don't need a config here");
- }
-
-}
-
-impl HookDataAccessorProvider for DebugHook {
-
- fn accessor(&self) -> HookDataAccessor {
- use libimagstore::hook::position::HookPosition as HP;
- use libimagstore::hook::accessor::HookDataAccessor as HDA;
-
- match self.position {
- HP::StoreUnload |
- HP::PreCreate |
- HP::PreRetrieve |
- HP::PreDelete |
- HP::PostDelete => HDA::StoreIdAccess(&self.accessor),
- HP::PostCreate |
- HP::PostRetrieve |
- HP::PreUpdate |
- HP::PostUpdate => HDA::MutableAccess(&self.accessor),
- }
- }
-
-}
-
-pub mod accessor {
- use std::ops::Deref;
-
- use libimagstore::storeid::StoreId;
- use libimagstore::store::FileLockEntry;
- use libimagstore::hook::result::HookResult;
- use libimagstore::hook::accessor::MutableHookDataAccessor;
- use libimagstore::hook::accessor::NonMutableHookDataAccessor;
- use libimagstore::hook::accessor::StoreIdAccessor;
- use libimagstore::hook::position::HookPosition;
-
- #[derive(Debug)]
- pub struct DebugHookAccessor {
- position: HookPosition,
- }
-
- impl DebugHookAccessor {
-
- pub fn new(position: HookPosition) -> DebugHookAccessor {
- DebugHookAccessor {
- position: position,
- }
- }
-
- }
-
- impl StoreIdAccessor for DebugHookAccessor {
-
- fn access(&self, id: &StoreId) -> HookResult<()> {
- debug!("[DEBUG HOOK]: {:?}", id);
- Ok(())
- }
-
- }
-
- impl MutableHookDataAccessor for DebugHookAccessor {
-
- fn access_mut(&self, fle: &mut FileLockEntry) -> HookResult<()> {
- debug!("[DEBUG HOOK] {:?}", fle.deref().deref());
- Ok(())
- }
-
- }
-
- impl NonMutableHookDataAccessor for DebugHookAccessor {
-
- fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
- debug!("[DEBUG HOOK] {:?}", fle.deref().deref());
- Ok(())
- }
-
- }
-
-}
-
diff --git a/libimagstorestdhook/src/denylinkeddelete.rs b/libimagstorestdhook/src/denylinkeddelete.rs
deleted file mode 100644
index 6186535..0000000
--- a/libimagstorestdhook/src/denylinkeddelete.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 toml::Value;
-
-use libimagstore::hook::Hook;
-use libimagstore::hook::error::HookErrorKind as HEK;
-use libimagstore::hook::accessor::HookDataAccessor as HDA;
-use libimagstore::hook::accessor::HookDataAccessorProvider;
-use libimagstore::hook::accessor::NonMutableHookDataAccessor;
-use libimagstore::hook::result::HookResult;
-use libimagstore::store::FileLockEntry;
-use libimagstore::toml_ext::TomlValueExt;
-use libimagentrylink::internal::InternalLinker;
-use libimagerror::trace::trace_error;
-
-mod error {
- generate_error_imports!();
- generate_error_types!(NoLinksLeftCheckerHookError, NoLinksLeftCheckerHookErrorKind,
- ReadInternalLinksError => "Error while reading internal links of entry",
- LinksLeft => "The entry has links and therefor cannot be deleted."
- );
-}
-use self::error::NoLinksLeftCheckerHookErrorKind as NLLCHEK;
-
-#[derive(Debug, Clone)]
-pub struct DenyDeletionOfLinkedEntriesHook {
- abort: bool
-}
-
-impl DenyDeletionOfLinkedEntriesHook {
-
- pub fn new() -> DenyDeletionOfLinkedEntriesHook {
- DenyDeletionOfLinkedEntriesHook {
- abort: true // by default, this hook aborts actions
- }
- }
-
-}
-
-impl Hook for DenyDeletionOfLinkedEntriesHook {
-
- fn name(&self) -> &'static str {
- "stdhook_linked_entries_cannot_be_deleted"
- }
-
- fn set_config(&mut self, v: &Value) {
- self.abort = match v.read("aborting") {
- Ok(Some(Value::Boolean(b))) => b,
- Ok(Some(_)) => {
- warn!("Configuration error, 'aborting' must be a Boolean (true|false).");
- warn!("Assuming 'true' now.");
- true
- },
- Ok(None) => {
- warn!("No key 'aborting' - Assuming 'true'");
- true
- },
- Err(e) => {
- error!("Error parsing TOML:");
- trace_error(&e);
- false
- },
- };
- }
-
-}
-
-impl HookDataAccessorProvider for DenyDeletionOfLinkedEntriesHook {
-
- fn accessor(&self) -> HDA {
- HDA::NonMutableAccess(self)
- }
-
-}
-
-impl NonMutableHookDataAccessor for DenyDeletionOfLinkedEntriesHook {
-
- fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
- use libimagerror::into::IntoError;
- use self::error::MapErrInto;
-
- debug!("[NO LINKS LEFT CHECKER HOOK] {:?}", fle.get_location());
-
- let n = try!(fle
- .get_internal_links()
- .map(|i| i.count())
- .map_err_into(NLLCHEK::ReadInternalLinksError)
- .map_err(Box::new)
- .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e)));
-
- if n > 0 {
- Err(NLLCHEK::LinksLeft.into_error())
- .map_err(Box::new)
- .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
- } else {
- Ok(())
- }
- }
-
-}
-
-
diff --git a/libimagstorestdhook/src/flock.rs b/libimagstorestdhook/src/flock.rs
deleted file mode 100644
index 6cc3086..0000000
--- a/libimagstorestdhook/src/flock.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 toml::Value;
-
-use fs2::FileExt;
-use std::fs::File;
-
-use libimagstore::hook::Hook;
-use libimagstore::hook::accessor::HookDataAccessor as HDA;
-use libimagstore::hook::accessor::HookDataAccessorProvider;
-use libimagstore::hook::accessor::StoreIdAccessor;
-use libimagstore::hook::accessor::MutableHookDataAccessor;
-use libimagstore::hook::accessor::NonMutableHookDataAccessor;
-use libimagstore::hook::result::HookResult;
-use libimagstore::hook::error::{HookError, HookErrorKind};
-use libimagstore::storeid::StoreId;
-use libimagstore::store::FileLockEntry;
-use libimagstore::store::Entry;
-
-mod error {
- generate_error_imports!();
- generate_error_types!(FlockError, FlockErrorKind,
- IOError => "IO Error",
- StoreIdPathBufConvertError => "Error while converting StoreId to PathBuf",
- FileOpenError => "Error on File::open()",
- LockError => "Error while lock()ing",
- UnlockError => "Error while unlock()ing"
- );
-}
-use self::error::FlockError as FE;
-use self::error::FlockErrorKind as FEK;
-use self::error::MapErrInto;
-
-trait EntryFlock {
- fn lock(&self) -> Result<(), FE>;
- fn unlock(&self) -> Result<(), FE>;
-}
-
-fn open_file(id: StoreId) -> Result<File, FE> {
- id.into_pathbuf()
- .map_err_into(FEK::StoreIdPathBufConvertError)
- .and_then(|loc| {
- File::open(loc)
- .map_err_into(FEK::FileOpenError)
- .map_err_into(FEK::IOError)
- })
-}
-
-impl EntryFlock for Entry {
-
- fn lock(&self) -> Result<(), FE> {
- open_file(self.get_location().clone())
- .and_then(|file| {
- file.lock_exclusive()
- .map_err_into(FEK::LockError)
- .map_err_into(FEK::IOError)
- })
- }
-
- fn unlock(&self) -> Result<(), FE> {
- open_file(self.get_location().clone())
- .and_then(|file| {
- file.unlock()
- .map_err_into(FEK::UnlockError)
- .map_err_into(FEK::LockError)
- .map_err_into(FEK::IOError)
- })
- }
-
-}
-
-#[derive(PartialEq, Eq, Debug, Clone)]
-pub enum Action {
- Lock,
- Unlock
-}
-
-fn action_to_str(a: &Action) -> &'static str {
- match *a {
- Action::Lock => "lock",
- Action::Unlock => "unlock",
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct FlockUpdateHook {
- action: Action,
-}
-
-impl FlockUpdateHook {
-
- pub fn new(action: Action) -> FlockUpdateHook {
- FlockUpdateHook {
- action: action,
- }
- }
-
-}
-
-impl Hook for FlockUpdateHook {
-
- fn name(&self) -> &'static str {
- "stdhook_flock_update"
- }
-
- fn set_config(&mut self, _: &Value) {
- () // We are not configurable here.
- }
-
-}
-
-impl HookDataAccessorProvider for FlockUpdateHook {
-
- fn accessor(&self) -> HDA {
- HDA::StoreIdAccess(self)
- }
-
-}
-
-impl StoreIdAccessor for FlockUpdateHook {
-
- fn access(&self, id: &StoreId) -> HookResult<()> {
- debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), id);
- Ok(())
- }
-
-}
-
-impl MutableHookDataAccessor for FlockUpdateHook {
-
- fn access_mut(&self, fle: &mut FileLockEntry) -> HookResult<()> {
- debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), fle.get_location());
- fle.lock()
- .map_err(|e| HookError::new(HookErrorKind::HookExecutionError, Some(Box::new(e))))
- .map(|_| ())
- }
-
-}
-
-impl NonMutableHookDataAccessor for FlockUpdateHook {
-
- fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
- debug!("[FLOCK HOOK][{}] {:?}", action_to_str(&self.action), fle.get_location());
- fle.unlock()
- .map_err(|e| HookError::new(HookErrorKind::HookExecutionError, Some(Box::new(e))))
- .map(|_| ())
- }
-
-}
-
diff --git a/libimagstorestdhook/src/lib.rs b/libimagstorestdhook/src/lib.rs
deleted file mode 100644
index abfea88..0000000
--- a/libimagstorestdhook/src/lib.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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
-//
-
-#![deny(
- dead_code,
- non_camel_case_types,
- non_snake_case,
- path_statements,
- trivial_numeric_casts,
- unstable_features,
- unused_allocation,
- unused_import_braces,
- unused_imports,
- unused_must_use,
- unused_mut,
- unused_qualifications,
- while_true,
-)]
-
-#[macro_use] extern crate log;
-extern crate toml;
-extern crate fs2;
-extern crate git2;
-
-extern crate libimagstore;
-extern crate libimagentrylink;
-extern crate libimaginteraction;
-#[macro_use] extern crate libimagerror;
-extern crate libimagutil;
-
-pub mod debug;
-pub mod denylinkeddelete;
-pub mod flock;
-pub mod linkverify;
-pub mod vcs;
-
diff --git a/libimagstorestdhook/src/linkverify.rs b/libimagstorestdhook/src/linkverify.rs
deleted file mode 100644
index 7919479..0000000
--- a/libimagstorestdhook/src/linkverify.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::path::PathBuf;
-
-use toml::Value;
-
-use libimagstore::hook::Hook;
-use libimagstore::hook::accessor::HookDataAccessor as HDA;
-use libimagstore::hook::accessor::HookDataAccessorProvider;
-use libimagstore::hook::accessor::NonMutableHookDataAccessor;
-use libimagstore::hook::result::HookResult;
-use libimagstore::store::FileLockEntry;
-use libimagentrylink::internal::InternalLinker;
-use libimagerror::trace::trace_error;
-
-#[derive(Debug, Clone)]
-pub struct LinkedEntriesExistHook {
- store_location: PathBuf,
-}
-
-impl LinkedEntriesExistHook {
-
- pub fn new(store_location: PathBuf) -> LinkedEntriesExistHook {
- LinkedEntriesExistHook {
- store_location: store_location,
- }
- }
-
-}
-
-impl Hook for LinkedEntriesExistHook {
-
- fn name(&self) -> &'static str {
- "stdhook_linked_entries_exist"
- }
-
- fn set_config(&mut self, _: &Value) {
- () // We are not configurable here.
- }
-
-}
-
-impl HookDataAccessorProvider for LinkedEntriesExistHook {
-
- fn accessor(&self) -> HDA {
- HDA::NonMutableAccess(self)
- }
-
-}
-
-impl NonMutableHookDataAccessor for LinkedEntriesExistHook {
-
- fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
- use libimagstore::hook::error::HookErrorKind;
- use libimagstore::hook::error::MapErrInto;
-
- debug!("[LINKVERIFY HOOK] {:?}", fle.get_location());
- match fle.get_internal_links() {
- Ok(links) => {
- for link in links {
- if !try!(link.exists().map_err_into(HookErrorKind::HookExecutionError)) {
- warn!("File link does not exist: {:?} -> {:?}", fle.get_location(), link);
- }
- }
- Ok(())
- },
- Err(e) => {
- warn!("Couldn't execute Link-Verify hook");
- trace_error(&e);
- Err(e).map_err_into(HookErrorKind::HookExecutionError)
- }
- }
- }
-
-}
-
diff --git a/libimagstorestdhook/src/vcs/git/action.rs b/libimagstorestdhook/src/vcs/git/action.rs
deleted file mode 100644
index 76715c8..0000000
--- a/libimagstorestdhook/src/vcs/git/action.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::fmt::{Display, Formatter, Error};
-
-/// Utility type to specify which kind of store action is running
-#[derive(Clone, Debug)]
-pub enum StoreAction {
- Create,
- Retrieve,
- Update,
- Delete,
- StoreUnload,
-}
-
-impl StoreAction {
-
- pub fn uppercase(&self) -> &str {
- match *self {
- StoreAction::Create => "CREATE",
- StoreAction::Retrieve => "RETRIEVE",
- StoreAction::Update => "UPDATE",
- StoreAction::Delete => "DELETE",
- StoreAction::StoreUnload => "STORE UNLOAD",
- }
- }
-
- pub fn as_commit_message(&self) -> &str {
- match *self {
- StoreAction::Create => "Create",
- StoreAction::Retrieve => "Retrieve",
- StoreAction::Update => "Update",
- StoreAction::Delete => "Delete",
- StoreAction::StoreUnload => "Store Unload",
- }
- }
-}
-
-impl Display for StoreAction {
-
- fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
- write!(fmt, "StoreAction: {}",
- match *self {
- StoreAction::Create => "create",
- StoreAction::Retrieve => "retrieve",
- StoreAction::Update => "update",
- StoreAction::Delete => "delete",
- StoreAction::StoreUnload => "store unload",
- })
- }
-
-}
-
diff --git a/libimagstorestdhook/src/vcs/git/config.rs b/libimagstorestdhook/src/vcs/git/config.rs
deleted file mode 100644
index 4c44db9..0000000
--- a/libimagstorestdhook/src/vcs/git/config.rs
+++ /dev/null
@@ -1,241 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 toml::Value;
-
-use libimagerror::into::IntoError;
-use libimagerror::trace::trace_error;
-use libimagstore::storeid::StoreId;
-use libimagstore::toml_ext::TomlValueExt;
-
-use vcs::git::error::GitHookErrorKind as GHEK;
-use vcs::git::error::MapErrInto;
-use vcs::git::result::Result;
-
-use vcs::git::action::StoreAction;
-
-use git2::Repository;
-
-/// Check the configuration whether we should commit interactively
-pub fn commit_interactive(config: &Value, action: &StoreAction) -> bool {
- match config.read("commit.interactive") {
- Ok(Some(Value::Boolean(b))) => b,
- Ok(Some(_)) => {
- warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.interactive' must be a Boolean.",
- action);
- warn!("Defaulting to commit.interactive = false");
- false
- }
- Ok(None) => {
- warn!("Unavailable configuration for");
- warn!("\t'store.hooks.stdhook_git_{}.commit.interactive'", action);
- warn!("Defaulting to false");
- false
- },
- Err(e) => {
- error!("Error parsing TOML:");
- trace_error(&e);
- false
- },
- }
-}
-
-/// Check the configuration whether we should commit with the editor
-fn commit_with_editor(config: &Value, action: &StoreAction) -> bool {
- match config.read("commit.interactive_editor") {
- Ok(Some(Value::Boolean(b))) => b,
- Ok(Some(_)) => {
- warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.interactive_editor' must be a Boolean.",
- action);
- warn!("Defaulting to commit.interactive_editor = false");
- false
- }
- Ok(None) => {
- warn!("Unavailable configuration for");
- warn!("\t'store.hooks.stdhook_git_{}.commit.interactive_editor'", action);
- warn!("Defaulting to false");
- false
- },
- Err(e) => {
- error!("Error parsing TOML:");
- trace_error(&e);
- false
- },
- }
-}
-
-/// Get the commit default message
-fn commit_default_msg<'a>(config: &'a Value, action: &'a StoreAction) -> Result<String> {
- config.read("commit.message")
- .map(|m| match m {
- Some(Value::String(b)) => String::from(b),
- Some(_) => {
- warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.message' must be a String.",
- action);
- warn!("Defaulting to commit.message = '{}'", action.as_commit_message());
- String::from(action.as_commit_message())
- },
- None => {
- warn!("Unavailable configuration for");
- warn!("\t'store.hooks.stdhook_git_{}.commit.message'", action);
- warn!("Defaulting to commit.message = '{}'", action.as_commit_message());
- String::from(action.as_commit_message())
- },
- })
- .map_err_into(GHEK::ConfigError)
-
-}
-
-/// Get the commit template
-///
-/// TODO: Implement good template string
-fn commit_template(action: &StoreAction, id: &StoreId) -> String {
- format!(r#"
-# Please commit your changes and remove these lines.
-#
-# You're about to commit changes via the {action} Hook
-#
-# Altered file: {id}
-#
- "#,
- action = action,
- id = id.local().display())
-}
-
-/// Generate a commit message
-///
-/// Uses the functions `commit_interactive()` and `commit_with_editor()`
-/// or reads one from the commandline or uses the `commit_default_msg()` string to create a commit
-/// message.
-pub fn commit_message(repo: &Repository, config: &Value, action: StoreAction, id: &StoreId) -> Result<String> {
- use libimaginteraction::ask::ask_string;
- use libimagutil::edit::edit_in_tmpfile_with_command;
- use std::process::Command;
-
- if commit_interactive(config, &action) {
- if commit_with_editor(config, &action) {
- repo.config()
- .map_err_into(GHEK::GitConfigFetchError)
- .and_then(|c| c.get_string("core.editor").map_err_into(GHEK::GitConfigEditorFetchError))
- .map_err_into(GHEK::ConfigError)
- .map(Command::new)
- .and_then(|cmd| {
- let mut s = commit_template(&action, id);
- edit_in_tmpfile_with_command(cmd, &mut s).map(|_| s)
- .map_err_into(GHEK::EditorError)
- })
- } else {
- Ok(ask_string("Commit Message", None, false, false, None, "> "))
- }
- } else {
- commit_default_msg(config, &action)
- }
-}
-
-/// Check whether the hook should abort if the repository cannot be initialized
-pub fn abort_on_repo_init_err(cfg: &Value) -> bool {
- get_bool_cfg(Some(cfg), "abort_on_repo_init_failure", true, true)
-}
-
-/// Get the branch which must be checked out before running the hook (if any).
-///
-/// If there is no configuration for this, this is `Ok(None)`, otherwise we try to find the
-/// configuration `String`.
-pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
- match cfg {
- Some(cfg) => {
- cfg.read("ensure_branch")
- .map_err_into(GHEK::ConfigError)
- .and_then(|toml| match toml {
- Some(Value::String(ref s)) => Ok(Some(s.clone())),
- Some(_) => {
- warn!("Configuration error, 'ensure_branch' must be a String.");
- Err(GHEK::ConfigTypeError.into_error())
- .map_err_into(GHEK::ConfigTypeError)
- },
- None => {
- debug!("No key `ensure_branch'");
- Ok(None)
- },
- })
- },
- None => Ok(None),
- }
-}
-
-/// Check whether we should check out a branch before committing.
-pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
- get_bool_cfg(cfg, "try_checkout_ensure_branch", true, true)
-}
-
-/// Helper to get a boolean value from the configuration.
-fn get_bool_cfg(cfg: Option<&Value>, name: &str, on_fail: bool, on_unavail: bool) -> bool {
- cfg.map(|cfg| {
- match cfg.read(name) {
- Ok(Some(Value::Boolean(b))) => b,
- Ok(Some(_)) => {
- warn!("Configuration error, '{}' must be a Boolean (true|false).", name);
- warn!("Assuming '{}' now.", on_fail);
- on_fail
- },
- Ok(None) => {
- warn!("No key '{}' - Assuming '{}'", name, on_unavail);
- on_unavail
- },
- Err(e) => {
- error!("Error parsing TOML:");
- trace_error(&e);
- false
- },
- }
- })
- .unwrap_or_else(|| {
- warn!("No configuration to fetch {} from, assuming {}", name, on_unavail);
- on_unavail
- })
-}
-
-/// Check whether the hook is enabled or not. If the config is not there, the hook is _enabled_ by
-/// default.
-pub fn is_enabled(cfg: &Value) -> bool {
- get_bool_cfg(Some(cfg), "enabled", true, true)
-}
-
-/// Check whether committing is enabled for a hook.
-pub fn committing_is_enabled(cfg: &Value) -> Result<bool> {
- cfg.read("commit.enabled")
- .map_err_into(GHEK::ConfigError)
- .and_then(|toml| match toml {
- Some(Value::Boolean(b)) => Ok(b),
- Some(_) => {
- warn!("Config setting whether committing is enabled or not has wrong type.");
- warn!("Expected Boolean");
- Err(GHEK::ConfigTypeError.into_error())
- },
- None => {
- warn!("No config setting whether committing is enabled or not.");
- Err(GHEK::NoConfigError.into_error())
- },
- })
-}
-
-pub fn add_wt_changes_before_committing(cfg: &Value) -> bool {
- get_bool_cfg(Some(cfg), "commit.add_wt_changes", true, true)
-}
-
diff --git a/libimagstorestdhook/src/vcs/git/delete.rs b/libimagstorestdhook/src/vcs/git/delete.rs
deleted file mode 100644
index 9886d25..0000000
--- a/libimagstorestdhook/src/vcs/git/delete.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::path::PathBuf;
-use std::path::Path;
-use std::fmt::{Debug, Formatter, Error as FmtError};
-use std::result::Result as RResult;
-
-use toml::Value;
-
-use libimagerror::trace::trace_error;
-use libimagstore::storeid::StoreId;
-use libimagstore::hook::Hook;
-use libimagstore::hook::result::HookResult;
-use libimagstore::hook::position::HookPosition;
-use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
-use libimagstore::hook::accessor::StoreIdAccessor;
-use libimagutil::debug_result::*;
-
-use vcs::git::error::GitHookErrorKind as GHEK;
-use vcs::git::error::MapErrInto;
-use vcs::git::runtime::Runtime as GRuntime;
-
-pub struct DeleteHook {
- storepath: PathBuf,
-
- runtime: GRuntime,
-
- position: HookPosition,
-}
-
-impl DeleteHook {
-
- pub fn new(storepath: PathBuf, p: HookPosition) -> DeleteHook {
- DeleteHook {
- runtime: GRuntime::new(&storepath),
- storepath: storepath,
- position: p,
- }
- }
-
-}
-
-impl Debug for DeleteHook {
- fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
- write!(fmt, "DeleteHook(storepath={:?}, repository={}, pos={:?}, cfg={:?})",
- self.storepath,
- (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
- self.position,
- self.runtime.has_config())
- }
-}
-
-
-impl Hook for DeleteHook {
-
- fn name(&self) -> &'static str {
- "stdhook_git_delete"
- }
-
- /// Set the configuration of the hook. See
- /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
- ///
- /// This function traces the error (using `trace_error()`) that
- /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
- /// returns, if any.
- fn set_config(&mut self, config: &Value) {
- if let Err(e) = self.runtime.set_config(config) {
- trace_error(&e);
- }
- }
-
-}
-
-impl HookDataAccessorProvider for DeleteHook {
-
- fn accessor(&self) -> HookDataAccessor {
- HookDataAccessor::StoreIdAccess(self)
- }
-}
-
-impl StoreIdAccessor for DeleteHook {
-
- fn access(&self, id: &StoreId) -> HookResult<()> {
- use libimagerror::into::IntoError;
- use vcs::git::action::StoreAction;
- use vcs::git::config::commit_message;
- use vcs::git::error::MapIntoHookError;
- use vcs::git::util::fetch_index;
- use vcs::git::config::abort_on_repo_init_err;
- use vcs::git::config::is_enabled;
- use vcs::git::config::committing_is_enabled;
- use git2::{ADD_DEFAULT, STATUS_WT_DELETED, IndexMatchedPath};
-
- debug!("[GIT DELETE HOOK]: {:?}", id);
-
- let action = StoreAction::Delete;
- let cfg = try!(self.runtime.config_value_or_err(&action));
-
- if !is_enabled(cfg) {
- return Ok(())
- }
-
- if !self.runtime.has_repository() {
- debug!("[GIT DELETE HOOK]: Runtime has no repository...");
- if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
- // Abort on repo init failure
- debug!("[GIT DELETE HOOK]: Config says we should abort if we have no repository");
- debug!("[GIT DELETE HOOK]: Returing Err(_)");
- return Err(GHEK::RepositoryInitError.into_error())
- .map_err_into(GHEK::RepositoryError)
- .map_into_hook_error()
- } else {
- debug!("[GIT DELETE HOOK]: Config says it is okay to not have a repository");
- debug!("[GIT DELETE HOOK]: Returing Ok(())");
- return Ok(())
- }
- }
-
- let _ = try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
- let repo = try!(self.runtime.repository(&action));
- let mut index = try!(fetch_index(repo, &action));
-
- let signature = try!(
- repo.signature()
- .map_err_into(GHEK::MkSignature)
- .map_dbg_err_str("Failed to fetch signature")
- .map_dbg_str("[GIT DELETE HOOK]: Fetched signature object")
- .map_into_hook_error()
- );
-
- let head = try!(
- repo.head()
- .map_err_into(GHEK::HeadFetchError)
- .map_dbg_err_str("Failed to fetch HEAD")
- .map_dbg_str("[GIT DELETE HOOK]: Fetched HEAD")
- .map_into_hook_error()
- );
-
- let file_status = try!(
- repo
- .status_file(id.local())
- .map_dbg_err_str("Failed to fetch file status")
- .map_dbg_err(|e| format!("\t-> {:?}", e))
- .map_dbg_str("[GIT DELETE HOOK]: Fetched file status")
- .map_err_into(GHEK::RepositoryFileStatusError)
- .map_into_hook_error()
- );
-
- let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
- debug!("[GIT DELETE HOOK]: Checking file status for: {}", path.display());
- if file_status.contains(STATUS_WT_DELETED) {
- debug!("[GIT DELETE HOOK]: File is deleted: {}", path.display());
- 0
- } else {
- debug!("[GIT DELETE HOOK]: Ignoring file: {}", path.display());
- 1
- }
- };
-
- try!(
- index.add_all(&[id.local()], ADD_DEFAULT, Some(cb as &mut IndexMatchedPath))
- .map_err_into(GHEK::RepositoryPathAddingError)
- .map_dbg_err_str("Failed to add to index")
- .map_dbg_str("[GIT DELETE HOOK]: Fetched index")
- .map_into_hook_error()
- );
-
- let tree_id = try!(
- index.write_tree()
- .map_err_into(GHEK::RepositoryIndexWritingError)
- .map_dbg_err_str("Failed to write tree")
- .map_dbg_str("[GIT DELETE HOOK]: Wrote index tree")
- .map_into_hook_error()
- );
-
- if !try!(committing_is_enabled(cfg)) {
- debug!("Committing not enabled. This is fine, returning now...");
- return Ok(())
- }
-
- let mut parents = Vec::new();
- {
- let commit = try!(
- repo.find_commit(head.target().unwrap())
- .map_err_into(GHEK::RepositoryParentFetchingError)
- .map_dbg_err_str("Failed to find commit HEAD")
- .map_dbg_str("[GIT DELETE HOOK]: Found commit HEAD")
- .map_into_hook_error()
- );
- parents.push(commit);
- }
-
- // for converting from Vec<Commit> to Vec<&Commit>
- let parents = parents.iter().collect::<Vec<_>>();
-
- let tree = try!(
- repo.find_tree(tree_id)
- .map_err_into(GHEK::RepositoryParentFetchingError)
- .map_dbg_err_str("Failed to find tree")
- .map_dbg_str("[GIT DELETE HOOK]: Found tree for index")
- .map_into_hook_error()
- );
-
- let message = try!(commit_message(&repo, cfg, action, &id)
- .map_dbg_err_str("Failed to get commit message")
- .map_dbg_str("[GIT DELETE HOOK]: Got commit message"));
-
- try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
- .map_dbg_str("Committed")
- .map_dbg_err_str("Failed to commit")
- .map_dbg_str("[GIT DELETE HOOK]: Committed")
- .map_err_into(GHEK::RepositoryCommittingError)
- .map_into_hook_error()
- );
-
- index.write()
- .map_err_into(GHEK::RepositoryIndexWritingError)
- .map_dbg_err_str("Failed to write tree")
- .map_dbg_str("[GIT DELETE HOOK]: Wrote index")
- .map_into_hook_error()
- .map(|_| ())
- }
-
-}
-
diff --git a/libimagstorestdhook/src/vcs/git/error.rs b/libimagstorestdhook/src/vcs/git/error.rs
deleted file mode 100644
index 34ae043..0000000
--- a/libimagstorestdhook/src/vcs/git/error.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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 git2::Error as Git2Error;
-
-use libimagstore::hook::error::HookError as HE;
-use libimagstore::hook::error::HookErrorKind as HEK;
-use libimagstore::hook::result::HookResult;
-
-generate_error_module!(
- generate_error_types!(GitHookError, GitHookErrorKind,
- ConfigError => "Configuration Error",
- NoConfigError => "No Configuration",
- ConfigTypeError => "Configuration value type wrong",
-
- RepositoryError => "Error while interacting with git repository",
- RepositoryInitError => "Error while loading the git repository",
- RepositoryBackendError => "Error in the git library",
- RepositoryBranchError => "Error while interacting with git branch(es)",
- RepositoryBranchNameFetchingError => "Error while fetching branch name",
- RepositoryWrongBranchError => "Error because repository is on wrong branch",
- RepositoryIndexFetchingError => "Error while fetching Repository Index",
- RepositoryIndexWritingError => "Error while writing Repository Index",
- RepositoryPathAddingError => "Error while adding Path to Index",
- RepositoryCommittingError => "Error while committing",
- RepositoryParentFetchingError => "Error while fetching parent of commit",
- RepositoryStatusFetchError => "Error while fetching repository status",
-
- HeadFetchError => "Error while getting HEAD",
- NotOnBranch => "No Branch is checked out",
- MkRepo => "Repository creation error",
- MkSignature => "Error while building Signature object",
-
- RepositoryFileStatusError => "Error while getting file status",
-
- GitConfigFetchError => "Error fetching git config",
- GitConfigEditorFetchError => "Error fetching 'editor' from git config",
- EditorError => "Error while calling editor"
- );
-);
-
-impl GitHookError {
-
- pub fn inside_of<T>(self, h: HEK) -> HookResult<T> {
- Err(HE::new(h, Some(Box::new(self))))
- }
-
-}
-
-impl From<GitHookError> for HE {
-
- fn from(he: GitHookError) -> HE {
- HE::new(HEK::HookExecutionError, Some(Box::new(he)))
- }
-
-}
-
-impl From<Git2Error> for GitHookError {
-
- fn from(ge: Git2Error) -> GitHookError {
- GitHookError::new(GitHookErrorKind::RepositoryBackendError, Some(Box::new(ge)))
- }
-
-}
-
-pub trait MapIntoHookError<T> {
- fn map_into_hook_error(self) -> Result<T, HE>;
-}
-
-impl<T> MapIntoHookError<T> for Result<T, GitHookError> {
-
- fn map_into_hook_error(self) -> Result<T, HE> {
- self.map_err(|e| HE::new(HEK::HookExecutionError, Some(Box::new(e))))
- }
-
-}
-
-pub use self::error::GitHookError;
-pub use self::error::GitHookErrorKind;
-pub use self::error::MapErrInto;
-
diff --git a/libimagstorestdhook/src/vcs/git/mod.rs b/libimagstorestdhook/src/vcs/git/mod.rs
deleted file mode 100644
index 7fc504b..0000000
--- a/libimagstorestdhook/src/vcs/git/mod.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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
-//
-
-mod action;
-mod config;
-pub mod delete;
-mod error;
-mod result;
-mod runtime;
-pub mod store_unload;
-pub mod update;
-pub mod util;
-
diff --git a/libimagstorestdhook/src/vcs/git/result.rs b/libimagstorestdhook/src/vcs/git/result.rs
deleted file mode 100644
index bf161eb..0000000
--- a/libimagstorestdhook/src/vcs/git/result.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::result::Result as RResult;
-
-use vcs::git::error::GitHookError;
-
-pub type Result<T> = RResult<T, GitHookError>;
diff --git a/libimagstorestdhook/src/vcs/git/runtime.rs b/libimagstorestdhook/src/vcs/git/runtime.rs
deleted file mode 100644
index 27fde40..0000000
--- a/libimagstorestdhook/src/vcs/git/runtime.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::path::PathBuf;
-
-use git2::Repository;
-use toml::Value;
-
-use libimagerror::into::IntoError;
-use libimagerror::trace::MapErrTrace;
-use libimagstore::hook::error::CustomData;
-use libimagstore::hook::error::HookErrorKind as HEK;
-use libimagstore::hook::result::HookResult;
-use libimagutil::debug_result::*;
-
-use vcs::git::action::StoreAction;
-use vcs::git::result::Result;
-use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};
-
-/// Runtime object for git hook implementations.
-///
-/// Contains some utility functionality to hold the repository and the configuration for the hooks.
-pub struct Runtime {
- repository: Option<Repository>,
- config: Option<Value>,
-}
-
-impl Runtime {
-
- /// Build a `Runtime` object, pass the store path to build the `Repository` instance the
- /// `Runtime` has to contain.
- ///
- /// If the building of the `Repository` fails, this function `trace_error()`s the error and
- /// returns a `Runtime` object that does _not_ contain a `Repository`.
- pub fn new(storepath: &PathBuf) -> Runtime {
- Runtime {
- repository: Repository::open(storepath).map_err_trace().ok(),
- config: None,
- }
- }
-
- /// Set the configuration for the `Runtime`. Always returns `Ok(())`.
- pub fn set_config(&mut self, cfg: &Value) -> Result<()> {
- self.config = Some(cfg.clone());
- Ok(())
- }
-
- /// Check whether the `Runtime` has a `Repository`
- pub fn has_repository(&self) -> bool {
- self.repository.is_some()
- }
-
- /// Check whether the `Runtime` has a configuration
- pub fn has_config(&self) -> bool {
- self.config.is_some()
- }
-
- /// Get the the config value by reference or get an `Err()` which can be returned to the callee
- /// of the Hook.
- ///
- /// The `action` Argument is required in case of `Err()` so the error message can be build
- /// correctly.
- pub fn config_value_or_err(&self, action: &StoreAction) -> HookResult<&Value> {
- self.config
- .as_ref()
- .ok_or(GHEK::NoConfigError.into_error())
- .map_err_into(GHEK::ConfigError)
- .map_err(Box::new)
- .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
- .map_err(|e| e.with_custom_data(CustomData::default().aborting(false)))
- .map_dbg_err(|_| {
- format!("[GIT {} HOOK]: Couldn't get Value object from config", action.uppercase())
- })
- }
-
- /// Get the `Repository` object from the `Runtime` or an `Err()` that can be returned to the
- /// callee of the Hook.
- ///
- /// The `action` Argument is required in case of `Err()` so the error message can be build
- /// correctly.
- pub fn repository(&self, action: &StoreAction) -> HookResult<&Repository> {
- use vcs::git::error::MapIntoHookError;
-
- debug!("[GIT {} HOOK]: Getting repository", action.uppercase());
- self.repository
- .as_ref()
- .ok_or(GHEK::MkRepo.into_error())
- .map_err_into(GHEK::RepositoryError)
- .map_into_hook_error()
- .map_dbg_err(|_| format!("[GIT {} HOOK]: Couldn't fetch Repository", action.uppercase()))
- .map_dbg(|_| format!("[GIT {} HOOK]: Repository object fetched", action.uppercase()))
- }
-
- /// Ensure that the branch that is put in the configuration file is checked out, if any.
- pub fn ensure_cfg_branch_is_checked_out(&self, action: &StoreAction) -> HookResult<()> {
- use vcs::git::config::ensure_branch;
- use vcs::git::config::do_checkout_ensure_branch;
-
- debug!("[GIT {} HOOK]: Ensuring branch checkout", action.uppercase());
- let head = try!(self
- .repository(action)
- .and_then(|r| {
- debug!("[GIT {} HOOK]: Repository fetched, getting head", action.uppercase());
- r.head()
- .map_dbg_err_str("Couldn't fetch HEAD")
- .map_dbg_err(|e| format!("\tbecause = {:?}", e))
- .map_err_into(GHEK::HeadFetchError)
- .map_err(|e| e.into())
- }));
- debug!("[GIT {} HOOK]: HEAD fetched", action.uppercase());
-
- // TODO: Fail if not on branch? hmmh... I'm not sure
- if !head.is_branch() {
- debug!("[GIT {} HOOK]: HEAD is not a branch", action.uppercase());
- return Err(GHEK::NotOnBranch.into_error().into());
- }
- debug!("[GIT {} HOOK]: HEAD is a branch", action.uppercase());
-
- // Check out appropriate branch ... or fail
- match ensure_branch(self.config.as_ref()) {
- Ok(Some(s)) => {
- debug!("[GIT {} HOOK]: We have to ensure branch: {}", action.uppercase(), s);
- match head.name().map(|name| {
- debug!("[GIT {} HOOK]: {} == {}", action.uppercase(), name, s);
- name == s
- }) {
- Some(b) => {
- if b {
- debug!("[GIT {} HOOK]: Branch already checked out.", action.uppercase());
- Ok(())
- } else {
- debug!("[GIT {} HOOK]: Branch not checked out.", action.uppercase());
-
- if !do_checkout_ensure_branch(self.config.as_ref()) {
- Err(GHEK::RepositoryWrongBranchError.into_error())
- .map_err_into(GHEK::RepositoryError)
- } else {
- // Else try to check out the branch...
- unimplemented!()
- }
- }
- },
-
- None => Err(GHEK::RepositoryBranchNameFetchingError.into_error())
- .map_err_into(GHEK::RepositoryBranchError)
- .map_err_into(GHEK::RepositoryError),
- }
- },
- Ok(None) => {
- debug!("[GIT {} HOOK]: No branch to checkout", action.uppercase());
- Ok(())
- },
-
- Err(e) => Err(e).map_err_into(GHEK::RepositoryError),
- }
- .map_err(Box::new)
- .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
- .map_dbg(|_| format!("[GIT {} HOOK]: Branch checked out", action.uppercase()))
- }
-
-}
-
diff --git a/libimagstorestdhook/src/vcs/git/store_unload.rs b/libimagstorestdhook/src/vcs/git/store_unload.rs
deleted file mode 100644
index 52d8860..0000000
--- a/libimagstorestdhook/src/vcs/git/store_unload.rs
+++ /dev/null
@@ -1,264 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::path::PathBuf;
-use std::fmt::{Debug, Formatter, Error as FmtError};
-use std::result::Result as RResult;
-
-use toml::Value;
-
-use libimagerror::trace::trace_error;
-use libimagstore::storeid::StoreId;
-use libimagstore::hook::Hook;
-use libimagstore::hook::result::HookResult;
-use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
-use libimagstore::hook::accessor::StoreIdAccessor;
-use libimagutil::debug_result::*;
-
-use vcs::git::error::GitHookErrorKind as GHEK;
-use vcs::git::error::MapErrInto;
-use vcs::git::runtime::Runtime as GRuntime;
-
-pub struct StoreUnloadHook {
- storepath: PathBuf,
-
- runtime: GRuntime,
-}
-
-impl StoreUnloadHook {
-
- pub fn new(storepath: PathBuf) -> StoreUnloadHook {
- StoreUnloadHook {
- runtime: GRuntime::new(&storepath),
- storepath: storepath,
- }
- }
-
-}
-
-impl Debug for StoreUnloadHook {
- fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
- write!(fmt, "StoreUnloadHook(storepath={:?}, repository={}, cfg={:?})",
- self.storepath,
- (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
- self.runtime.has_config())
- }
-}
-
-
-impl Hook for StoreUnloadHook {
-
- fn name(&self) -> &'static str {
- "stdhook_git_storeunload"
- }
-
- /// Set the configuration of the hook. See
- /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
- ///
- /// This function traces the error (using `trace_error()`) that
- /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
- /// returns, if any.
- fn set_config(&mut self, config: &Value) {
- if let Err(e) = self.runtime.set_config(config) {
- trace_error(&e);
- }
- }
-
-}
-
-impl HookDataAccessorProvider for StoreUnloadHook {
-
- fn accessor(&self) -> HookDataAccessor {
- HookDataAccessor::StoreIdAccess(self)
- }
-}
-
-impl StoreIdAccessor for StoreUnloadHook {
-
- fn access(&self, id: &StoreId) -> HookResult<()> {
- use libimagerror::into::IntoError;
- use vcs::git::action::StoreAction;
- use vcs::git::config::commit_message;
- use vcs::git::error::MapIntoHookError;
- use vcs::git::util::fetch_index;
- use vcs::git::config::abort_on_repo_init_err;
- use vcs::git::config::is_enabled;
- use vcs::git::config::committing_is_enabled;
- use vcs::git::config::add_wt_changes_before_committing;
-
- use git2::{ADD_DEFAULT,
- StatusOptions,
- Status,
- StatusShow as STShow,
- STATUS_INDEX_NEW as I_NEW,
- STATUS_INDEX_DELETED as I_DEL,
- STATUS_INDEX_RENAMED as I_REN,
- STATUS_INDEX_MODIFIED as I_MOD,
- STATUS_WT_NEW as WT_NEW,
- STATUS_WT_DELETED as WT_DEL,
- STATUS_WT_RENAMED as WT_REN,
- STATUS_WT_MODIFIED as WT_MOD};
-
- let action = StoreAction::StoreUnload;
- let cfg = try!(self.runtime.config_value_or_err(&action));
-
- if !is_enabled(cfg) {
- return Ok(())
- }
-
- if !self.runtime.has_repository() {
- debug!("[GIT STORE UNLOAD HOOK]: Runtime has no repository...");
- if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
- // Abort on repo init failure
- debug!("[GIT STORE UNLOAD HOOK]: Config says we should abort if we have no repository");
- debug!("[GIT STORE UNLOAD HOOK]: Returing Err(_)");
- return Err(GHEK::RepositoryInitError.into_error())
- .map_err_into(GHEK::RepositoryError)
- .map_into_hook_error()
- } else {
- debug!("[GIT STORE UNLOAD HOOK]: Config says it is okay to not have a repository");
- debug!("[GIT STORE UNLOAD HOOK]: Returing Ok(())");
- return Ok(())
- }
- }
-
- let _ = try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
- let repo = try!(self.runtime.repository(&action));
- let mut index = try!(fetch_index(repo, &action));
-
- let check_dirty = |show: STShow, new: Status, modif: Status, del: Status, ren: Status| {
- let mut status_options = StatusOptions::new();
- status_options.show(show);
- status_options.include_untracked(true);
-
- repo.statuses(Some(&mut status_options))
- .map(|statuses| {
- statuses.iter()
- .map(|s| s.status())
- .map(|s| {
- debug!("STATUS_WT_NEW = {}", s == new);
- debug!("STATUS_WT_MODIFIED = {}", s == modif);
- debug!("STATUS_WT_DELETED = {}", s == del);
- debug!("STATUS_WT_RENAMED = {}", s == ren);
- s
- })
- .any(|s| s == new || s == modif || s == del || s == ren)
- })
- .map_err_into(GHEK::RepositoryStatusFetchError)
- .map_err_into(GHEK::RepositoryError)
- .map_into_hook_error()
- };
-
- if try!(check_dirty(STShow::Workdir, WT_NEW, WT_MOD, WT_DEL, WT_REN)) {
- if add_wt_changes_before_committing(cfg) {
- debug!("Adding WT changes before committing.");
- try!(index.add_all(&["*"], ADD_DEFAULT, None)
- .map_err_into(GHEK::RepositoryPathAddingError)
- .map_err_into(GHEK::RepositoryError)
- .map_into_hook_error());
- } else {
- warn!("WT dirty, but adding files before committing on Drop disabled.");
- warn!("Continuing without adding changes to the index.");
- }
- } else {
- debug!("WT not dirty.");
- }
-
- if try!(check_dirty(STShow::Index, I_NEW, I_MOD, I_DEL, I_REN)) {
- debug!("INDEX DIRTY!");
- } else {
- debug!("INDEX CLEAN... not continuing!");
- return Ok(());
- }
-
- let signature = try!(
- repo.signature()
- .map_err_into(GHEK::MkSignature)
- .map_dbg_err_str("Failed to fetch signature")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Fetched signature object")
- .map_into_hook_error()
- );
-
- let head = try!(
- repo.head()
- .map_err_into(GHEK::HeadFetchError)
- .map_dbg_err_str("Failed to fetch HEAD")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Fetched HEAD")
- .map_into_hook_error()
- );
-
- let tree_id = try!(
- index.write_tree()
- .map_err_into(GHEK::RepositoryIndexWritingError)
- .map_dbg_err_str("Failed to write tree")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Wrote index tree")
- .map_into_hook_error()
- );
-
- if !try!(committing_is_enabled(cfg)) {
- debug!("Committing not enabled. This is fine, returning now...");
- return Ok(())
- }
-
- let mut parents = Vec::new();
- {
- let commit = try!(
- repo.find_commit(head.target().unwrap())
- .map_err_into(GHEK::RepositoryParentFetchingError)
- .map_dbg_err_str("Failed to find commit HEAD")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Found commit HEAD")
- .map_into_hook_error()
- );
- parents.push(commit);
- }
-
- // for converting from Vec<Commit> to Vec<&Commit>
- let parents = parents.iter().collect::<Vec<_>>();
-
- let tree = try!(
- repo.find_tree(tree_id)
- .map_err_into(GHEK::RepositoryParentFetchingError)
- .map_dbg_err_str("Failed to find tree")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Found tree for index")
- .map_into_hook_error()
- );
-
- let message = try!(commit_message(&repo, cfg, action, &id)
- .map_dbg_err_str("Failed to get commit message")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Got commit message"));
-
- try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
- .map_dbg_str("Committed")
- .map_dbg_err_str("Failed to commit")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Committed")
- .map_err_into(GHEK::RepositoryCommittingError)
- .map_into_hook_error()
- );
-
- index.write()
- .map_err_into(GHEK::RepositoryIndexWritingError)
- .map_dbg_err_str("Failed to write tree")
- .map_dbg_str("[GIT STORE UNLOAD HOOK]: Wrote index")
- .map_into_hook_error()
- .map(|_| ())
- }
-
-}
-
-
diff --git a/libimagstorestdhook/src/vcs/git/update.rs b/libimagstorestdhook/src/vcs/git/update.rs
deleted file mode 100644
index f017c87..0000000
--- a/libimagstorestdhook/src/vcs/git/update.rs
+++ /dev/null
@@ -1,263 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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::path::PathBuf;
-use std::path::Path;
-use std::fmt::{Debug, Formatter, Error as FmtError};
-use std::result::Result as RResult;
-
-use toml::Value;
-
-use libimagerror::trace::trace_error;
-use libimagstore::hook::Hook;
-use libimagstore::hook::accessor::StoreIdAccessor;
-use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
-use libimagstore::hook::position::HookPosition;
-use libimagstore::hook::result::HookResult;
-use libimagstore::storeid::StoreId;
-use libimagutil::debug_result::*;
-
-use vcs::git::error::GitHookErrorKind as GHEK;
-use vcs::git::error::MapErrInto;
-use vcs::git::runtime::Runtime as GRuntime;
-
-/// The `UpdateHook` type
-///
-/// Represents a hook which is executed whenever a entry in the store is updated (written to disk).
-///
-/// # Time of execution
-///
-/// This hook is executed _after_ the store operation succeeded, so _after_ the file is written to
-/// disk.
-pub struct UpdateHook {
- storepath: PathBuf,
-
- runtime: GRuntime,
-
- position: HookPosition,
-}
-
-impl UpdateHook {
-
- pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
- UpdateHook {
- runtime: GRuntime::new(&storepath),
- storepath: storepath,
- position: p,
- }
- }
-
-}
-
-impl Debug for UpdateHook {
- fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
- write!(fmt, "UpdateHook(storepath={:?}, repository={}, pos={:?}, cfg={:?})",
- self.storepath,
- (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
- self.position,
- self.runtime.has_config())
- }
-}
-
-impl Hook for UpdateHook {
-
- fn name(&self) -> &'static str {
- "stdhook_git_update"
- }
-
- /// Set the configuration of the hook. See
- /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
- ///
- /// This function traces the error (using `trace_error()`) that
- /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
- /// returns, if any.
- fn set_config(&mut self, config: &Value) {
- if let Err(e) = self.runtime.set_config(config) {
- trace_error(&e);
- }
- }
-
-}
-
-impl HookDataAccessorProvider for UpdateHook {
-
- fn accessor(&self) -> HookDataAccessor {
- HookDataAccessor::StoreIdAccess(self)
- }
-}
-
-impl StoreIdAccessor for UpdateHook {
-
- /// The implementation of the UpdateHook
- ///
- /// # Scope
- ///
- /// This hook takes the git index and commits it either interactively or with a default message,
- /// if there is no configuration for an interactive commit.
- ///
- fn access(&self, id: &StoreId) -> HookResult<()> {
- use libimagerror::into::IntoError;
- use vcs::git::action::StoreAction;
- use vcs::git::config::commit_message;
- use vcs::git::error::MapIntoHookError;
- use vcs::git::util::fetch_index;
- use vcs::git::config::abort_on_repo_init_err;
- use vcs::git::config::is_enabled;
- use vcs::git::config::committing_is_enabled;
- use git2::{ADD_DEFAULT, STATUS_WT_NEW, STATUS_WT_MODIFIED, IndexMatchedPath};
-
- debug!("[GIT UPDATE HOOK]: {:?}", id);
-
- let action = StoreAction::Update;
- let cfg = try!(self.runtime.config_value_or_err(&action));
-
- if !is_enabled(cfg) {
- return Ok(());
- }
-
- if !self.runtime.has_repository() {
- debug!("[GIT UPDATE HOOK]: Runtime has no repository...");
- if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
- // Abort on repo init failure
- debug!("[GIT UPDATE HOOK]: Config says we should abort if we have no repository");
- debug!("[GIT UPDATE HOOK]: Returing Err(_)");
- return Err(GHEK::RepositoryInitError.into_error())
- .map_err_into(GHEK::RepositoryError)
- .map_into_hook_error()
- } else {
- debug!("[GIT UPDATE HOOK]: Config says it is okay to not have a repository");
- debug!("[GIT UPDATE HOOK]: Returing Ok(())");
- return Ok(())
- }
- }
-
- let _ = try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
- let repo = try!(self.runtime.repository(&action));
-
- let file_status = try!(
- repo
- .status_file(id.local())
- .map_dbg_err_str("Failed to fetch file status")
- .map_dbg_err(|e| format!("\t-> {:?}", e))
- .map_dbg_str("[GIT UPDATE HOOK]: Fetched file status")
- .map_err_into(GHEK::RepositoryFileStatusError)
- .map_into_hook_error()
- );
-
- debug!("File status: STATUS_WT_NEW = {}", file_status.contains(STATUS_WT_NEW));
- debug!("File status: STATUS_WT_MODIFIED = {}", file_status.contains(STATUS_WT_MODIFIED));
-
- if !file_status.contains(STATUS_WT_NEW) && !file_status.contains(STATUS_WT_MODIFIED) {
- // File seems to be unmodified and not new. This means that the file is already
- // committed and we can return here.
- return Ok(())
- }
-
- let mut index = try!(fetch_index(repo, &action));
-
- let signature = try!(
- repo.signature()
- .map_err_into(GHEK::MkSignature)
- .map_dbg_err_str("Failed to fetch signature")
- .map_dbg_str("[GIT UPDATE HOOK]: Fetched signature object")
- .map_into_hook_error()
- );
-
- let head = try!(
- repo.head()
- .map_err_into(GHEK::HeadFetchError)
- .map_dbg_err_str("Failed to fetch HEAD")
- .map_dbg_str("[GIT UPDATE HOOK]: Fetched HEAD")
- .map_into_hook_error()
- );
-
- let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
- if file_status.contains(STATUS_WT_NEW) || file_status.contains(STATUS_WT_MODIFIED) {
- debug!("[GIT CREATE HOOK]: File is modified/new: {}", path.display());
- 0
- } else {
- debug!("[GIT CREATE HOOK]: Ignoring file: {}", path.display());
- 1
- }
- };
-
- try!(
- index.add_all(&[id.local()], ADD_DEFAULT, Some(cb as &mut IndexMatchedPath))
- .map_err_into(GHEK::RepositoryPathAddingError)
- .map_dbg_err_str("Failed to add to index")
- .map_dbg(|_| format!("[GIT UPDATE HOOK]: Added id ({:?}) to index", id))
- .map_into_hook_error()
- );
-
- let tree_id = try!(
- index.write_tree()
- .map_err_into(GHEK::RepositoryIndexWritingError)
- .map_dbg_err_str("Failed to write tree")
- .map_dbg_str("[GIT UPDATE HOOK]: Wrote tree")
- .map_into_hook_error()
- );
-
- if !try!(committing_is_enabled(cfg)) {
- debug!("Committing not enabled. This is fine, returning now...");
- return Ok(())
- }
-
- let mut parents = Vec::new();
- {
- let commit = try!(
- repo.find_commit(head.target().unwrap())
- .map_err_into(GHEK::RepositoryParentFetchingError)
- .map_dbg_err_str("Failed to find commit HEAD")
- .map_dbg_str("[GIT UPDATE HOOK]: Fetched commit parents of HEAD")
- .map_into_hook_error()
- );
- parents.push(commit);
- }
-
- // for converting from Vec<Commit> to Vec<&Commit>
- let parents = parents.iter().collect::<Vec<_>>();
-
- let tree = try!(
- repo.find_tree(tree_id)
- .map_err_into(GHEK::RepositoryParentFetchingError)
- .map_dbg_err_str("Failed to find tree")
- .map_dbg_str("[GIT UPDATE HOOK]: Found Tree for parents")
- .map_into_hook_error()
- );
-
- let message = try!(commit_message(&repo, cfg, StoreAction::Update, &id)
- .map_dbg_err_str("Failed to get commit message")
- .map_dbg_str("[GIT UPDATE HOOK]: Fetched commit message"));
-
- try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
- .map_dbg_str("Committed")
- .map_dbg_err_str("Failed to commit")
- .map_err_into(GHEK::RepositoryCommittingError)
- .map_into_hook_error()
- );
-
- index.write()
- .map_err_into(GHEK::RepositoryIndexWritingError)
- .map_dbg_err_str("Failed to write tree")
- .map_into_hook_error()
- .map(|_| ())
- }
-
-}
-
diff --git a/libimagstorestdhook/src/vcs/git/util.rs b/libimagstorestdhook/src/vcs/git/util.rs
deleted file mode 100644
index bfeb2c2..0000000
--- a/libimagstorestdhook/src/vcs/git/util.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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
-//
-
-//! Utility functionality for integrating git hooks in the store
-//!
-//! Contains primitives to create a repository within the store path
-
-use git2::{Repository, Index};
-
-use vcs::git::error::GitHookErrorKind as GHEK;
-use vcs::git::error::MapErrInto;
-use vcs::git::action::StoreAction;
-use vcs::git::error::MapIntoHookError;
-
-use libimagutil::debug_result::*;
-use libimagstore::hook::error::HookError;
-
-pub fn fetch_index(repo: &Repository, action: &StoreAction) -> Result<Index, HookError> {
- debug!("[GIT {} HOOK]: Getting Index", action.uppercase());
- repo.index()
- .map_dbg_err(|_| format!("[GIT {} HOOK]: Couldn't fetch Index", action.uppercase()))
- .map_dbg(|_| format!("[GIT {} HOOK]: Index object fetched", action.uppercase()))
- .map_err_into(GHEK::RepositoryIndexFetchingError)
- .map_into_hook_error()
-}
-
diff --git a/libimagstorestdhook/src/vcs/mod.rs b/libimagstorestdhook/src/vcs/mod.rs
deleted file mode 100644
index 7449c7b..0000000
--- a/libimagstorestdhook/src/vcs/mod.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// imag - the personal information management suite for the commandline
-// Copyright (C) 2015, 2016 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
-//
-
-pub mod git;