Merge pull request #739 from matthiasbeyer/libimagstorestdhook/git-delete-hook
libimagstorestdhook/git delete hook
This commit is contained in:
commit
9b332815b9
3 changed files with 157 additions and 20 deletions
42
imagrc.toml
42
imagrc.toml
|
@ -66,20 +66,6 @@ ensure_branch = "master"
|
|||
# Try to checkout the ensure_branch if it isn't checked out
|
||||
try_checkout_ensure_branch = true
|
||||
|
||||
[store.hooks.stdhook_git_delete]
|
||||
aspect = "vcs"
|
||||
|
||||
# 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 = "master"
|
||||
|
||||
# Try to checkout the ensure_branch if it isn't checked out
|
||||
try_checkout_ensure_branch = true
|
||||
|
||||
[store.hooks.stdhook_git_update]
|
||||
aspect = "vcs"
|
||||
|
||||
|
@ -108,3 +94,31 @@ interactive_editor = false
|
|||
# Commit message if the commit is not interactive
|
||||
message = "Update"
|
||||
|
||||
[store.hooks.stdhook_git_delete]
|
||||
aspect = "vcs"
|
||||
|
||||
# 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 = "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]
|
||||
|
||||
# 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"
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<'a> Runtime<'a> {
|
|||
let sp = storepath;
|
||||
|
||||
let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
|
||||
(Box::new(GitDeleteHook::new(sp.clone(), HP::PreDelete)) , "vcs", HP::PreDelete),
|
||||
(Box::new(GitDeleteHook::new(sp.clone(), HP::PostDelete)) , "vcs", HP::PostDelete),
|
||||
(Box::new(GitUpdateHook::new(sp, HP::PostUpdate)) , "vcs", HP::PostUpdate),
|
||||
];
|
||||
|
||||
|
|
|
@ -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(|_| ())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue