Merge branch 'libimagstorestdhook/git-update' into libimagstorestdhook/git
This commit is contained in:
commit
566c463383
7 changed files with 148 additions and 60 deletions
|
@ -8,6 +8,18 @@ pub enum StoreAction {
|
||||||
Delete,
|
Delete,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StoreAction {
|
||||||
|
|
||||||
|
pub fn uppercase(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
StoreAction::Create => "CREATE",
|
||||||
|
StoreAction::Retrieve => "RETRIEVE",
|
||||||
|
StoreAction::Update => "UPDATE",
|
||||||
|
StoreAction::Delete => "DELETE",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for StoreAction {
|
impl Display for StoreAction {
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||||
|
|
|
@ -13,11 +13,11 @@ pub fn commit_interactive(config: &Value) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit_message(config: &Value, action: StoreAction) -> String {
|
pub fn commit_message(config: &Value, action: StoreAction) -> Result<String> {
|
||||||
if commit_interactive(config) {
|
if commit_interactive(config) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
} else {
|
} else {
|
||||||
String::from("Dummy commit")
|
Ok(String::from("Dummy commit"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ impl StoreIdAccessor for CreateHook {
|
||||||
use vcs::git::action::StoreAction;
|
use vcs::git::action::StoreAction;
|
||||||
use vcs::git::config::commit_message;
|
use vcs::git::config::commit_message;
|
||||||
use vcs::git::error::MapIntoHookError;
|
use vcs::git::error::MapIntoHookError;
|
||||||
|
use vcs::git::util::fetch_index;
|
||||||
|
|
||||||
debug!("[GIT CREATE HOOK]: {:?}", id);
|
debug!("[GIT CREATE HOOK]: {:?}", id);
|
||||||
|
|
||||||
|
@ -102,32 +103,12 @@ impl StoreIdAccessor for CreateHook {
|
||||||
.map_into_hook_error()
|
.map_into_hook_error()
|
||||||
);
|
);
|
||||||
|
|
||||||
let cfg = try!(
|
let action = StoreAction::Create;
|
||||||
self.runtime
|
try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
|
||||||
.config_value_or_err()
|
|
||||||
.map_dbg_err_str("[GIT CREATE HOOK]: Couldn't get Value object from config")
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!("[GIT CREATE HOOK]: Ensuring branch checkout");
|
let cfg = try!(self.runtime.config_value_or_err(&action));
|
||||||
try!(self.runtime.ensure_cfg_branch_is_checked_out());
|
let repo = try!(self.runtime.repository(&action));
|
||||||
debug!("[GIT CREATE HOOK]: Branch checked out");
|
let mut index = try!(fetch_index(repo, &action));
|
||||||
|
|
||||||
debug!("[GIT CREATE HOOK]: Getting repository");
|
|
||||||
let repo = try!(
|
|
||||||
self.runtime
|
|
||||||
.repository()
|
|
||||||
.map_dbg_err_str("[GIT CREATE HOOK]: Couldn't fetch Repository")
|
|
||||||
.map_err_into(GHEK::RepositoryError)
|
|
||||||
.map_into_hook_error()
|
|
||||||
);
|
|
||||||
debug!("[GIT CREATE HOOK]: Repository object fetched");
|
|
||||||
|
|
||||||
let mut index = try!(
|
|
||||||
repo
|
|
||||||
.index()
|
|
||||||
.map_err_into(GHEK::RepositoryIndexFetchingError)
|
|
||||||
.map_into_hook_error()
|
|
||||||
);
|
|
||||||
|
|
||||||
let file_status = try!(
|
let file_status = try!(
|
||||||
repo
|
repo
|
||||||
|
|
|
@ -24,6 +24,7 @@ generate_error_module!(
|
||||||
RepositoryCommittingError => "Error while committing",
|
RepositoryCommittingError => "Error while committing",
|
||||||
RepositoryHeadFetchingError => "Error while fetching HEAD",
|
RepositoryHeadFetchingError => "Error while fetching HEAD",
|
||||||
RepositoryHeadTargetFetchingError => "Error while fetching target of HEAD",
|
RepositoryHeadTargetFetchingError => "Error while fetching target of HEAD",
|
||||||
|
RepositoryParentFetchingError => "Error while fetching parent of commit",
|
||||||
HeadFetchError => "Error while getting HEAD",
|
HeadFetchError => "Error while getting HEAD",
|
||||||
NotOnBranch => "No Branch is checked out",
|
NotOnBranch => "No Branch is checked out",
|
||||||
MkRepo => "Repository creation error",
|
MkRepo => "Repository creation error",
|
||||||
|
|
|
@ -10,6 +10,7 @@ use libimagstore::hook::error::HookErrorKind as HEK;
|
||||||
use libimagstore::hook::result::HookResult;
|
use libimagstore::hook::result::HookResult;
|
||||||
use libimagutil::debug_result::*;
|
use libimagutil::debug_result::*;
|
||||||
|
|
||||||
|
use vcs::git::action::StoreAction;
|
||||||
use vcs::git::result::Result;
|
use vcs::git::result::Result;
|
||||||
use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};
|
use vcs::git::error::{MapErrInto, GitHookErrorKind as GHEK};
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ impl Runtime {
|
||||||
self.config.is_some()
|
self.config.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config_value_or_err(&self) -> HookResult<&Value> {
|
pub fn config_value_or_err(&self, action: &StoreAction) -> HookResult<&Value> {
|
||||||
self.config
|
self.config
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(GHEK::NoConfigError.into_error())
|
.ok_or(GHEK::NoConfigError.into_error())
|
||||||
|
@ -55,21 +56,30 @@ impl Runtime {
|
||||||
.map_err(Box::new)
|
.map_err(Box::new)
|
||||||
.map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
|
.map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
|
||||||
.map_err(|mut e| e.with_custom_data(CustomData::default().aborting(false)))
|
.map_err(|mut e| e.with_custom_data(CustomData::default().aborting(false)))
|
||||||
|
.map_dbg_err(|_| {
|
||||||
|
format!("[GIT {} HOOK]: Couldn't get Value object from config", action.uppercase())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repository(&self) -> HookResult<&Repository> {
|
pub fn repository(&self, action: &StoreAction) -> HookResult<&Repository> {
|
||||||
|
use vcs::git::error::MapIntoHookError;
|
||||||
|
|
||||||
|
debug!("[GIT {} HOOK]: Getting repository", action.uppercase());
|
||||||
self.repository
|
self.repository
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(GHEK::MkRepo.into_error())
|
.ok_or(GHEK::MkRepo.into_error())
|
||||||
.map_err(Box::new)
|
.map_err_into(GHEK::RepositoryError)
|
||||||
.map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
|
.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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_cfg_branch_is_checked_out(&self) -> HookResult<()> {
|
pub fn ensure_cfg_branch_is_checked_out(&self, action: &StoreAction) -> HookResult<()> {
|
||||||
use vcs::git::config::ensure_branch;
|
use vcs::git::config::ensure_branch;
|
||||||
|
|
||||||
|
debug!("[GIT CREATE HOOK]: Ensuring branch checkout");
|
||||||
let head = try!(self
|
let head = try!(self
|
||||||
.repository()
|
.repository(action)
|
||||||
.and_then(|r| {
|
.and_then(|r| {
|
||||||
debug!("Repository fetched, getting head");
|
debug!("Repository fetched, getting head");
|
||||||
r.head()
|
r.head()
|
||||||
|
@ -119,6 +129,7 @@ impl Runtime {
|
||||||
}
|
}
|
||||||
.map_err(Box::new)
|
.map_err(Box::new)
|
||||||
.map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
|
.map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
|
||||||
|
.map_dbg_str("[GIT CREATE HOOK]: Branch checked out")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,58 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::fmt::{Debug, Formatter, Error as FmtError};
|
||||||
|
use std::result::Result as RResult;
|
||||||
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
use libimagstore::storeid::StoreId;
|
use libimagerror::into::IntoError;
|
||||||
|
use libimagerror::trace::trace_error;
|
||||||
use libimagstore::hook::Hook;
|
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 libimagstore::hook::accessor::StoreIdAccessor;
|
||||||
|
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
|
||||||
|
use libimagstore::hook::error::HookError as HE;
|
||||||
|
use libimagstore::hook::error::HookErrorKind as HEK;
|
||||||
|
use libimagstore::hook::position::HookPosition;
|
||||||
|
use libimagstore::hook::result::HookResult;
|
||||||
|
use libimagstore::storeid::StoreId;
|
||||||
|
use libimagutil::debug_result::*;
|
||||||
|
|
||||||
|
use vcs::git::error::GitHookError as GHE;
|
||||||
|
use vcs::git::error::GitHookErrorKind as GHEK;
|
||||||
|
use vcs::git::error::MapErrInto;
|
||||||
|
use vcs::git::error::MapIntoHookError;
|
||||||
|
use vcs::git::result::Result;
|
||||||
|
use vcs::git::runtime::Runtime as GRuntime;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UpdateHook {
|
pub struct UpdateHook {
|
||||||
storepath: PathBuf,
|
storepath: PathBuf,
|
||||||
|
|
||||||
|
runtime: GRuntime,
|
||||||
|
|
||||||
position: HookPosition,
|
position: HookPosition,
|
||||||
config: Option<Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdateHook {
|
impl UpdateHook {
|
||||||
|
|
||||||
pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
|
pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
|
||||||
UpdateHook {
|
UpdateHook {
|
||||||
|
runtime: GRuntime::new(&storepath),
|
||||||
storepath: storepath,
|
storepath: storepath,
|
||||||
position: p,
|
position: p,
|
||||||
config: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl Hook for UpdateHook {
|
||||||
|
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
|
@ -36,7 +60,9 @@ impl Hook for UpdateHook {
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,9 +76,70 @@ impl HookDataAccessorProvider for UpdateHook {
|
||||||
|
|
||||||
impl StoreIdAccessor for UpdateHook {
|
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<()> {
|
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;
|
||||||
|
|
||||||
debug!("[GIT UPDATE HOOK]: {:?}", id);
|
debug!("[GIT UPDATE HOOK]: {:?}", id);
|
||||||
Ok(())
|
|
||||||
|
let action = StoreAction::Update;
|
||||||
|
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 tree_id = try!(
|
||||||
|
index.write_tree()
|
||||||
|
.map_err_into(GHEK::RepositoryIndexWritingError)
|
||||||
|
.map_into_hook_error()
|
||||||
|
);
|
||||||
|
|
||||||
|
let signature = try!(
|
||||||
|
repo.signature()
|
||||||
|
.map_err_into(GHEK::MkSignature)
|
||||||
|
.map_into_hook_error()
|
||||||
|
);
|
||||||
|
|
||||||
|
let head = try!(
|
||||||
|
repo.head()
|
||||||
|
.map_err_into(GHEK::HeadFetchError)
|
||||||
|
.map_into_hook_error()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut parents = Vec::new();
|
||||||
|
{
|
||||||
|
let commit = try!(
|
||||||
|
repo.find_commit(head.target().unwrap())
|
||||||
|
.map_err_into(GHEK::RepositoryParentFetchingError)
|
||||||
|
.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_into_hook_error()
|
||||||
|
);
|
||||||
|
|
||||||
|
let message = try!(commit_message(cfg, StoreAction::Update));
|
||||||
|
|
||||||
|
repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
|
||||||
|
.map_err_into(GHEK::RepositoryCommittingError)
|
||||||
|
.map_into_hook_error()
|
||||||
|
.map(|_| ())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,23 @@
|
||||||
//!
|
//!
|
||||||
//! Contains primitives to create a repository within the store path
|
//! Contains primitives to create a repository within the store path
|
||||||
|
|
||||||
use git2::Repository;
|
use git2::{Repository, Index};
|
||||||
use git2::RepositoryInitOptions;
|
|
||||||
|
|
||||||
use libimagstore::store::Store;
|
|
||||||
|
|
||||||
use vcs::git::error::GitHookErrorKind as GHEK;
|
use vcs::git::error::GitHookErrorKind as GHEK;
|
||||||
use vcs::git::error::MapErrInto;
|
use vcs::git::error::MapErrInto;
|
||||||
use vcs::git::result::Result;
|
use vcs::git::runtime::Runtime as GRuntime;
|
||||||
|
use vcs::git::action::StoreAction;
|
||||||
|
use vcs::git::error::MapIntoHookError;
|
||||||
|
|
||||||
pub fn mkrepo(store: &Store) -> Result<()> {
|
use libimagutil::debug_result::*;
|
||||||
let mut opts = RepositoryInitOptions::new();
|
use libimagstore::hook::error::HookError;
|
||||||
opts.bare(false);
|
|
||||||
opts.no_reinit(true);
|
pub fn fetch_index(repo: &Repository, action: &StoreAction) -> Result<Index, HookError> {
|
||||||
opts.mkdir(false);
|
debug!("[GIT {} HOOK]: Getting Index", action.uppercase());
|
||||||
opts.external_template(false);
|
repo.index()
|
||||||
Repository::init_opts(store.path(), &opts)
|
.map_dbg_err(|_| format!("[GIT {} HOOK]: Couldn't fetch Index", action.uppercase()))
|
||||||
.map(|_| ())
|
.map_dbg(|_| format!("[GIT {} HOOK]: Index object fetched", action.uppercase()))
|
||||||
.map_err_into(GHEK::MkRepo)
|
.map_err_into(GHEK::RepositoryIndexFetchingError)
|
||||||
}
|
.map_into_hook_error()
|
||||||
|
|
||||||
pub fn hasrepo(store: &Store) -> bool {
|
|
||||||
Repository::open(store.path()).is_ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue