summaryrefslogtreecommitdiffstats
path: root/libimagstorestdhook/src
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2016-09-18 09:49:47 +0200
committerGitHub <noreply@github.com>2016-09-18 09:49:46 +0200
commit9b332815b9b69dd3f4bb69b5247ad19966920689 (patch)
tree3819f386f36a0eb04eca2c539b8741c10a4a6d80 /libimagstorestdhook/src
parentee60f6057cd7887682fbde0a22d22b012475598c (diff)
parentf9ea5c50137c1cffabb4ace99c3a74f7860d8b4a (diff)
Merge pull request #739 from matthiasbeyer/libimagstorestdhook/git-delete-hook
libimagstorestdhook/git delete hook
Diffstat (limited to 'libimagstorestdhook/src')
-rw-r--r--libimagstorestdhook/src/vcs/git/delete.rs133
1 files changed, 128 insertions, 5 deletions
diff --git a/libimagstorestdhook/src/vcs/git/delete.rs b/libimagstorestdhook/src/vcs/git/delete.rs
index 902e5096..63e9f65c 100644
--- a/libimagstorestdhook/src/vcs/git/delete.rs
+++ b/libimagstorestdhook/src/vcs/git/delete.rs
@@ -1,42 +1,70 @@
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;
-#[derive(Debug)]
pub struct DeleteHook {
storepath: PathBuf,
+ runtime: GRuntime,
+
position: HookPosition,
- config: Option<Value>,
}
impl DeleteHook {
pub fn new(storepath: PathBuf, p: HookPosition) -> DeleteHook {
DeleteHook {
+ runtime: GRuntime::new(&storepath),
storepath: storepath,
position: p,
- config: None,
}
}
}
+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) {
- self.config = Some(config.clone());
+ if let Err(e) = self.runtime.set_config(config) {
+ trace_error(&e);
+ }
}
}
@@ -51,8 +79,103 @@ impl HookDataAccessorProvider for DeleteHook {
impl StoreIdAccessor for DeleteHook {
fn access(&self, id: &StoreId) -> HookResult<()> {
+ use vcs::git::action::StoreAction;
+ use vcs::git::config::commit_message;
+ use vcs::git::error::MapIntoHookError;
+ use vcs::git::util::fetch_index;
+ use git2::{ADD_DEFAULT, STATUS_WT_DELETED, IndexMatchedPath};
+
debug!("[GIT DELETE HOOK]: {:?}", id);
- Ok(())
+
+ let action = StoreAction::Delete;
+ let cfg = try!(self.runtime.config_value_or_err(&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_into_hook_error()
+ );
+
+ let head = try!(
+ repo.head()
+ .map_err_into(GHEK::HeadFetchError)
+ .map_dbg_err_str("Failed to fetch 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_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_into_hook_error()
+ );
+
+ let tree_id = try!(
+ index.write_tree()
+ .map_err_into(GHEK::RepositoryIndexWritingError)
+ .map_dbg_err_str("Failed to write tree")
+ .map_into_hook_error()
+ );
+
+ 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_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_into_hook_error()
+ );
+
+ let message = try!(commit_message(&repo, cfg, action)
+ .map_dbg_err_str("Failed to get 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(|_| ())
}
}