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 to checkout the ensure_branch if it isn't checked out
|
||||||
try_checkout_ensure_branch = true
|
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]
|
[store.hooks.stdhook_git_update]
|
||||||
aspect = "vcs"
|
aspect = "vcs"
|
||||||
|
|
||||||
|
@ -108,3 +94,31 @@ interactive_editor = false
|
||||||
# Commit message if the commit is not interactive
|
# Commit message if the commit is not interactive
|
||||||
message = "Update"
|
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 sp = storepath;
|
||||||
|
|
||||||
let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
|
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),
|
(Box::new(GitUpdateHook::new(sp, HP::PostUpdate)) , "vcs", HP::PostUpdate),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,70 @@
|
||||||
use std::path::PathBuf;
|
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 toml::Value;
|
||||||
|
|
||||||
|
use libimagerror::trace::trace_error;
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagstore::storeid::StoreId;
|
||||||
use libimagstore::hook::Hook;
|
use libimagstore::hook::Hook;
|
||||||
use libimagstore::hook::result::HookResult;
|
use libimagstore::hook::result::HookResult;
|
||||||
use libimagstore::hook::position::HookPosition;
|
use libimagstore::hook::position::HookPosition;
|
||||||
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
|
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
|
||||||
use libimagstore::hook::accessor::StoreIdAccessor;
|
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 {
|
pub struct DeleteHook {
|
||||||
storepath: PathBuf,
|
storepath: PathBuf,
|
||||||
|
|
||||||
|
runtime: GRuntime,
|
||||||
|
|
||||||
position: HookPosition,
|
position: HookPosition,
|
||||||
config: Option<Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeleteHook {
|
impl DeleteHook {
|
||||||
|
|
||||||
pub fn new(storepath: PathBuf, p: HookPosition) -> DeleteHook {
|
pub fn new(storepath: PathBuf, p: HookPosition) -> DeleteHook {
|
||||||
DeleteHook {
|
DeleteHook {
|
||||||
|
runtime: GRuntime::new(&storepath),
|
||||||
storepath: storepath,
|
storepath: storepath,
|
||||||
position: p,
|
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 {
|
impl Hook for DeleteHook {
|
||||||
|
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"stdhook_git_delete"
|
"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) {
|
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 {
|
impl StoreIdAccessor for DeleteHook {
|
||||||
|
|
||||||
fn access(&self, id: &StoreId) -> HookResult<()> {
|
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);
|
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