2013-03-19 16:49:07 -05:00
package git
/ *
# include < git2 . h >
2016-05-29 06:33:53 -05:00
2020-12-05 15:13:59 -06:00
extern void _go_git_populate_checkout_callbacks ( git_checkout_options * opts ) ;
2013-03-19 16:49:07 -05:00
* /
import "C"
import (
"os"
2014-03-26 13:28:48 -05:00
"runtime"
2015-01-21 23:44:51 -06:00
"unsafe"
2013-03-19 16:49:07 -05:00
)
2016-05-29 06:33:53 -05:00
type CheckoutNotifyType uint
2013-03-19 16:49:07 -05:00
type CheckoutStrategy uint
const (
2016-05-29 06:33:53 -05:00
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
2013-09-12 03:40:57 -05:00
CheckoutNone CheckoutStrategy = C . GIT_CHECKOUT_NONE // Dry run, no actual updates
2014-10-27 09:12:18 -05:00
CheckoutSafe CheckoutStrategy = C . GIT_CHECKOUT_SAFE // Allow safe updates that cannot overwrite uncommitted data
2015-07-09 17:31:32 -05:00
CheckoutForce CheckoutStrategy = C . GIT_CHECKOUT_FORCE // Allow all updates to force working directory to look like index
2015-03-14 19:49:32 -05:00
CheckoutRecreateMissing CheckoutStrategy = C . GIT_CHECKOUT_RECREATE_MISSING // Allow checkout to recreate missing files
2014-10-27 09:12:18 -05:00
CheckoutAllowConflicts CheckoutStrategy = C . GIT_CHECKOUT_ALLOW_CONFLICTS // Allow checkout to make safe updates even if conflicts are found
CheckoutRemoveUntracked CheckoutStrategy = C . GIT_CHECKOUT_REMOVE_UNTRACKED // Remove untracked files not in index (that are not ignored)
CheckoutRemoveIgnored CheckoutStrategy = C . GIT_CHECKOUT_REMOVE_IGNORED // Remove ignored files not in index
2015-03-04 13:31:41 -06:00
CheckoutUpdateOnly CheckoutStrategy = C . GIT_CHECKOUT_UPDATE_ONLY // Only update existing files, don't create new ones
2014-10-27 09:12:18 -05:00
CheckoutDontUpdateIndex CheckoutStrategy = C . GIT_CHECKOUT_DONT_UPDATE_INDEX // Normally checkout updates index entries as it goes; this stops that
CheckoutNoRefresh CheckoutStrategy = C . GIT_CHECKOUT_NO_REFRESH // Don't refresh index/config/etc before doing checkout
2015-03-14 19:49:32 -05:00
CheckoutSkipUnmerged CheckoutStrategy = C . GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files
2018-12-17 01:56:37 -06:00
CheckoutUseOurs CheckoutStrategy = C . GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
2015-03-14 19:49:32 -05:00
CheckoutUseTheirs CheckoutStrategy = C . GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index
2015-03-04 13:31:41 -06:00
CheckoutDisablePathspecMatch CheckoutStrategy = C . GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths
2015-03-14 19:49:32 -05:00
CheckoutSkipLockedDirectories CheckoutStrategy = C . GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES // Ignore directories in use, they will be left empty
CheckoutDontOverwriteIgnored CheckoutStrategy = C . GIT_CHECKOUT_DONT_OVERWRITE_IGNORED // Don't overwrite ignored files that exist in the checkout target
CheckoutConflictStyleMerge CheckoutStrategy = C . GIT_CHECKOUT_CONFLICT_STYLE_MERGE // Write normal merge files for conflicts
CheckoutConflictStyleDiff3 CheckoutStrategy = C . GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 // Include common ancestor data in diff3 format files for conflicts
CheckoutDontRemoveExisting CheckoutStrategy = C . GIT_CHECKOUT_DONT_REMOVE_EXISTING // Don't overwrite existing files or folders
CheckoutDontWriteIndex CheckoutStrategy = C . GIT_CHECKOUT_DONT_WRITE_INDEX // Normally checkout writes the index upon completion; this prevents that
2014-10-27 09:12:18 -05:00
CheckoutUpdateSubmodules CheckoutStrategy = C . GIT_CHECKOUT_UPDATE_SUBMODULES // Recursively checkout submodules with same options (NOT IMPLEMENTED)
CheckoutUpdateSubmodulesIfChanged CheckoutStrategy = C . GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED // Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED)
2013-03-19 16:49:07 -05:00
)
2020-12-01 21:11:41 -06:00
type CheckoutNotifyCallback func ( why CheckoutNotifyType , path string , baseline , target , workdir DiffFile ) error
type CheckoutProgressCallback func ( path string , completed , total uint )
2016-05-29 06:33:53 -05:00
2020-12-05 09:23:44 -06:00
type CheckoutOptions struct {
2016-05-29 06:33:53 -05:00
Strategy CheckoutStrategy // Default will be a dry run
DisableFilters bool // Don't apply filters like CRLF conversion
DirMode os . FileMode // Default is 0755
FileMode os . FileMode // Default is 0644 or 0755 as dictated by blob
FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY
NotifyFlags CheckoutNotifyType // Default will be none
NotifyCallback CheckoutNotifyCallback
ProgressCallback CheckoutProgressCallback
TargetDirectory string // Alternative checkout path to workdir
Paths [ ] string
Baseline * Tree
2014-03-26 13:28:48 -05:00
}
2020-12-05 09:23:44 -06:00
func checkoutOptionsFromC ( c * C . git_checkout_options ) CheckoutOptions {
opts := CheckoutOptions {
Strategy : CheckoutStrategy ( c . checkout_strategy ) ,
DisableFilters : c . disable_filters != 0 ,
DirMode : os . FileMode ( c . dir_mode ) ,
FileMode : os . FileMode ( c . file_mode ) ,
FileOpenFlags : int ( c . file_open_flags ) ,
NotifyFlags : CheckoutNotifyType ( c . notify_flags ) ,
}
2016-05-29 08:14:16 -05:00
if c . notify_payload != nil {
2020-12-05 15:13:59 -06:00
opts . NotifyCallback = pointerHandles . Get ( c . notify_payload ) . ( * checkoutCallbackData ) . options . NotifyCallback
2016-05-29 08:14:16 -05:00
}
if c . progress_payload != nil {
2020-12-05 15:13:59 -06:00
opts . ProgressCallback = pointerHandles . Get ( c . progress_payload ) . ( * checkoutCallbackData ) . options . ProgressCallback
2016-05-29 08:14:16 -05:00
}
2015-03-04 13:38:19 -06:00
if c . target_directory != nil {
opts . TargetDirectory = C . GoString ( c . target_directory )
}
return opts
}
2020-12-05 15:13:59 -06:00
type checkoutCallbackData struct {
options * CheckoutOptions
errorTarget * error
2013-03-19 16:49:07 -05:00
}
2016-05-29 06:33:53 -05:00
//export checkoutNotifyCallback
2020-12-05 15:13:59 -06:00
func checkoutNotifyCallback (
why C . git_checkout_notify_t ,
cpath * C . char ,
cbaseline , ctarget , cworkdir , handle unsafe . Pointer ,
) C . int {
if handle == nil {
return C . int ( ErrorCodeOK )
2016-05-29 08:27:48 -05:00
}
2016-05-29 06:33:53 -05:00
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 ) )
}
2020-12-05 15:13:59 -06:00
data := pointerHandles . Get ( handle ) . ( * checkoutCallbackData )
if data . options . NotifyCallback == nil {
return C . int ( ErrorCodeOK )
}
2020-12-01 21:11:41 -06:00
err := data . options . NotifyCallback ( CheckoutNotifyType ( why ) , path , baseline , target , workdir )
if err != nil {
* data . errorTarget = err
2020-12-05 15:13:59 -06:00
return C . int ( ErrorCodeUser )
2016-05-29 06:33:53 -05:00
}
2020-12-05 15:13:59 -06:00
return C . int ( ErrorCodeOK )
2016-05-29 06:33:53 -05:00
}
//export checkoutProgressCallback
2020-12-05 15:13:59 -06:00
func checkoutProgressCallback (
path * C . char ,
completed_steps , total_steps C . size_t ,
handle unsafe . Pointer ,
) {
data := pointerHandles . Get ( handle ) . ( * checkoutCallbackData )
if data . options . ProgressCallback == nil {
return
2016-05-29 06:33:53 -05:00
}
2020-12-05 15:13:59 -06:00
data . options . ProgressCallback ( C . GoString ( path ) , uint ( completed_steps ) , uint ( total_steps ) )
2016-05-29 06:33:53 -05:00
}
2020-12-10 09:19:41 -06:00
// populateCheckoutOptions populates the provided C-struct with the contents of
// the provided CheckoutOptions struct. Returns copts, or nil if opts is nil,
// in order to help with what to pass.
func populateCheckoutOptions ( copts * C . git_checkout_options , opts * CheckoutOptions , errorTarget * error ) * C . git_checkout_options {
C . git_checkout_options_init ( copts , C . GIT_CHECKOUT_OPTIONS_VERSION )
2013-03-19 16:49:07 -05:00
if opts == nil {
2014-03-10 21:27:35 -05:00
return nil
2013-03-19 16:49:07 -05:00
}
2014-03-10 21:27:35 -05:00
2020-12-10 09:19:41 -06:00
copts . checkout_strategy = C . uint ( opts . Strategy )
copts . disable_filters = cbool ( opts . DisableFilters )
copts . dir_mode = C . uint ( opts . DirMode . Perm ( ) )
copts . file_mode = C . uint ( opts . FileMode . Perm ( ) )
copts . notify_flags = C . uint ( opts . NotifyFlags )
2016-05-29 06:33:53 -05:00
if opts . NotifyCallback != nil || opts . ProgressCallback != nil {
2020-12-10 09:19:41 -06:00
C . _go_git_populate_checkout_callbacks ( copts )
2020-12-05 15:13:59 -06:00
data := & checkoutCallbackData {
options : opts ,
errorTarget : errorTarget ,
}
payload := pointerHandles . Track ( data )
if opts . NotifyCallback != nil {
2020-12-10 09:19:41 -06:00
copts . notify_payload = payload
2020-12-05 15:13:59 -06:00
}
if opts . ProgressCallback != nil {
2020-12-10 09:19:41 -06:00
copts . progress_payload = payload
2020-12-05 15:13:59 -06:00
}
2016-05-29 06:33:53 -05:00
}
2015-01-21 23:44:51 -06:00
if opts . TargetDirectory != "" {
2020-12-10 09:19:41 -06:00
copts . target_directory = C . CString ( opts . TargetDirectory )
2015-01-21 23:44:51 -06:00
}
2015-03-14 09:27:47 -05:00
if len ( opts . Paths ) > 0 {
2020-12-10 09:19:41 -06:00
copts . paths . strings = makeCStringsFromStrings ( opts . Paths )
copts . paths . count = C . size_t ( len ( opts . Paths ) )
2015-03-14 09:27:47 -05:00
}
2015-09-16 15:08:37 -05:00
if opts . Baseline != nil {
2020-12-10 09:19:41 -06:00
copts . baseline = opts . Baseline . cast_ptr
2015-09-16 15:08:37 -05:00
}
2020-12-10 09:19:41 -06:00
return copts
2013-03-19 16:49:07 -05:00
}
2020-12-10 09:19:41 -06:00
func freeCheckoutOptions ( copts * C . git_checkout_options ) {
if copts == nil {
2015-01-21 23:44:51 -06:00
return
}
2020-12-10 09:19:41 -06:00
C . free ( unsafe . Pointer ( copts . target_directory ) )
if copts . paths . count > 0 {
freeStrarray ( & copts . paths )
2015-03-14 09:27:47 -05:00
}
2020-12-10 09:19:41 -06:00
if copts . notify_payload != nil {
pointerHandles . Untrack ( copts . notify_payload )
} else if copts . progress_payload != nil {
pointerHandles . Untrack ( copts . progress_payload )
2016-05-29 06:33:53 -05:00
}
2015-01-21 23:44:51 -06:00
}
2013-03-19 16:49:07 -05:00
// Updates files in the index and the working tree to match the content of
2014-03-10 21:27:35 -05:00
// the commit pointed at by HEAD. opts may be nil.
2020-12-05 09:23:44 -06:00
func ( v * Repository ) CheckoutHead ( opts * CheckoutOptions ) error {
2013-09-18 02:23:47 -05:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2020-12-05 15:13:59 -06:00
var err error
2020-12-10 09:19:41 -06:00
cOpts := populateCheckoutOptions ( & C . git_checkout_options { } , opts , & err )
2020-12-05 09:23:44 -06:00
defer freeCheckoutOptions ( cOpts )
2015-01-21 23:44:51 -06:00
ret := C . git_checkout_head ( v . ptr , cOpts )
2017-07-07 16:45:09 -05:00
runtime . KeepAlive ( v )
2020-12-05 15:13:59 -06:00
if ret == C . int ( ErrorCodeUser ) && err != nil {
return err
}
2013-03-19 16:49:07 -05:00
if ret < 0 {
2013-07-07 09:43:44 -05:00
return MakeGitError ( ret )
2013-03-19 16:49:07 -05:00
}
return nil
}
2014-03-10 21:27:35 -05:00
// Updates files in the working tree to match the content of the given
2014-03-10 21:30:56 -05:00
// index. If index is nil, the repository's index will be used. opts
// may be nil.
2020-12-05 09:23:44 -06:00
func ( v * Repository ) CheckoutIndex ( index * Index , opts * CheckoutOptions ) error {
2014-03-10 21:30:56 -05:00
var iptr * C . git_index = nil
if index != nil {
iptr = index . ptr
}
2013-09-18 02:23:47 -05:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2020-12-05 15:13:59 -06:00
var err error
2020-12-10 09:19:41 -06:00
cOpts := populateCheckoutOptions ( & C . git_checkout_options { } , opts , & err )
2020-12-05 09:23:44 -06:00
defer freeCheckoutOptions ( cOpts )
2015-01-21 23:44:51 -06:00
ret := C . git_checkout_index ( v . ptr , iptr , cOpts )
2017-07-07 16:45:09 -05:00
runtime . KeepAlive ( v )
2020-12-05 15:13:59 -06:00
if ret == C . int ( ErrorCodeUser ) && err != nil {
return err
}
2014-08-27 04:03:21 -05:00
if ret < 0 {
return MakeGitError ( ret )
}
return nil
}
2020-12-05 09:23:44 -06:00
func ( v * Repository ) CheckoutTree ( tree * Tree , opts * CheckoutOptions ) error {
2014-08-27 04:03:21 -05:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2020-12-05 15:13:59 -06:00
var err error
2020-12-10 09:19:41 -06:00
cOpts := populateCheckoutOptions ( & C . git_checkout_options { } , opts , & err )
2020-12-05 09:23:44 -06:00
defer freeCheckoutOptions ( cOpts )
2015-01-21 23:44:51 -06:00
ret := C . git_checkout_tree ( v . ptr , tree . ptr , cOpts )
2017-07-07 16:45:09 -05:00
runtime . KeepAlive ( v )
2020-12-05 15:13:59 -06:00
runtime . KeepAlive ( tree )
if ret == C . int ( ErrorCodeUser ) && err != nil {
return err
}
2013-03-19 16:49:07 -05:00
if ret < 0 {
2013-07-07 09:43:44 -05:00
return MakeGitError ( ret )
2013-03-19 16:49:07 -05:00
}
return nil
2015-09-16 15:08:37 -05:00
}