2014-02-20 00:25:30 -06:00
package git
/ *
# include < git2 . h >
2020-08-18 08:14:02 -05:00
extern void _go_git_populate_apply_cb ( git_apply_options * options ) ;
2014-02-20 00:25:30 -06:00
extern int _go_git_diff_foreach ( git_diff * diff , int eachFile , int eachHunk , int eachLine , void * payload ) ;
2014-03-22 00:16:26 -05:00
extern void _go_git_setup_diff_notify_callbacks ( git_diff_options * opts ) ;
2015-06-12 12:10:00 -05:00
extern int _go_git_diff_blobs ( git_blob * old , const char * old_path , git_blob * new , const char * new_path , git_diff_options * opts , int eachFile , int eachHunk , int eachLine , void * payload ) ;
2014-02-20 00:25:30 -06:00
* /
import "C"
import (
2014-03-22 00:16:26 -05:00
"errors"
2014-02-20 00:25:30 -06:00
"runtime"
"unsafe"
)
2020-02-23 17:24:27 -06:00
type DiffFlag uint32
2014-03-20 23:56:41 -05:00
2014-02-26 05:58:45 -06:00
const (
2014-03-20 23:56:41 -05:00
DiffFlagBinary DiffFlag = C . GIT_DIFF_FLAG_BINARY
2014-10-27 09:12:18 -05:00
DiffFlagNotBinary DiffFlag = C . GIT_DIFF_FLAG_NOT_BINARY
DiffFlagValidOid DiffFlag = C . GIT_DIFF_FLAG_VALID_ID
2016-03-29 13:41:46 -05:00
DiffFlagExists DiffFlag = C . GIT_DIFF_FLAG_EXISTS
2014-02-26 05:58:45 -06:00
)
2014-02-26 04:34:38 -06:00
2014-02-26 05:58:45 -06:00
type Delta int
2014-03-20 23:56:41 -05:00
2014-02-23 18:04:55 -06:00
const (
2014-03-20 23:56:41 -05:00
DeltaUnmodified Delta = C . GIT_DELTA_UNMODIFIED
2014-10-27 09:12:18 -05:00
DeltaAdded Delta = C . GIT_DELTA_ADDED
DeltaDeleted Delta = C . GIT_DELTA_DELETED
DeltaModified Delta = C . GIT_DELTA_MODIFIED
DeltaRenamed Delta = C . GIT_DELTA_RENAMED
DeltaCopied Delta = C . GIT_DELTA_COPIED
DeltaIgnored Delta = C . GIT_DELTA_IGNORED
DeltaUntracked Delta = C . GIT_DELTA_UNTRACKED
DeltaTypeChange Delta = C . GIT_DELTA_TYPECHANGE
2016-03-29 13:41:46 -05:00
DeltaUnreadable Delta = C . GIT_DELTA_UNREADABLE
2016-03-29 13:37:22 -05:00
DeltaConflicted Delta = C . GIT_DELTA_CONFLICTED
2014-02-26 05:58:45 -06:00
)
2014-02-23 18:04:55 -06:00
2019-08-27 12:02:12 -05:00
//go:generate stringer -type Delta -trimprefix Delta -tags static
2014-02-26 05:58:45 -06:00
type DiffLineType int
2014-03-20 23:56:41 -05:00
2014-02-26 05:58:45 -06:00
const (
2014-03-20 23:56:41 -05:00
DiffLineContext DiffLineType = C . GIT_DIFF_LINE_CONTEXT
2014-10-27 09:12:18 -05:00
DiffLineAddition DiffLineType = C . GIT_DIFF_LINE_ADDITION
DiffLineDeletion DiffLineType = C . GIT_DIFF_LINE_DELETION
DiffLineContextEOFNL DiffLineType = C . GIT_DIFF_LINE_CONTEXT_EOFNL
DiffLineAddEOFNL DiffLineType = C . GIT_DIFF_LINE_ADD_EOFNL
DiffLineDelEOFNL DiffLineType = C . GIT_DIFF_LINE_DEL_EOFNL
DiffLineFileHdr DiffLineType = C . GIT_DIFF_LINE_FILE_HDR
DiffLineHunkHdr DiffLineType = C . GIT_DIFF_LINE_HUNK_HDR
DiffLineBinary DiffLineType = C . GIT_DIFF_LINE_BINARY
2014-02-23 18:04:55 -06:00
)
2019-08-27 12:02:12 -05:00
//go:generate stringer -type DiffLineType -trimprefix DiffLine -tags static
2014-02-20 00:25:30 -06:00
type DiffFile struct {
2014-03-20 23:56:41 -05:00
Path string
Oid * Oid
Size int
2014-02-26 16:01:32 -06:00
Flags DiffFlag
2014-03-20 23:56:41 -05:00
Mode uint16
2014-02-20 00:25:30 -06:00
}
2014-03-22 00:16:26 -05:00
func diffFileFromC ( file * C . git_diff_file ) DiffFile {
return DiffFile {
2014-03-20 23:56:41 -05:00
Path : C . GoString ( file . path ) ,
2014-03-21 00:54:18 -05:00
Oid : newOidFromC ( & file . id ) ,
2014-03-20 23:56:41 -05:00
Size : int ( file . size ) ,
2014-02-26 16:01:32 -06:00
Flags : DiffFlag ( file . flags ) ,
2014-03-20 23:56:41 -05:00
Mode : uint16 ( file . mode ) ,
2014-02-23 18:49:04 -06:00
}
2014-02-20 00:25:30 -06:00
}
type DiffDelta struct {
2014-03-20 23:56:41 -05:00
Status Delta
Flags DiffFlag
2014-02-26 16:01:32 -06:00
Similarity uint16
2014-03-22 00:16:26 -05:00
OldFile DiffFile
NewFile DiffFile
2014-02-23 18:49:04 -06:00
}
2014-03-22 00:16:26 -05:00
func diffDeltaFromC ( delta * C . git_diff_delta ) DiffDelta {
return DiffDelta {
2014-03-20 23:56:41 -05:00
Status : Delta ( delta . status ) ,
Flags : DiffFlag ( delta . flags ) ,
2014-02-26 16:01:32 -06:00
Similarity : uint16 ( delta . similarity ) ,
2014-03-22 00:16:26 -05:00
OldFile : diffFileFromC ( & delta . old_file ) ,
NewFile : diffFileFromC ( & delta . new_file ) ,
2014-02-23 18:49:04 -06:00
}
2014-02-20 00:25:30 -06:00
}
type DiffHunk struct {
2014-02-26 16:01:32 -06:00
OldStart int
OldLines int
NewStart int
NewLines int
2014-03-20 23:56:41 -05:00
Header string
2014-02-20 00:25:30 -06:00
}
2015-06-12 10:45:11 -05:00
func diffHunkFromC ( hunk * C . git_diff_hunk ) DiffHunk {
2014-03-22 00:16:26 -05:00
return DiffHunk {
OldStart : int ( hunk . old_start ) ,
OldLines : int ( hunk . old_lines ) ,
NewStart : int ( hunk . new_start ) ,
NewLines : int ( hunk . new_lines ) ,
Header : C . GoStringN ( & hunk . header [ 0 ] , C . int ( hunk . header_len ) ) ,
2014-02-23 18:49:04 -06:00
}
}
2014-02-20 00:25:30 -06:00
type DiffLine struct {
2014-03-20 23:56:41 -05:00
Origin DiffLineType
2014-02-26 04:34:38 -06:00
OldLineno int
NewLineno int
2014-03-20 23:56:41 -05:00
NumLines int
Content string
2014-02-20 00:25:30 -06:00
}
2015-06-12 10:45:11 -05:00
func diffLineFromC ( line * C . git_diff_line ) DiffLine {
2014-03-22 00:16:26 -05:00
return DiffLine {
2014-03-20 23:56:41 -05:00
Origin : DiffLineType ( line . origin ) ,
2014-02-26 04:34:38 -06:00
OldLineno : int ( line . old_lineno ) ,
NewLineno : int ( line . new_lineno ) ,
2014-03-20 23:56:41 -05:00
NumLines : int ( line . num_lines ) ,
Content : C . GoStringN ( line . content , C . int ( line . content_len ) ) ,
2014-02-23 18:49:04 -06:00
}
}
2014-02-20 00:25:30 -06:00
type Diff struct {
2020-06-21 08:45:39 -05:00
ptr * C . git_diff
repo * Repository
runFinalizer bool
2014-02-20 00:25:30 -06:00
}
2014-03-22 00:16:26 -05:00
func ( diff * Diff ) NumDeltas ( ) ( int , error ) {
if diff . ptr == nil {
return - 1 , ErrInvalid
}
2017-07-08 04:38:19 -05:00
ret := int ( C . git_diff_num_deltas ( diff . ptr ) )
runtime . KeepAlive ( diff )
return ret , nil
2014-03-22 00:16:26 -05:00
}
2020-05-09 22:32:17 -05:00
func ( diff * Diff ) Delta ( index int ) ( DiffDelta , error ) {
2014-03-22 00:16:26 -05:00
if diff . ptr == nil {
return DiffDelta { } , ErrInvalid
}
ptr := C . git_diff_get_delta ( diff . ptr , C . size_t ( index ) )
2017-07-08 04:38:19 -05:00
ret := diffDeltaFromC ( ptr )
runtime . KeepAlive ( diff )
return ret , nil
2014-03-22 00:16:26 -05:00
}
2020-05-09 22:32:17 -05:00
// deprecated: You should use `Diff.Delta()` instead.
func ( diff * Diff ) GetDelta ( index int ) ( DiffDelta , error ) {
return diff . Delta ( index )
}
2017-07-08 04:38:19 -05:00
func newDiffFromC ( ptr * C . git_diff , repo * Repository ) * Diff {
2014-02-20 00:25:30 -06:00
if ptr == nil {
return nil
}
diff := & Diff {
2020-06-21 08:45:39 -05:00
ptr : ptr ,
repo : repo ,
runFinalizer : true ,
2014-02-20 00:25:30 -06:00
}
runtime . SetFinalizer ( diff , ( * Diff ) . Free )
return diff
}
2014-03-20 23:56:41 -05:00
func ( diff * Diff ) Free ( ) error {
2014-03-21 00:54:18 -05:00
if diff . ptr == nil {
2014-03-20 23:56:41 -05:00
return ErrInvalid
}
2020-06-21 08:45:39 -05:00
if ! diff . runFinalizer {
// This is the case with the Diff objects that are involved in the DiffNotifyCallback.
diff . ptr = nil
return nil
}
2014-02-20 00:25:30 -06:00
runtime . SetFinalizer ( diff , nil )
C . git_diff_free ( diff . ptr )
2014-03-21 01:19:22 -05:00
diff . ptr = nil
2014-03-20 23:56:41 -05:00
return nil
2014-02-20 00:25:30 -06:00
}
2014-11-26 10:22:15 -06:00
func ( diff * Diff ) FindSimilar ( opts * DiffFindOptions ) error {
var copts * C . git_diff_find_options
if opts != nil {
copts = & C . git_diff_find_options {
version : C . GIT_DIFF_FIND_OPTIONS_VERSION ,
flags : C . uint32_t ( opts . Flags ) ,
rename_threshold : C . uint16_t ( opts . RenameThreshold ) ,
copy_threshold : C . uint16_t ( opts . CopyThreshold ) ,
rename_from_rewrite_threshold : C . uint16_t ( opts . RenameFromRewriteThreshold ) ,
break_rewrite_threshold : C . uint16_t ( opts . BreakRewriteThreshold ) ,
rename_limit : C . size_t ( opts . RenameLimit ) ,
}
}
2014-12-05 19:58:28 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2014-11-26 10:22:15 -06:00
ecode := C . git_diff_find_similar ( diff . ptr , copts )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( diff )
2014-11-26 10:22:15 -06:00
if ecode < 0 {
return MakeGitError ( ecode )
}
return nil
}
2014-12-28 16:07:33 -06:00
type DiffStats struct {
ptr * C . git_diff_stats
}
func ( stats * DiffStats ) Free ( ) error {
if stats . ptr == nil {
return ErrInvalid
}
runtime . SetFinalizer ( stats , nil )
C . git_diff_stats_free ( stats . ptr )
stats . ptr = nil
return nil
}
func ( stats * DiffStats ) Insertions ( ) int {
2017-07-08 04:38:19 -05:00
ret := int ( C . git_diff_stats_insertions ( stats . ptr ) )
runtime . KeepAlive ( stats )
return ret
2014-12-28 16:07:33 -06:00
}
func ( stats * DiffStats ) Deletions ( ) int {
2017-07-08 04:38:19 -05:00
ret := int ( C . git_diff_stats_deletions ( stats . ptr ) )
runtime . KeepAlive ( stats )
return ret
2014-12-28 16:07:33 -06:00
}
func ( stats * DiffStats ) FilesChanged ( ) int {
2017-07-08 04:38:19 -05:00
ret := int ( C . git_diff_stats_files_changed ( stats . ptr ) )
runtime . KeepAlive ( stats )
return ret
2014-12-28 16:07:33 -06:00
}
2016-04-07 23:51:00 -05:00
type DiffStatsFormat int
const (
DiffStatsNone DiffStatsFormat = C . GIT_DIFF_STATS_NONE
DiffStatsFull DiffStatsFormat = C . GIT_DIFF_STATS_FULL
DiffStatsShort DiffStatsFormat = C . GIT_DIFF_STATS_SHORT
DiffStatsNumber DiffStatsFormat = C . GIT_DIFF_STATS_NUMBER
DiffStatsIncludeSummary DiffStatsFormat = C . GIT_DIFF_STATS_INCLUDE_SUMMARY
)
func ( stats * DiffStats ) String ( format DiffStatsFormat ,
width uint ) ( string , error ) {
buf := C . git_buf { }
2018-08-08 04:51:51 -05:00
defer C . git_buf_dispose ( & buf )
2016-04-07 23:51:00 -05:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ret := C . git_diff_stats_to_buf ( & buf ,
stats . ptr , C . git_diff_stats_format_t ( format ) , C . size_t ( width ) )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( stats )
2016-04-07 23:51:00 -05:00
if ret < 0 {
return "" , MakeGitError ( ret )
}
return C . GoString ( buf . ptr ) , nil
}
2014-12-28 16:07:33 -06:00
func ( diff * Diff ) Stats ( ) ( * DiffStats , error ) {
stats := new ( DiffStats )
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2017-07-08 04:38:19 -05:00
ecode := C . git_diff_get_stats ( & stats . ptr , diff . ptr )
runtime . KeepAlive ( diff )
if ecode < 0 {
2014-12-28 16:07:33 -06:00
return nil , MakeGitError ( ecode )
}
runtime . SetFinalizer ( stats , ( * DiffStats ) . Free )
return stats , nil
}
2014-03-21 19:20:48 -05:00
type diffForEachData struct {
FileCallback DiffForEachFileCallback
HunkCallback DiffForEachHunkCallback
LineCallback DiffForEachLineCallback
Error error
2014-02-20 00:25:30 -06:00
}
2019-08-27 12:23:37 -05:00
type DiffForEachFileCallback func ( delta DiffDelta , progress float64 ) ( DiffForEachHunkCallback , error )
2014-03-22 00:16:26 -05:00
type DiffDetail int
2014-03-21 19:20:48 -05:00
2014-03-22 00:16:26 -05:00
const (
DiffDetailFiles DiffDetail = iota
DiffDetailHunks
DiffDetailLines
)
func ( diff * Diff ) ForEach ( cbFile DiffForEachFileCallback , detail DiffDetail ) error {
2014-03-21 00:54:18 -05:00
if diff . ptr == nil {
2014-03-20 23:56:41 -05:00
return ErrInvalid
}
2014-03-21 19:20:48 -05:00
intHunks := C . int ( 0 )
2014-03-22 00:16:26 -05:00
if detail >= DiffDetailHunks {
2014-03-21 19:20:48 -05:00
intHunks = C . int ( 1 )
}
intLines := C . int ( 0 )
2014-03-22 00:16:26 -05:00
if detail >= DiffDetailLines {
2014-03-21 19:20:48 -05:00
intLines = C . int ( 1 )
}
data := & diffForEachData {
FileCallback : cbFile ,
2014-03-20 23:56:41 -05:00
}
2015-04-24 03:10:09 -05:00
handle := pointerHandles . Track ( data )
defer pointerHandles . Untrack ( handle )
ecode := C . _go_git_diff_foreach ( diff . ptr , 1 , intHunks , intLines , handle )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( diff )
2014-03-20 23:56:41 -05:00
if ecode < 0 {
return data . Error
}
return nil
2014-02-20 00:25:30 -06:00
}
//export diffForEachFileCb
2015-04-24 03:10:09 -05:00
func diffForEachFileCb ( delta * C . git_diff_delta , progress C . float , handle unsafe . Pointer ) int {
payload := pointerHandles . Get ( handle )
data , ok := payload . ( * diffForEachData )
if ! ok {
panic ( "could not retrieve data for handle" )
}
2014-03-21 19:20:48 -05:00
data . HunkCallback = nil
if data . FileCallback != nil {
2014-03-22 00:16:26 -05:00
cb , err := data . FileCallback ( diffDeltaFromC ( delta ) , float64 ( progress ) )
2014-03-21 19:20:48 -05:00
if err != nil {
data . Error = err
return - 1
}
data . HunkCallback = cb
2014-02-20 00:25:30 -06:00
}
return 0
}
2014-03-22 00:16:26 -05:00
type DiffForEachHunkCallback func ( DiffHunk ) ( DiffForEachLineCallback , error )
2014-02-20 00:25:30 -06:00
//export diffForEachHunkCb
2015-04-24 03:10:09 -05:00
func diffForEachHunkCb ( delta * C . git_diff_delta , hunk * C . git_diff_hunk , handle unsafe . Pointer ) int {
payload := pointerHandles . Get ( handle )
data , ok := payload . ( * diffForEachData )
if ! ok {
panic ( "could not retrieve data for handle" )
}
2014-03-21 19:20:48 -05:00
data . LineCallback = nil
if data . HunkCallback != nil {
2015-06-12 10:45:11 -05:00
cb , err := data . HunkCallback ( diffHunkFromC ( hunk ) )
2014-03-21 19:20:48 -05:00
if err != nil {
data . Error = err
return - 1
}
data . LineCallback = cb
2014-02-20 00:25:30 -06:00
}
return 0
}
2014-03-22 00:16:26 -05:00
type DiffForEachLineCallback func ( DiffLine ) error
2014-02-20 00:25:30 -06:00
//export diffForEachLineCb
2015-04-24 03:10:09 -05:00
func diffForEachLineCb ( delta * C . git_diff_delta , hunk * C . git_diff_hunk , line * C . git_diff_line , handle unsafe . Pointer ) int {
payload := pointerHandles . Get ( handle )
data , ok := payload . ( * diffForEachData )
if ! ok {
panic ( "could not retrieve data for handle" )
}
2014-03-20 23:56:41 -05:00
2015-06-12 10:45:11 -05:00
err := data . LineCallback ( diffLineFromC ( line ) )
2014-03-20 23:56:41 -05:00
if err != nil {
data . Error = err
2014-02-20 00:25:30 -06:00
return - 1
}
return 0
}
2014-03-20 23:56:41 -05:00
func ( diff * Diff ) Patch ( deltaIndex int ) ( * Patch , error ) {
2014-03-21 00:54:18 -05:00
if diff . ptr == nil {
2014-03-20 23:56:41 -05:00
return nil , ErrInvalid
}
2014-02-20 00:25:30 -06:00
var patchPtr * C . git_patch
2014-12-05 19:44:57 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2014-03-20 23:56:41 -05:00
ecode := C . git_patch_from_diff ( & patchPtr , diff . ptr , C . size_t ( deltaIndex ) )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( diff )
2014-03-20 23:56:41 -05:00
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
return newPatchFromC ( patchPtr ) , nil
}
2019-05-29 09:55:37 -05:00
type DiffFormat int
const (
DiffFormatPatch DiffFormat = C . GIT_DIFF_FORMAT_PATCH
DiffFormatPatchHeader DiffFormat = C . GIT_DIFF_FORMAT_PATCH_HEADER
DiffFormatRaw DiffFormat = C . GIT_DIFF_FORMAT_RAW
DiffFormatNameOnly DiffFormat = C . GIT_DIFF_FORMAT_NAME_ONLY
DiffFormatNameStatus DiffFormat = C . GIT_DIFF_FORMAT_NAME_STATUS
)
func ( diff * Diff ) ToBuf ( format DiffFormat ) ( [ ] byte , error ) {
if diff . ptr == nil {
return nil , ErrInvalid
}
diffBuf := C . git_buf { }
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_diff_to_buf ( & diffBuf , diff . ptr , C . git_diff_format_t ( format ) )
runtime . KeepAlive ( diff )
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
defer C . git_buf_free ( & diffBuf )
return C . GoBytes ( unsafe . Pointer ( diffBuf . ptr ) , C . int ( diffBuf . size ) ) , nil
}
2014-03-22 00:16:26 -05:00
type DiffOptionsFlag int
const (
DiffNormal DiffOptionsFlag = C . GIT_DIFF_NORMAL
2014-10-27 09:12:18 -05:00
DiffReverse DiffOptionsFlag = C . GIT_DIFF_REVERSE
DiffIncludeIgnored DiffOptionsFlag = C . GIT_DIFF_INCLUDE_IGNORED
DiffRecurseIgnoredDirs DiffOptionsFlag = C . GIT_DIFF_RECURSE_IGNORED_DIRS
DiffIncludeUntracked DiffOptionsFlag = C . GIT_DIFF_INCLUDE_UNTRACKED
DiffRecurseUntracked DiffOptionsFlag = C . GIT_DIFF_RECURSE_UNTRACKED_DIRS
DiffIncludeUnmodified DiffOptionsFlag = C . GIT_DIFF_INCLUDE_UNMODIFIED
DiffIncludeTypeChange DiffOptionsFlag = C . GIT_DIFF_INCLUDE_TYPECHANGE
DiffIncludeTypeChangeTrees DiffOptionsFlag = C . GIT_DIFF_INCLUDE_TYPECHANGE_TREES
DiffIgnoreFilemode DiffOptionsFlag = C . GIT_DIFF_IGNORE_FILEMODE
DiffIgnoreSubmodules DiffOptionsFlag = C . GIT_DIFF_IGNORE_SUBMODULES
DiffIgnoreCase DiffOptionsFlag = C . GIT_DIFF_IGNORE_CASE
2016-03-29 13:41:46 -05:00
DiffIncludeCaseChange DiffOptionsFlag = C . GIT_DIFF_INCLUDE_CASECHANGE
2014-10-27 09:12:18 -05:00
DiffDisablePathspecMatch DiffOptionsFlag = C . GIT_DIFF_DISABLE_PATHSPEC_MATCH
DiffSkipBinaryCheck DiffOptionsFlag = C . GIT_DIFF_SKIP_BINARY_CHECK
DiffEnableFastUntrackedDirs DiffOptionsFlag = C . GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
DiffForceText DiffOptionsFlag = C . GIT_DIFF_FORCE_TEXT
DiffForceBinary DiffOptionsFlag = C . GIT_DIFF_FORCE_BINARY
DiffIgnoreWhitespace DiffOptionsFlag = C . GIT_DIFF_IGNORE_WHITESPACE
DiffIgnoreWhitespaceChange DiffOptionsFlag = C . GIT_DIFF_IGNORE_WHITESPACE_CHANGE
DiffIgnoreWitespaceEol DiffOptionsFlag = C . GIT_DIFF_IGNORE_WHITESPACE_EOL
DiffShowUntrackedContent DiffOptionsFlag = C . GIT_DIFF_SHOW_UNTRACKED_CONTENT
DiffShowUnmodified DiffOptionsFlag = C . GIT_DIFF_SHOW_UNMODIFIED
DiffPatience DiffOptionsFlag = C . GIT_DIFF_PATIENCE
DiffMinimal DiffOptionsFlag = C . GIT_DIFF_MINIMAL
2018-01-17 05:47:06 -06:00
DiffShowBinary DiffOptionsFlag = C . GIT_DIFF_SHOW_BINARY
DiffIndentHeuristic DiffOptionsFlag = C . GIT_DIFF_INDENT_HEURISTIC
2014-03-22 00:16:26 -05:00
)
type DiffNotifyCallback func ( diffSoFar * Diff , deltaToAdd DiffDelta , matchedPathspec string ) error
type DiffOptions struct {
Flags DiffOptionsFlag
IgnoreSubmodules SubmoduleIgnore
Pathspec [ ] string
NotifyCallback DiffNotifyCallback
2014-12-02 18:50:37 -06:00
ContextLines uint32
InterhunkLines uint32
2014-03-22 00:16:26 -05:00
IdAbbrev uint16
MaxSize int
OldPrefix string
NewPrefix string
}
func DefaultDiffOptions ( ) ( DiffOptions , error ) {
opts := C . git_diff_options { }
2014-12-05 19:44:57 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2014-03-22 00:16:26 -05:00
ecode := C . git_diff_init_options ( & opts , C . GIT_DIFF_OPTIONS_VERSION )
if ecode < 0 {
return DiffOptions { } , MakeGitError ( ecode )
}
return DiffOptions {
Flags : DiffOptionsFlag ( opts . flags ) ,
IgnoreSubmodules : SubmoduleIgnore ( opts . ignore_submodules ) ,
Pathspec : makeStringsFromCStrings ( opts . pathspec . strings , int ( opts . pathspec . count ) ) ,
2014-12-02 18:50:37 -06:00
ContextLines : uint32 ( opts . context_lines ) ,
InterhunkLines : uint32 ( opts . interhunk_lines ) ,
2014-03-22 00:16:26 -05:00
IdAbbrev : uint16 ( opts . id_abbrev ) ,
MaxSize : int ( opts . max_size ) ,
2014-12-30 04:03:20 -06:00
OldPrefix : "a" ,
NewPrefix : "b" ,
2014-03-22 00:16:26 -05:00
} , nil
}
2014-11-26 10:22:15 -06:00
type DiffFindOptionsFlag int
const (
DiffFindByConfig DiffFindOptionsFlag = C . GIT_DIFF_FIND_BY_CONFIG
DiffFindRenames DiffFindOptionsFlag = C . GIT_DIFF_FIND_RENAMES
DiffFindRenamesFromRewrites DiffFindOptionsFlag = C . GIT_DIFF_FIND_RENAMES_FROM_REWRITES
DiffFindCopies DiffFindOptionsFlag = C . GIT_DIFF_FIND_COPIES
DiffFindCopiesFromUnmodified DiffFindOptionsFlag = C . GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED
DiffFindRewrites DiffFindOptionsFlag = C . GIT_DIFF_FIND_REWRITES
DiffFindBreakRewrites DiffFindOptionsFlag = C . GIT_DIFF_BREAK_REWRITES
DiffFindAndBreakRewrites DiffFindOptionsFlag = C . GIT_DIFF_FIND_AND_BREAK_REWRITES
DiffFindForUntracked DiffFindOptionsFlag = C . GIT_DIFF_FIND_FOR_UNTRACKED
DiffFindAll DiffFindOptionsFlag = C . GIT_DIFF_FIND_ALL
DiffFindIgnoreLeadingWhitespace DiffFindOptionsFlag = C . GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE
DiffFindIgnoreWhitespace DiffFindOptionsFlag = C . GIT_DIFF_FIND_IGNORE_WHITESPACE
DiffFindDontIgnoreWhitespace DiffFindOptionsFlag = C . GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE
DiffFindExactMatchOnly DiffFindOptionsFlag = C . GIT_DIFF_FIND_EXACT_MATCH_ONLY
DiffFindBreakRewritesForRenamesOnly DiffFindOptionsFlag = C . GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY
DiffFindRemoveUnmodified DiffFindOptionsFlag = C . GIT_DIFF_FIND_REMOVE_UNMODIFIED
)
2020-08-18 08:14:02 -05:00
// TODO implement git_diff_similarity_metric
2014-11-26 10:22:15 -06:00
type DiffFindOptions struct {
Flags DiffFindOptionsFlag
RenameThreshold uint16
CopyThreshold uint16
RenameFromRewriteThreshold uint16
BreakRewriteThreshold uint16
RenameLimit uint
}
func DefaultDiffFindOptions ( ) ( DiffFindOptions , error ) {
opts := C . git_diff_find_options { }
2014-12-05 19:58:28 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2014-11-26 10:22:15 -06:00
ecode := C . git_diff_find_init_options ( & opts , C . GIT_DIFF_FIND_OPTIONS_VERSION )
if ecode < 0 {
return DiffFindOptions { } , MakeGitError ( ecode )
}
return DiffFindOptions {
Flags : DiffFindOptionsFlag ( opts . flags ) ,
RenameThreshold : uint16 ( opts . rename_threshold ) ,
CopyThreshold : uint16 ( opts . copy_threshold ) ,
RenameFromRewriteThreshold : uint16 ( opts . rename_from_rewrite_threshold ) ,
BreakRewriteThreshold : uint16 ( opts . break_rewrite_threshold ) ,
RenameLimit : uint ( opts . rename_limit ) ,
} , nil
}
2014-03-22 00:16:26 -05:00
var (
ErrDeltaSkip = errors . New ( "Skip delta" )
)
type diffNotifyData struct {
2020-06-21 08:45:39 -05:00
Callback DiffNotifyCallback
Repository * Repository
Error error
2014-03-22 00:16:26 -05:00
}
//export diffNotifyCb
2015-04-24 03:10:09 -05:00
func diffNotifyCb ( _diff_so_far unsafe . Pointer , delta_to_add * C . git_diff_delta , matched_pathspec * C . char , handle unsafe . Pointer ) int {
2014-03-22 00:16:26 -05:00
diff_so_far := ( * C . git_diff ) ( _diff_so_far )
2015-04-24 03:10:09 -05:00
payload := pointerHandles . Get ( handle )
data , ok := payload . ( * diffNotifyData )
if ! ok {
panic ( "could not retrieve data for handle" )
}
2014-03-22 00:16:26 -05:00
if data != nil {
2020-06-21 08:45:39 -05:00
// We are not taking ownership of this diff pointer, so no finalizer is set.
diff := & Diff {
ptr : diff_so_far ,
repo : data . Repository ,
runFinalizer : false ,
2014-03-22 00:16:26 -05:00
}
2020-06-21 08:45:39 -05:00
err := data . Callback ( diff , diffDeltaFromC ( delta_to_add ) , C . GoString ( matched_pathspec ) )
// Since the callback could theoretically keep a reference to the diff
// (which could be freed by libgit2 if an error occurs later during the
// diffing process), this converts a use-after-free (terrible!) into a nil
// dereference ("just" pretty bad).
diff . ptr = nil
2014-03-22 00:16:26 -05:00
if err == ErrDeltaSkip {
return 1
} else if err != nil {
data . Error = err
return - 1
} else {
return 0
}
}
return 0
}
2020-06-21 08:45:39 -05:00
func diffOptionsToC ( opts * DiffOptions , repo * Repository ) ( copts * C . git_diff_options ) {
2014-03-22 00:16:26 -05:00
cpathspec := C . git_strarray { }
if opts != nil {
2020-06-21 08:45:39 -05:00
notifyData := & diffNotifyData {
Callback : opts . NotifyCallback ,
Repository : repo ,
2014-03-22 00:16:26 -05:00
}
2015-04-24 03:10:09 -05:00
2014-03-22 00:16:26 -05:00
if opts . Pathspec != nil {
cpathspec . count = C . size_t ( len ( opts . Pathspec ) )
cpathspec . strings = makeCStringsFromStrings ( opts . Pathspec )
}
copts = & C . git_diff_options {
version : C . GIT_DIFF_OPTIONS_VERSION ,
flags : C . uint32_t ( opts . Flags ) ,
ignore_submodules : C . git_submodule_ignore_t ( opts . IgnoreSubmodules ) ,
pathspec : cpathspec ,
2014-12-02 18:50:37 -06:00
context_lines : C . uint32_t ( opts . ContextLines ) ,
interhunk_lines : C . uint32_t ( opts . InterhunkLines ) ,
2014-03-22 00:16:26 -05:00
id_abbrev : C . uint16_t ( opts . IdAbbrev ) ,
max_size : C . git_off_t ( opts . MaxSize ) ,
2014-12-30 04:03:20 -06:00
old_prefix : C . CString ( opts . OldPrefix ) ,
new_prefix : C . CString ( opts . NewPrefix ) ,
2014-03-22 00:16:26 -05:00
}
if opts . NotifyCallback != nil {
C . _go_git_setup_diff_notify_callbacks ( copts )
2016-02-16 10:22:43 -06:00
copts . payload = pointerHandles . Track ( notifyData )
2014-03-22 00:16:26 -05:00
}
}
2014-12-05 15:52:15 -06:00
return
}
func freeDiffOptions ( copts * C . git_diff_options ) {
if copts != nil {
cpathspec := copts . pathspec
freeStrarray ( & cpathspec )
2014-12-30 04:03:20 -06:00
C . free ( unsafe . Pointer ( copts . old_prefix ) )
C . free ( unsafe . Pointer ( copts . new_prefix ) )
2016-02-16 10:22:43 -06:00
if copts . payload != nil {
pointerHandles . Untrack ( copts . payload )
2015-05-22 03:01:50 -05:00
}
2014-12-05 15:52:15 -06:00
}
}
func ( v * Repository ) DiffTreeToTree ( oldTree , newTree * Tree , opts * DiffOptions ) ( * Diff , error ) {
var diffPtr * C . git_diff
var oldPtr , newPtr * C . git_tree
if oldTree != nil {
oldPtr = oldTree . cast_ptr
}
if newTree != nil {
newPtr = newTree . cast_ptr
}
2020-06-21 08:45:39 -05:00
copts := diffOptionsToC ( opts , v )
2014-12-05 15:52:15 -06:00
defer freeDiffOptions ( copts )
2014-03-22 00:16:26 -05:00
2014-12-05 19:44:57 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2014-03-22 00:16:26 -05:00
ecode := C . git_diff_tree_to_tree ( & diffPtr , v . ptr , oldPtr , newPtr , copts )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( oldTree )
runtime . KeepAlive ( newTree )
2014-03-21 00:54:18 -05:00
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
2017-07-08 04:38:19 -05:00
return newDiffFromC ( diffPtr , v ) , nil
2014-02-20 00:25:30 -06:00
}
2014-11-08 01:26:52 -06:00
func ( v * Repository ) DiffTreeToWorkdir ( oldTree * Tree , opts * DiffOptions ) ( * Diff , error ) {
var diffPtr * C . git_diff
var oldPtr * C . git_tree
if oldTree != nil {
oldPtr = oldTree . cast_ptr
}
2020-06-21 08:45:39 -05:00
copts := diffOptionsToC ( opts , v )
2014-12-05 15:52:15 -06:00
defer freeDiffOptions ( copts )
2014-11-08 01:26:52 -06:00
2014-12-05 19:44:57 -06:00
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
2014-11-08 01:26:52 -06:00
ecode := C . git_diff_tree_to_workdir ( & diffPtr , v . ptr , oldPtr , copts )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( oldTree )
2014-11-08 01:26:52 -06:00
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
2017-07-08 04:38:19 -05:00
return newDiffFromC ( diffPtr , v ) , nil
2014-11-08 01:26:52 -06:00
}
2015-03-11 18:12:22 -05:00
2016-03-05 21:18:32 -06:00
func ( v * Repository ) DiffTreeToIndex ( oldTree * Tree , index * Index , opts * DiffOptions ) ( * Diff , error ) {
var diffPtr * C . git_diff
var oldPtr * C . git_tree
var indexPtr * C . git_index
if oldTree != nil {
oldPtr = oldTree . cast_ptr
}
if index != nil {
indexPtr = index . ptr
}
2020-06-21 08:45:39 -05:00
copts := diffOptionsToC ( opts , v )
2016-03-05 21:18:32 -06:00
defer freeDiffOptions ( copts )
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_diff_tree_to_index ( & diffPtr , v . ptr , oldPtr , indexPtr , copts )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( oldTree )
runtime . KeepAlive ( index )
2016-03-05 21:18:32 -06:00
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
2017-07-08 04:38:19 -05:00
return newDiffFromC ( diffPtr , v ) , nil
2016-03-05 21:18:32 -06:00
}
2015-03-11 18:12:22 -05:00
func ( v * Repository ) DiffTreeToWorkdirWithIndex ( oldTree * Tree , opts * DiffOptions ) ( * Diff , error ) {
var diffPtr * C . git_diff
var oldPtr * C . git_tree
if oldTree != nil {
oldPtr = oldTree . cast_ptr
}
2020-06-21 08:45:39 -05:00
copts := diffOptionsToC ( opts , v )
2015-03-11 18:12:22 -05:00
defer freeDiffOptions ( copts )
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_diff_tree_to_workdir_with_index ( & diffPtr , v . ptr , oldPtr , copts )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( oldTree )
2015-03-11 18:12:22 -05:00
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
2017-07-08 04:38:19 -05:00
return newDiffFromC ( diffPtr , v ) , nil
2015-03-11 18:12:22 -05:00
}
2015-03-11 18:12:39 -05:00
func ( v * Repository ) DiffIndexToWorkdir ( index * Index , opts * DiffOptions ) ( * Diff , error ) {
var diffPtr * C . git_diff
var indexPtr * C . git_index
if index != nil {
indexPtr = index . ptr
}
2020-06-21 08:45:39 -05:00
copts := diffOptionsToC ( opts , v )
2015-03-11 18:12:39 -05:00
defer freeDiffOptions ( copts )
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_diff_index_to_workdir ( & diffPtr , v . ptr , indexPtr , copts )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( index )
2015-03-11 18:12:39 -05:00
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
2017-07-08 04:38:19 -05:00
return newDiffFromC ( diffPtr , v ) , nil
2015-03-11 18:12:39 -05:00
}
2015-06-12 12:10:00 -05:00
// DiffBlobs performs a diff between two arbitrary blobs. You can pass
// whatever file names you'd like for them to appear as in the diff.
func DiffBlobs ( oldBlob * Blob , oldAsPath string , newBlob * Blob , newAsPath string , opts * DiffOptions , fileCallback DiffForEachFileCallback , detail DiffDetail ) error {
data := & diffForEachData {
FileCallback : fileCallback ,
}
intHunks := C . int ( 0 )
if detail >= DiffDetailHunks {
intHunks = C . int ( 1 )
}
intLines := C . int ( 0 )
if detail >= DiffDetailLines {
intLines = C . int ( 1 )
}
handle := pointerHandles . Track ( data )
defer pointerHandles . Untrack ( handle )
2020-06-21 08:45:39 -05:00
var repo * Repository
2015-06-12 12:10:00 -05:00
var oldBlobPtr , newBlobPtr * C . git_blob
if oldBlob != nil {
oldBlobPtr = oldBlob . cast_ptr
2020-06-21 08:45:39 -05:00
repo = oldBlob . repo
2015-06-12 12:10:00 -05:00
}
if newBlob != nil {
newBlobPtr = newBlob . cast_ptr
2020-06-21 08:45:39 -05:00
repo = newBlob . repo
2015-06-12 12:10:00 -05:00
}
oldBlobPath := C . CString ( oldAsPath )
defer C . free ( unsafe . Pointer ( oldBlobPath ) )
newBlobPath := C . CString ( newAsPath )
defer C . free ( unsafe . Pointer ( newBlobPath ) )
2020-06-21 08:45:39 -05:00
copts := diffOptionsToC ( opts , repo )
2015-06-12 12:10:00 -05:00
defer freeDiffOptions ( copts )
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . _go_git_diff_blobs ( oldBlobPtr , oldBlobPath , newBlobPtr , newBlobPath , copts , 1 , intHunks , intLines , handle )
2017-07-08 04:38:19 -05:00
runtime . KeepAlive ( oldBlob )
runtime . KeepAlive ( newBlob )
2015-06-12 12:10:00 -05:00
if ecode < 0 {
return MakeGitError ( ecode )
}
return nil
}
2020-08-18 08:14:02 -05:00
// ApplyHunkCallback is a callback that will be made per delta (file) when applying a patch.
type ApplyHunkCallback func ( * DiffHunk ) ( apply bool , err error )
// ApplyDeltaCallback is a callback that will be made per hunk when applying a patch.
type ApplyDeltaCallback func ( * DiffDelta ) ( apply bool , err error )
// ApplyOptions has 2 callbacks that are called for hunks or deltas
// If these functions return an error, abort the apply process immediately.
// If the first return value is true, the delta/hunk will be applied. If it is false, the delta/hunk will not be applied. In either case, the rest of the apply process will continue.
type ApplyOptions struct {
ApplyHunkCallback ApplyHunkCallback
ApplyDeltaCallback ApplyDeltaCallback
Flags uint
}
//export hunkApplyCallback
func hunkApplyCallback ( _hunk * C . git_diff_hunk , _payload unsafe . Pointer ) C . int {
opts , ok := pointerHandles . Get ( _payload ) . ( * ApplyOptions )
if ! ok {
panic ( "invalid apply options payload" )
}
if opts . ApplyHunkCallback == nil {
return 0
}
hunk := diffHunkFromC ( _hunk )
apply , err := opts . ApplyHunkCallback ( & hunk )
if err != nil {
if gitError , ok := err . ( * GitError ) ; ok {
return C . int ( gitError . Code )
}
return - 1
} else if apply {
return 0
} else {
return 1
}
}
//export deltaApplyCallback
func deltaApplyCallback ( _delta * C . git_diff_delta , _payload unsafe . Pointer ) C . int {
opts , ok := pointerHandles . Get ( _payload ) . ( * ApplyOptions )
if ! ok {
panic ( "invalid apply options payload" )
}
if opts . ApplyDeltaCallback == nil {
return 0
}
delta := diffDeltaFromC ( _delta )
apply , err := opts . ApplyDeltaCallback ( & delta )
if err != nil {
if gitError , ok := err . ( * GitError ) ; ok {
return C . int ( gitError . Code )
}
return - 1
} else if apply {
return 0
} else {
return 1
}
}
// DefaultApplyOptions returns default options for applying diffs or patches.
func DefaultApplyOptions ( ) ( * ApplyOptions , error ) {
opts := C . git_apply_options { }
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_apply_options_init ( & opts , C . GIT_APPLY_OPTIONS_VERSION )
if int ( ecode ) != 0 {
return nil , MakeGitError ( ecode )
}
return applyOptionsFromC ( & opts ) , nil
}
func ( a * ApplyOptions ) toC ( ) * C . git_apply_options {
if a == nil {
return nil
}
opts := & C . git_apply_options {
version : C . GIT_APPLY_OPTIONS_VERSION ,
flags : C . uint ( a . Flags ) ,
}
if a . ApplyDeltaCallback != nil || a . ApplyHunkCallback != nil {
C . _go_git_populate_apply_cb ( opts )
opts . payload = pointerHandles . Track ( a )
}
return opts
}
func applyOptionsFromC ( opts * C . git_apply_options ) * ApplyOptions {
return & ApplyOptions {
Flags : uint ( opts . flags ) ,
}
}
// ApplyLocation represents the possible application locations for applying
// diffs.
type ApplyLocation int
const (
// ApplyLocationWorkdir applies the patch to the workdir, leaving the
// index untouched. This is the equivalent of `git apply` with no location
// argument.
ApplyLocationWorkdir ApplyLocation = C . GIT_APPLY_LOCATION_WORKDIR
// ApplyLocationIndex applies the patch to the index, leaving the working
// directory untouched. This is the equivalent of `git apply --cached`.
ApplyLocationIndex ApplyLocation = C . GIT_APPLY_LOCATION_INDEX
// ApplyLocationBoth applies the patch to both the working directory and
// the index. This is the equivalent of `git apply --index`.
ApplyLocationBoth ApplyLocation = C . GIT_APPLY_LOCATION_BOTH
)
// ApplyDiff appllies a Diff to the given repository, making changes directly
// in the working directory, the index, or both.
func ( v * Repository ) ApplyDiff ( diff * Diff , location ApplyLocation , opts * ApplyOptions ) error {
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
cOpts := opts . toC ( )
ecode := C . git_apply ( v . ptr , diff . ptr , C . git_apply_location_t ( location ) , cOpts )
runtime . KeepAlive ( v )
runtime . KeepAlive ( diff )
runtime . KeepAlive ( cOpts )
if ecode < 0 {
return MakeGitError ( ecode )
}
return nil
}
// DiffFromBuffer reads the contents of a git patch file into a Diff object.
//
// The diff object produced is similar to the one that would be produced if you
// actually produced it computationally by comparing two trees, however there
// may be subtle differences. For example, a patch file likely contains
// abbreviated object IDs, so the object IDs in a git_diff_delta produced by
// this function will also be abbreviated.
//
// This function will only read patch files created by a git implementation, it
// will not read unified diffs produced by the diff program, nor any other
// types of patch files.
func DiffFromBuffer ( buffer [ ] byte , repo * Repository ) ( * Diff , error ) {
var diff * C . git_diff
cBuffer := C . CBytes ( buffer )
defer C . free ( unsafe . Pointer ( cBuffer ) )
runtime . LockOSThread ( )
defer runtime . UnlockOSThread ( )
ecode := C . git_diff_from_buffer ( & diff , ( * C . char ) ( cBuffer ) , C . size_t ( len ( buffer ) ) )
if ecode < 0 {
return nil , MakeGitError ( ecode )
}
runtime . KeepAlive ( diff )
return newDiffFromC ( diff , repo ) , nil
}