From c8ce59d4eb3fc736fa380e7a2747c96659552e5d Mon Sep 17 00:00:00 2001 From: lhchavez Date: Sun, 5 Sep 2021 20:06:56 -0700 Subject: [PATCH] Add support for Repository.ReachableFromAny() (#826) This change exposes the binding for `git_graph_reachable_from_any()`. --- graph.go | 27 +++++++++++++++++++ graph_test.go | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 graph_test.go diff --git a/graph.go b/graph.go index 688818c..05da423 100644 --- a/graph.go +++ b/graph.go @@ -40,3 +40,30 @@ func (repo *Repository) AheadBehind(local, upstream *Oid) (ahead, behind int, er return int(aheadT), int(behindT), nil } + +// ReachableFromAny returns whether a commit is reachable from any of a list of +// commits by following parent edges. +func (repo *Repository) ReachableFromAny(commit *Oid, descendants []*Oid) (bool, error) { + if len(descendants) == 0 { + return false, nil + } + + coids := make([]C.git_oid, len(descendants)) + for i := 0; i < len(descendants); i++ { + coids[i] = *descendants[i].toC() + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_graph_reachable_from_any(repo.ptr, commit.toC(), &coids[0], C.size_t(len(descendants))) + runtime.KeepAlive(repo) + runtime.KeepAlive(commit) + runtime.KeepAlive(coids) + runtime.KeepAlive(descendants) + if ret < 0 { + return false, MakeGitError(ret) + } + + return (ret > 0), nil +} diff --git a/graph_test.go b/graph_test.go new file mode 100644 index 0000000..da19f35 --- /dev/null +++ b/graph_test.go @@ -0,0 +1,75 @@ +package git + +import ( + "testing" +) + +func TestReachableFromAny(t *testing.T) { + repo, err := OpenRepository("testdata/TestGitRepository.git") + checkFatal(t, err) + defer repo.Free() + + for name, tc := range map[string]struct { + reachable bool + commit string + descendants []string + }{ + "empty": { + reachable: false, + commit: "49322bb17d3acc9146f98c97d078513228bbf3c0", + }, + "same": { + reachable: true, + commit: "49322bb17d3acc9146f98c97d078513228bbf3c0", + descendants: []string{"49322bb17d3acc9146f98c97d078513228bbf3c0"}, + }, + "unreachable": { + reachable: false, + commit: "ac7e7e44c1885efb472ad54a78327d66bfc4ecef", + descendants: []string{"58be4659bb571194ed4562d04b359d26216f526e"}, + }, + "unreachable-reverse": { + reachable: false, + commit: "58be4659bb571194ed4562d04b359d26216f526e", + descendants: []string{"ac7e7e44c1885efb472ad54a78327d66bfc4ecef"}, + }, + "root": { + reachable: false, + commit: "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", + descendants: []string{ + "ac7e7e44c1885efb472ad54a78327d66bfc4ecef", + "d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", + "f73b95671f326616d66b2afb3bdfcdbbce110b44", + "d0114ab8ac326bab30e3a657a0397578c5a1af88", + }, + }, + "head": { + reachable: false, + commit: "49322bb17d3acc9146f98c97d078513228bbf3c0", + descendants: []string{ + "ac7e7e44c1885efb472ad54a78327d66bfc4ecef", + "d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", + "f73b95671f326616d66b2afb3bdfcdbbce110b44", + "d0114ab8ac326bab30e3a657a0397578c5a1af88", + }, + }, + } { + tc := tc + t.Run(name, func(t *testing.T) { + commit, err := NewOid(tc.commit) + checkFatal(t, err) + + descendants := make([]*Oid, len(tc.descendants)) + for i, o := range tc.descendants { + descendants[i], err = NewOid(o) + checkFatal(t, err) + } + reachable, err := repo.ReachableFromAny(commit, descendants) + checkFatal(t, err) + + if reachable != tc.reachable { + t.Errorf("ReachableFromAny(%s, %v) = %v, wanted %v", tc.commit, tc.descendants, reachable, tc.reachable) + } + }) + } +}