Checkout callbacks #321

Merged
netnose merged 6 commits from checkout-callbacks into master 2016-10-03 04:53:30 -05:00
3 changed files with 84 additions and 9 deletions

View File

@ -2,6 +2,8 @@ package git
/* /*
#include <git2.h> #include <git2.h>
extern void _go_git_populate_checkout_cb(git_checkout_options *opts);
*/ */
import "C" import "C"
import ( import (
@ -10,9 +12,18 @@ import (
"unsafe" "unsafe"
) )
type CheckoutNotifyType uint
type CheckoutStrategy uint type CheckoutStrategy uint
const ( const (
CheckoutNotifyNone CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_NONE
CheckoutNotifyConflict CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_CONFLICT
CheckoutNotifyDirty CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_DIRTY
CheckoutNotifyUpdated CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_UPDATED
CheckoutNotifyUntracked CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_UNTRACKED
CheckoutNotifyIgnored CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_IGNORED
CheckoutNotifyAll CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_ALL
CheckoutNone CheckoutStrategy = C.GIT_CHECKOUT_NONE // Dry run, no actual updates CheckoutNone CheckoutStrategy = C.GIT_CHECKOUT_NONE // Dry run, no actual updates
CheckoutSafe CheckoutStrategy = C.GIT_CHECKOUT_SAFE // Allow safe updates that cannot overwrite uncommitted data CheckoutSafe CheckoutStrategy = C.GIT_CHECKOUT_SAFE // Allow safe updates that cannot overwrite uncommitted data
CheckoutForce CheckoutStrategy = C.GIT_CHECKOUT_FORCE // Allow all updates to force working directory to look like index CheckoutForce CheckoutStrategy = C.GIT_CHECKOUT_FORCE // Allow all updates to force working directory to look like index
@ -37,15 +48,21 @@ const (
CheckoutUpdateSubmodulesIfChanged CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED // Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) CheckoutUpdateSubmodulesIfChanged CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED // Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED)
) )
type CheckoutNotifyCallback func(why CheckoutNotifyType, path string, baseline, target, workdir DiffFile) ErrorCode
type CheckoutProgressCallback func(path string, completed, total uint) ErrorCode
type CheckoutOpts struct { type CheckoutOpts struct {
Strategy CheckoutStrategy // Default will be a dry run Strategy CheckoutStrategy // Default will be a dry run
DisableFilters bool // Don't apply filters like CRLF conversion DisableFilters bool // Don't apply filters like CRLF conversion
DirMode os.FileMode // Default is 0755 DirMode os.FileMode // Default is 0755
FileMode os.FileMode // Default is 0644 or 0755 as dictated by blob FileMode os.FileMode // Default is 0644 or 0755 as dictated by blob
FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY
TargetDirectory string // Alternative checkout path to workdir NotifyFlags CheckoutNotifyType // Default will be none
Paths []string NotifyCallback CheckoutNotifyCallback
Baseline *Tree ProgressCallback CheckoutProgressCallback
TargetDirectory string // Alternative checkout path to workdir
Paths []string
Baseline *Tree
} }
func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts { func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts {
@ -55,6 +72,13 @@ func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts {
opts.DirMode = os.FileMode(c.dir_mode) opts.DirMode = os.FileMode(c.dir_mode)
opts.FileMode = os.FileMode(c.file_mode) opts.FileMode = os.FileMode(c.file_mode)
opts.FileOpenFlags = int(c.file_open_flags) opts.FileOpenFlags = int(c.file_open_flags)
opts.NotifyFlags = CheckoutNotifyType(c.notify_flags)
if c.notify_payload != nil {
opts.NotifyCallback = pointerHandles.Get(c.notify_payload).(*CheckoutOpts).NotifyCallback
}
if c.progress_payload != nil {
opts.ProgressCallback = pointerHandles.Get(c.progress_payload).(*CheckoutOpts).ProgressCallback
}
if c.target_directory != nil { if c.target_directory != nil {
opts.TargetDirectory = C.GoString(c.target_directory) opts.TargetDirectory = C.GoString(c.target_directory)
} }
@ -70,6 +94,38 @@ func (opts *CheckoutOpts) toC() *C.git_checkout_options {
return &c return &c
} }
//export checkoutNotifyCallback
func checkoutNotifyCallback(why C.git_checkout_notify_t, cpath *C.char, cbaseline, ctarget, cworkdir, data unsafe.Pointer) int {
if data == nil {
return 0
}
path := C.GoString(cpath)
var baseline, target, workdir DiffFile
if cbaseline != nil {
baseline = diffFileFromC((*C.git_diff_file)(cbaseline))
}
if ctarget != nil {
target = diffFileFromC((*C.git_diff_file)(ctarget))
}
if cworkdir != nil {
workdir = diffFileFromC((*C.git_diff_file)(cworkdir))
}
opts := pointerHandles.Get(data).(*CheckoutOpts)
if opts.NotifyCallback == nil {
return 0
}
return int(opts.NotifyCallback(CheckoutNotifyType(why), path, baseline, target, workdir))
}
//export checkoutProgressCallback
func checkoutProgressCallback(path *C.char, completed_steps, total_steps C.size_t, data unsafe.Pointer) int {
opts := pointerHandles.Get(data).(*CheckoutOpts)
if opts.ProgressCallback == nil {
return 0
}
return int(opts.ProgressCallback(C.GoString(path), uint(completed_steps), uint(total_steps)))
}
// Convert the CheckoutOpts struct to the corresponding // Convert the CheckoutOpts struct to the corresponding
// C-struct. Returns a pointer to ptr, or nil if opts is nil, in order // C-struct. Returns a pointer to ptr, or nil if opts is nil, in order
// to help with what to pass. // to help with what to pass.
@ -83,6 +139,17 @@ func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) *C.gi
ptr.disable_filters = cbool(opts.DisableFilters) ptr.disable_filters = cbool(opts.DisableFilters)
ptr.dir_mode = C.uint(opts.DirMode.Perm()) ptr.dir_mode = C.uint(opts.DirMode.Perm())
ptr.file_mode = C.uint(opts.FileMode.Perm()) ptr.file_mode = C.uint(opts.FileMode.Perm())
ptr.notify_flags = C.uint(opts.NotifyFlags)
if opts.NotifyCallback != nil || opts.ProgressCallback != nil {
C._go_git_populate_checkout_cb(ptr)
}
payload := pointerHandles.Track(opts)
if opts.NotifyCallback != nil {
ptr.notify_payload = payload
}
if opts.ProgressCallback != nil {
ptr.progress_payload = payload
}
if opts.TargetDirectory != "" { if opts.TargetDirectory != "" {
ptr.target_directory = C.CString(opts.TargetDirectory) ptr.target_directory = C.CString(opts.TargetDirectory)
} }
@ -106,6 +173,9 @@ func freeCheckoutOpts(ptr *C.git_checkout_options) {
if ptr.paths.count > 0 { if ptr.paths.count > 0 {
freeStrarray(&ptr.paths) freeStrarray(&ptr.paths)
} }
if ptr.notify_payload != nil {
pointerHandles.Untrack(ptr.notify_payload)
}
} }
// Updates files in the index and the working tree to match the content of // Updates files in the index and the working tree to match the content of

View File

@ -41,7 +41,6 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error)
var ptr *C.git_repository var ptr *C.git_repository
ret := C.git_clone(&ptr, curl, cpath, copts) ret := C.git_clone(&ptr, curl, cpath, copts)
freeCheckoutOpts(&copts.checkout_opts)
if ret < 0 { if ret < 0 {
return nil, MakeGitError(ret) return nil, MakeGitError(ret)

View File

@ -10,6 +10,12 @@ void _go_git_populate_remote_cb(git_clone_options *opts)
opts->remote_cb = (git_remote_create_cb)remoteCreateCallback; opts->remote_cb = (git_remote_create_cb)remoteCreateCallback;
} }
void _go_git_populate_checkout_cb(git_checkout_options *opts)
{
opts->notify_cb = (git_checkout_notify_cb)checkoutNotifyCallback;
opts->progress_cb = (git_checkout_progress_cb)checkoutProgressCallback;
}
int _go_git_visit_submodule(git_repository *repo, void *fct) int _go_git_visit_submodule(git_repository *repo, void *fct)
{ {
return git_submodule_foreach(repo, (gogit_submodule_cbk)&SubmoduleVisitor, fct); return git_submodule_foreach(repo, (gogit_submodule_cbk)&SubmoduleVisitor, fct);