2016-08-06 23:40:59 -05:00
package git
/ *
# include < git2 . h >
* /
import "C"
import (
2017-07-08 13:58:08 -05:00
"errors"
2016-08-06 23:40:59 -05:00
"runtime"
"unsafe"
)
// RebaseOperationType is the type of rebase operation
type RebaseOperationType uint
const (
// RebaseOperationPick The given commit is to be cherry-picked. The client should commit the changes and continue if there are no conflicts.
RebaseOperationPick RebaseOperationType = C . GIT_REBASE_OPERATION_PICK
// RebaseOperationEdit The given commit is to be cherry-picked, but the client should stop to allow the user to edit the changes before committing them.
RebaseOperationEdit RebaseOperationType = C . GIT_REBASE_OPERATION_EDIT
// RebaseOperationSquash The given commit is to be squashed into the previous commit. The commit message will be merged with the previous message.
RebaseOperationSquash RebaseOperationType = C . GIT_REBASE_OPERATION_SQUASH
// RebaseOperationFixup No commit will be cherry-picked. The client should run the given command and (if successful) continue.
RebaseOperationFixup RebaseOperationType = C . GIT_REBASE_OPERATION_FIXUP
// RebaseOperationExec No commit will be cherry-picked. The client should run the given command and (if successful) continue.
RebaseOperationExec RebaseOperationType = C . GIT_REBASE_OPERATION_EXEC
)
2017-07-08 13:58:08 -05:00
// Special value indicating that there is no currently active operation
var RebaseNoOperation uint = ^ uint ( 0 )
// Error returned if there is no current rebase operation
2017-10-01 23:04:08 -05:00
var ErrRebaseNoOperation = errors . New ( "no current rebase operation" )
2017-07-08 13:58:08 -05:00
2016-08-06 23:40:59 -05:00
// RebaseOperation describes a single instruction/operation to be performed during the rebase.
type RebaseOperation struct {
Type RebaseOperationType
2016-10-31 18:57:23 -05:00
Id * Oid
2016-08-06 23:40:59 -05:00
Exec string
}
2016-08-07 02:31:42 -05:00
func newRebaseOperationFromC ( c * C . git_rebase_operation ) * RebaseOperation {
2016-08-06 23:40:59 -05:00
operation := & RebaseOperation { }
operation . Type = RebaseOperationType ( c . _type )
2016-10-31 18:57:23 -05:00
operation . Id = newOidFromC ( & c . id )
2016-08-06 23:40:59 -05:00
operation . Exec = C . GoString ( c . exec )
return operation
}
// RebaseOptions are used to tell the rebase machinery how to operate
2016-09-13 01:03:16 -05:00
type RebaseOptions struct {
Version uint
Quiet int
InMemory int
RewriteNotesRef string
MergeOptions MergeOptions
CheckoutOptions CheckoutOpts
}
// DefaultRebaseOptions returns a RebaseOptions with default values.
func DefaultRebaseOptions ( ) ( RebaseOptions , error ) {
opts := C . git_rebase_options { }
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_rebase_init_options ( & opts , C . GIT_REBASE_OPTIONS_VERSION )
if ecode < 0 {
return RebaseOptions { } , MakeGitError ( ecode )
}
return rebaseOptionsFromC ( & opts ) , nil
}
func rebaseOptionsFromC ( opts * C . git_rebase_options ) RebaseOptions {
return RebaseOptions {
Version : uint ( opts . version ) ,
Quiet : int ( opts . quiet ) ,
InMemory : int ( opts . inmemory ) ,
RewriteNotesRef : C . GoString ( opts . rewrite_notes_ref ) ,
MergeOptions : mergeOptionsFromC ( & opts . merge_options ) ,
CheckoutOptions : checkoutOptionsFromC ( & opts . checkout_options ) ,
}
}
func ( ro * RebaseOptions ) toC ( ) * C . git_rebase_options {
if ro == nil {
return nil
}
return & C . git_rebase_options {
version : C . uint ( ro . Version ) ,
quiet : C . int ( ro . Quiet ) ,
inmemory : C . int ( ro . InMemory ) ,
2016-10-31 18:57:23 -05:00
rewrite_notes_ref : mapEmptyStringToNull ( ro . RewriteNotesRef ) ,
2016-09-13 01:03:16 -05:00
merge_options : * ro . MergeOptions . toC ( ) ,
checkout_options : * ro . CheckoutOptions . toC ( ) ,
}
}
2016-08-06 23:40:59 -05:00
2016-10-31 18:57:23 -05:00
func mapEmptyStringToNull ( ref string ) * C . char {
2016-09-13 23:42:58 -05:00
if ref == "" {
return nil
}
return C . CString ( ref )
}
2016-10-31 18:57:23 -05:00
// Rebase is the struct representing a Rebase object.
2016-08-06 23:40:59 -05:00
type Rebase struct {
ptr * C . git_rebase
2017-07-08 09:07:51 -05:00
r * Repository
2016-08-06 23:40:59 -05:00
}
2016-10-31 18:57:23 -05:00
// InitRebase initializes a rebase operation to rebase the changes in branch relative to upstream onto another branch.
func ( r * Repository ) InitRebase ( branch * AnnotatedCommit , upstream * AnnotatedCommit , onto * AnnotatedCommit , opts * RebaseOptions ) ( * Rebase , error ) {
2016-08-06 23:40:59 -05:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
if branch == nil {
branch = & AnnotatedCommit { ptr : nil }
}
if upstream == nil {
upstream = & AnnotatedCommit { ptr : nil }
}
if onto == nil {
onto = & AnnotatedCommit { ptr : nil }
}
var ptr * C . git_rebase
2016-09-13 01:03:16 -05:00
err := C . git_rebase_init ( & ptr , r . ptr , branch . ptr , upstream . ptr , onto . ptr , opts . toC ( ) )
2017-07-08 09:07:51 -05:00
runtime . KeepAlive ( branch )
runtime . KeepAlive ( upstream )
runtime . KeepAlive ( onto )
2016-08-06 23:40:59 -05:00
if err < 0 {
return nil , MakeGitError ( err )
}
return newRebaseFromC ( ptr ) , nil
}
2016-10-31 18:57:23 -05:00
// OpenRebase opens an existing rebase that was previously started by either an invocation of InitRebase or by another client.
func ( r * Repository ) OpenRebase ( opts * RebaseOptions ) ( * Rebase , error ) {
2016-09-05 23:15:10 -05:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
var ptr * C . git_rebase
2016-09-13 01:03:16 -05:00
err := C . git_rebase_open ( & ptr , r . ptr , opts . toC ( ) )
2017-07-08 09:07:51 -05:00
runtime . KeepAlive ( r )
2016-09-05 23:15:10 -05:00
if err < 0 {
return nil , MakeGitError ( err )
}
return newRebaseFromC ( ptr ) , nil
}
2016-08-07 02:31:42 -05:00
// OperationAt gets the rebase operation specified by the given index.
func ( rebase * Rebase ) OperationAt ( index uint ) * RebaseOperation {
operation := C . git_rebase_operation_byindex ( rebase . ptr , C . size_t ( index ) )
2017-07-08 09:07:51 -05:00
2016-08-07 02:31:42 -05:00
return newRebaseOperationFromC ( operation )
}
2017-07-08 13:58:08 -05:00
// CurrentOperationIndex gets the index of the rebase operation that is
// currently being applied. There is also an error returned for API
// compatibility.
2016-10-31 18:57:23 -05:00
func ( rebase * Rebase ) CurrentOperationIndex ( ) ( uint , error ) {
2016-11-23 00:10:59 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2017-07-08 13:58:08 -05:00
var err error
operationIndex := uint ( C . git_rebase_operation_current ( rebase . ptr ) )
runtime . KeepAlive ( rebase )
if operationIndex == RebaseNoOperation {
err = ErrRebaseNoOperation
2016-10-31 18:57:23 -05:00
}
2016-11-23 00:10:59 -06:00
2017-07-08 13:58:08 -05:00
return uint ( operationIndex ) , err
2016-08-07 02:31:42 -05:00
}
// OperationCount gets the count of rebase operations that are to be applied.
func ( rebase * Rebase ) OperationCount ( ) uint {
2017-07-08 09:07:51 -05:00
ret := uint ( C . git_rebase_operation_entrycount ( rebase . ptr ) )
runtime . KeepAlive ( rebase )
return ret
2016-08-07 02:31:42 -05:00
}
2016-08-06 23:40:59 -05:00
// Next performs the next rebase operation and returns the information about it.
2016-10-31 18:57:23 -05:00
// If the operation is one that applies a patch (which is any operation except RebaseOperationExec)
2016-08-06 23:40:59 -05:00
// then the patch will be applied and the index and working directory will be updated with the changes.
// If there are conflicts, you will need to address those before committing the changes.
func ( rebase * Rebase ) Next ( ) ( * RebaseOperation , error ) {
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
var ptr * C . git_rebase_operation
err := C . git_rebase_next ( & ptr , rebase . ptr )
2017-07-08 09:07:51 -05:00
runtime . KeepAlive ( rebase )
2016-08-06 23:40:59 -05:00
if err < 0 {
return nil , MakeGitError ( err )
}
2016-08-07 02:31:42 -05:00
return newRebaseOperationFromC ( ptr ) , nil
2016-08-06 23:40:59 -05:00
}
// Commit commits the current patch.
2016-10-31 18:57:23 -05:00
// You must have resolved any conflicts that were introduced during the patch application from the Next() invocation.
2016-08-06 23:40:59 -05:00
func ( rebase * Rebase ) Commit ( ID * Oid , author , committer * Signature , message string ) error {
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
authorSig , err := author . toC ( )
if err != nil {
return err
}
defer C . git_signature_free ( authorSig )
committerSig , err := committer . toC ( )
if err != nil {
return err
}
2016-10-31 18:57:23 -05:00
defer C . git_signature_free ( committerSig )
2016-08-06 23:40:59 -05:00
cmsg := C . CString ( message )
defer C . free ( unsafe . Pointer ( cmsg ) )
cerr := C . git_rebase_commit ( ID . toC ( ) , rebase . ptr , authorSig , committerSig , nil , cmsg )
2017-07-08 09:07:51 -05:00
runtime . KeepAlive ( ID )
runtime . KeepAlive ( rebase )
2016-08-06 23:40:59 -05:00
if cerr < 0 {
return MakeGitError ( cerr )
}
return nil
}
// Finish finishes a rebase that is currently in progress once all patches have been applied.
func ( rebase * Rebase ) Finish ( ) error {
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
err := C . git_rebase_finish ( rebase . ptr , nil )
2017-07-08 09:07:51 -05:00
runtime . KeepAlive ( rebase )
2016-08-06 23:40:59 -05:00
if err < 0 {
return MakeGitError ( err )
}
return nil
}
2016-08-07 02:31:42 -05:00
// Abort aborts a rebase that is currently in progress, resetting the repository and working directory to their state before rebase began.
func ( rebase * Rebase ) Abort ( ) error {
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
err := C . git_rebase_abort ( rebase . ptr )
2017-07-08 09:07:51 -05:00
runtime . KeepAlive ( rebase )
2016-08-07 02:31:42 -05:00
if err < 0 {
return MakeGitError ( err )
}
return nil
2016-08-07 01:33:06 -05:00
}
2016-10-31 18:57:23 -05:00
// Free frees the Rebase object.
2016-08-06 23:40:59 -05:00
func ( rebase * Rebase ) Free ( ) {
runtime . SetFinalizer ( rebase , nil )
2016-08-07 19:49:40 -05:00
C . git_rebase_free ( rebase . ptr )
2016-08-06 23:40:59 -05:00
}
func newRebaseFromC ( ptr * C . git_rebase ) * Rebase {
rebase := & Rebase { ptr : ptr }
runtime . SetFinalizer ( rebase , ( * Rebase ) . Free )
return rebase
}