git2go/diff.go

266 lines
5.3 KiB
Go

package git
/*
#include <git2.h>
extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload);
*/
import "C"
import (
"runtime"
"unsafe"
)
type DiffFlag int
const (
DiffFlagBinary = C.GIT_DIFF_FLAG_BINARY
DiffFlagNotBinary = C.GIT_DIFF_FLAG_NOT_BINARY
DiffFlagValidOid = C.GIT_DIFF_FLAG_VALID_OID
)
type Delta int
const (
DeltaUnmodified = C.GIT_DELTA_UNMODIFIED
DeltaAdded = C.GIT_DELTA_ADDED
DeltaDeleted = C.GIT_DELTA_DELETED
DeltaModified = C.GIT_DELTA_MODIFIED
DeltaRenamed = C.GIT_DELTA_RENAMED
DeltaCopied = C.GIT_DELTA_COPIED
DeltaIgnored = C.GIT_DELTA_IGNORED
DeltaUntracked = C.GIT_DELTA_UNTRACKED
DeltaTypeChange = C.GIT_DELTA_TYPECHANGE
)
type DiffLineType int
const (
DiffLineContext = C.GIT_DIFF_LINE_CONTEXT
DiffLineAddition = C.GIT_DIFF_LINE_ADDITION
DiffLineDeletion = C.GIT_DIFF_LINE_DELETION
DiffLineContextEOFNL = C.GIT_DIFF_LINE_CONTEXT_EOFNL
DiffLineAddEOFNL = C.GIT_DIFF_LINE_ADD_EOFNL
DiffLineDelEOFNL = C.GIT_DIFF_LINE_DEL_EOFNL
DiffLineFileHdr = C.GIT_DIFF_LINE_FILE_HDR
DiffLineHunkHdr = C.GIT_DIFF_LINE_HUNK_HDR
DiffLineBinary = C.GIT_DIFF_LINE_BINARY
)
type DiffFile struct {
file C.git_diff_file
Path string
}
func newDiffFile(file *C.git_diff_file) *DiffFile {
return &DiffFile{
file: *file,
Path: C.GoString(file.path),
}
}
func (df *DiffFile) Oid() *Oid {
return newOidFromC(&df.file.oid)
}
func (df *DiffFile) Size() int {
return int(df.file.size)
}
func (df *DiffFile) Flags() uint32 {
return uint32(df.file.flags)
}
func (df *DiffFile) Mode() uint16 {
return uint16(df.file.mode)
}
type DiffDelta struct {
delta C.git_diff_delta
OldFile *DiffFile
NewFile *DiffFile
}
func newDiffDelta(delta *C.git_diff_delta) *DiffDelta {
return &DiffDelta{
delta: *delta,
OldFile: newDiffFile(&delta.old_file),
NewFile: newDiffFile(&delta.new_file),
}
}
func (dd *DiffDelta) Status() Delta {
return Delta(dd.delta.status)
}
func (dd *DiffDelta) Flags() DiffFlag {
return DiffFlag(dd.delta.flags)
}
func (dd *DiffDelta) Similarity() uint16 {
return uint16(dd.delta.similarity)
}
type DiffHunk struct {
hunk C.git_diff_hunk
Header string
DiffDelta
}
func newDiffHunk(delta *C.git_diff_delta, hunk *C.git_diff_hunk) *DiffHunk {
return &DiffHunk{
hunk: *hunk,
Header: C.GoStringN(&hunk.header[0], C.int(hunk.header_len)),
DiffDelta: *newDiffDelta(delta),
}
}
func (dh *DiffHunk) OldStart() int {
return int(dh.hunk.old_start)
}
func (dh *DiffHunk) OldLines() int {
return int(dh.hunk.old_lines)
}
func (dh *DiffHunk) NewStart() int {
return int(dh.hunk.new_start)
}
func (dh *DiffHunk) NewLines() int {
return int(dh.hunk.new_lines)
}
type DiffLine struct {
Origin DiffLineType
OldLineno int
NewLineno int
NumLines int
Content string
DiffHunk
}
func newDiffLine(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line) *DiffLine {
return &DiffLine{
Origin: DiffLineType(line.origin),
OldLineno: int(line.old_lineno),
NewLineno: int(line.new_lineno),
NumLines: int(line.num_lines),
Content: C.GoStringN(line.content, C.int(line.content_len)),
DiffHunk: *newDiffHunk(delta, hunk),
}
}
type Diff struct {
ptr *C.git_diff
}
func newDiff(ptr *C.git_diff) *Diff {
if ptr == nil {
return nil
}
diff := &Diff{
ptr: ptr,
}
runtime.SetFinalizer(diff, (*Diff).Free)
return diff
}
func (diff *Diff) Free() {
runtime.SetFinalizer(diff, nil)
C.git_diff_free(diff.ptr)
}
func (diff *Diff) forEachFileWrap(ch chan *DiffDelta) {
C._go_git_diff_foreach(diff.ptr, 1, 0, 0, unsafe.Pointer(&ch))
close(ch)
}
func (diff *Diff) ForEachFile() chan *DiffDelta {
ch := make(chan *DiffDelta, 0)
go diff.forEachFileWrap(ch)
return ch
}
//export diffForEachFileCb
func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, payload unsafe.Pointer) int {
ch := *(*chan *DiffDelta)(payload)
select {
case ch <-newDiffDelta(delta):
case <-ch:
return -1
}
return 0
}
func (diff *Diff) forEachHunkWrap(ch chan *DiffHunk) {
C._go_git_diff_foreach(diff.ptr, 0, 1, 0, unsafe.Pointer(&ch))
close(ch)
}
func (diff *Diff) ForEachHunk() chan *DiffHunk {
ch := make(chan *DiffHunk, 0)
go diff.forEachHunkWrap(ch)
return ch
}
//export diffForEachHunkCb
func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, payload unsafe.Pointer) int {
ch := *(*chan *DiffHunk)(payload)
select {
case ch <-newDiffHunk(delta, hunk):
case <-ch:
return -1
}
return 0
}
func (diff *Diff) forEachLineWrap(ch chan *DiffLine) {
C._go_git_diff_foreach(diff.ptr, 0, 0, 1, unsafe.Pointer(&ch))
close(ch)
}
func (diff *Diff) ForEachLine() chan *DiffLine {
ch := make(chan *DiffLine, 0)
go diff.forEachLineWrap(ch)
return ch
}
//export diffForEachLineCb
func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line, payload unsafe.Pointer) int {
ch := *(*chan *DiffLine)(payload)
select {
case ch <-newDiffLine(delta, hunk, line):
case <-ch:
return -1
}
return 0
}
func (diff *Diff) NumDeltas() int {
return int(C.git_diff_num_deltas(diff.ptr))
}
func (diff *Diff) GetDelta(index int) *DiffDelta {
ptr := C.git_diff_get_delta(diff.ptr, C.size_t(index))
if ptr == nil {
return nil
}
return newDiffDelta(ptr)
}
func (diff *Diff) Patch(deltaIndex int) *Patch {
var patchPtr *C.git_patch
C.git_patch_from_diff(&patchPtr, diff.ptr, C.size_t(deltaIndex))
return newPatch(patchPtr)
}