diff --git a/diff.go b/diff.go new file mode 100644 index 0000000..d9570c9 --- /dev/null +++ b/diff.go @@ -0,0 +1,229 @@ +package git + +/* +#include + +extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload); +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type DiffFile struct { + file C.git_diff_file +} + +func (df *DiffFile) Oid() *Oid { + return newOidFromC(&df.file.oid) +} + +func (df *DiffFile) Path() string { + return C.GoString(df.file.path) +} + +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 +} + +func (dd *DiffDelta) Status() int { + return int(dd.delta.status) +} + +func (dd *DiffDelta) Flags() uint32 { + return uint32(dd.delta.flags) +} + +func (dd *DiffDelta) Similarity() uint16 { + return uint16(dd.delta.similarity) +} + +func (dd *DiffDelta) OldFile() *DiffFile { + return &DiffFile{dd.delta.old_file} +} + +func (dd *DiffDelta) NewFile() *DiffFile { + return &DiffFile{dd.delta.new_file} +} + +type DiffHunk struct { + hunk C.git_diff_hunk + DiffDelta +} + +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) +} + +func (dh *DiffHunk) Header() string { + return C.GoStringN(&dh.hunk.header[0], C.int(dh.hunk.header_len)) +} + +type DiffLine struct { + line C.git_diff_line + DiffHunk +} + +func (dl *DiffLine) Origin() byte { + return byte(dl.line.origin) +} + +func (dl *DiffLine) OldLineno() int { + return int(dl.line.old_lineno) +} + +func (dl *DiffLine) NewLineno() int { + return int(dl.line.new_lineno) +} + +func (dl *DiffLine) NumLines() int { + return int(dl.line.num_lines) +} + +func (dl *DiffLine) Content() string { + return C.GoStringN(dl.line.content, C.int(dl.line.content_len)) +} + +func (dl *DiffLine) ContentOffset() int { + return int(dl.line.content_offset) +} + +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 <-&DiffDelta{*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 <-&DiffHunk{*hunk, DiffDelta{*delta}}: + 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 <-&DiffLine{*line, DiffHunk{*hunk, DiffDelta{*delta}}}: + 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 &DiffDelta{*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) +} diff --git a/patch.go b/patch.go new file mode 100644 index 0000000..561786e --- /dev/null +++ b/patch.go @@ -0,0 +1,37 @@ +package git + +/* +#include +*/ +import "C" +import ( + "runtime" +) + +type Patch struct { + ptr *C.git_patch +} + +func newPatch(ptr *C.git_patch) *Patch { + if ptr == nil { + return nil + } + + patch := &Patch{ + ptr: ptr, + } + + runtime.SetFinalizer(patch, (*Patch).Free) + return patch +} + +func (patch *Patch) Free() { + runtime.SetFinalizer(patch, nil) + C.git_patch_free(patch.ptr) +} + +func (patch *Patch) String() string { + var cptr *C.char + C.git_patch_to_str(&cptr, patch.ptr) + return C.GoString(cptr) +} diff --git a/repository.go b/repository.go index 3a9068d..58d3487 100644 --- a/repository.go +++ b/repository.go @@ -146,6 +146,20 @@ func (v *Repository) LookupReference(name string) (*Reference, error) { return newReferenceFromC(ptr), nil } +func (v *Repository) Head() (*Reference, error) { + var ptr *C.git_reference + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_repository_head(&ptr, v.ptr) + if ecode < 0 { + return nil, LastError() + } + + return newReferenceFromC(ptr), nil +} + func (v *Repository) CreateReference(name string, oid *Oid, force bool) (*Reference, error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -241,6 +255,23 @@ func (v *Repository) CreateCommit( return oid, nil } +func (v *Repository) DiffTreeToTree(oldTree, newTree *Tree) *Diff { + var diffPtr *C.git_diff + var oldPtr, newPtr *C.git_tree + + if oldTree != nil { + oldPtr = oldTree.gitObject.ptr + } + + if newTree != nil { + newPtr = newTree.gitObject.ptr + } + + C.git_diff_tree_to_tree(&diffPtr, v.ptr, oldPtr, newPtr, nil) + + return newDiff(diffPtr) +} + func (v *Odb) Free() { runtime.SetFinalizer(v, nil) C.git_odb_free(v.ptr) diff --git a/wrapper.c b/wrapper.c index 2af3974..93331ad 100644 --- a/wrapper.c +++ b/wrapper.c @@ -24,4 +24,25 @@ int _go_git_odb_foreach(git_odb *db, void *payload) { return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload); } + +int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload) +{ + git_diff_file_cb fcb = NULL; + git_diff_hunk_cb hcb = NULL; + git_diff_line_cb lcb = NULL; + + if (eachFile) { + fcb = (git_diff_file_cb)&diffForEachFileCb; + } + + if (eachHunk) { + hcb = (git_diff_hunk_cb)&diffForEachHunkCb; + } + + if (eachLine) { + lcb = (git_diff_line_cb)&diffForEachLineCb; + } + + return git_diff_foreach(diff, fcb, hcb, lcb, payload); +} /* EOF */