Integrated git_diff_find_similar #141

Merged
jochil merged 1 commits from git_diff_find_similar into master 2014-12-05 19:29:02 -06:00
2 changed files with 140 additions and 6 deletions

71
diff.go
View File

@ -164,6 +164,29 @@ func (diff *Diff) Free() error {
return nil
}
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),
}
}
ecode := C.git_diff_find_similar(diff.ptr, copts)
if ecode < 0 {
return MakeGitError(ecode)
}
return nil
}
type diffForEachData struct {
FileCallback DiffForEachFileCallback
HunkCallback DiffForEachHunkCallback
@ -341,6 +364,54 @@ func DefaultDiffOptions() (DiffOptions, error) {
}, nil
}
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
)
//TODO implement git_diff_similarity_metric
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{}
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
}
var (
ErrDeltaSkip = errors.New("Skip delta")
)

View File

@ -6,20 +6,68 @@ import (
"testing"
)
func TestDiffTreeToTree(t *testing.T) {
func TestFindSimilar(t *testing.T) {
repo := createTestRepo(t)
defer repo.Free()
defer os.RemoveAll(repo.Workdir())
_, originalTreeId := seedTestRepo(t, repo)
originalTree, err := repo.LookupTree(originalTreeId)
originalTree, newTree := createTestTrees(t, repo)
diffOpt, _ := DefaultDiffOptions()
diff, err := repo.DiffTreeToTree(originalTree, newTree, &diffOpt)
checkFatal(t, err)
if diff == nil {
t.Fatal("no diff returned")
}
findOpts, err := DefaultDiffFindOptions()
checkFatal(t, err)
findOpts.Flags = DiffFindBreakRewrites
err = diff.FindSimilar(&findOpts)
checkFatal(t, err)
_, newTreeId := updateReadme(t, repo, "file changed\n")
numDiffs := 0
numAdded := 0
numDeleted := 0
newTree, err := repo.LookupTree(newTreeId)
checkFatal(t, err)
err = diff.ForEach(func(file DiffDelta, progress float64) (DiffForEachHunkCallback, error) {
numDiffs++
switch file.Status {
case DeltaAdded:
numAdded++
case DeltaDeleted:
numDeleted++
}
return func(hunk DiffHunk) (DiffForEachLineCallback, error) {
return func(line DiffLine) error {
return nil
}, nil
}, nil
}, DiffDetailLines)
if numDiffs != 2 {
t.Fatal("Incorrect number of files in diff")
}
if numAdded != 1 {
t.Fatal("Incorrect number of new files in diff")
}
if numDeleted != 1 {
t.Fatal("Incorrect number of deleted files in diff")
}
}
func TestDiffTreeToTree(t *testing.T) {
repo := createTestRepo(t)
defer repo.Free()
defer os.RemoveAll(repo.Workdir())
originalTree, newTree := createTestTrees(t, repo)
callbackInvoked := false
opts := DiffOptions{
@ -94,3 +142,18 @@ func TestDiffTreeToTree(t *testing.T) {
}
}
func createTestTrees(t *testing.T, repo *Repository) (originalTree *Tree, newTree *Tree) {
var err error
_, originalTreeId := seedTestRepo(t, repo)
originalTree, err = repo.LookupTree(originalTreeId)
checkFatal(t, err)
_, newTreeId := updateReadme(t, repo, "file changed\n")
newTree, err = repo.LookupTree(newTreeId)
checkFatal(t, err)
return originalTree, newTree
}