Merge branch 'tags-col' into next
This commit is contained in:
commit
c0c6caed3a
|
@ -27,6 +27,9 @@ type Repository struct {
|
||||||
// Notes represents the collection of notes and can be used to
|
// Notes represents the collection of notes and can be used to
|
||||||
// read, write and delete notes from this repository.
|
// read, write and delete notes from this repository.
|
||||||
Notes NoteCollection
|
Notes NoteCollection
|
||||||
|
// Tags represents the collection of tags and can be used to create,
|
||||||
|
// list and iterate tags in this repository.
|
||||||
|
Tags TagsCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRepositoryFromC(ptr *C.git_repository) *Repository {
|
func newRepositoryFromC(ptr *C.git_repository) *Repository {
|
||||||
|
@ -36,6 +39,7 @@ func newRepositoryFromC(ptr *C.git_repository) *Repository {
|
||||||
repo.Submodules.repo = repo
|
repo.Submodules.repo = repo
|
||||||
repo.References.repo = repo
|
repo.References.repo = repo
|
||||||
repo.Notes.repo = repo
|
repo.Notes.repo = repo
|
||||||
|
repo.Tags.repo = repo
|
||||||
|
|
||||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||||
|
|
||||||
|
@ -317,36 +321,6 @@ func (v *Repository) CreateCommit(
|
||||||
return oid, nil
|
return oid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Repository) CreateTag(
|
|
||||||
name string, commit *Commit, tagger *Signature, message string) (*Oid, error) {
|
|
||||||
|
|
||||||
oid := new(Oid)
|
|
||||||
|
|
||||||
cname := C.CString(name)
|
|
||||||
defer C.free(unsafe.Pointer(cname))
|
|
||||||
|
|
||||||
cmessage := C.CString(message)
|
|
||||||
defer C.free(unsafe.Pointer(cmessage))
|
|
||||||
|
|
||||||
taggerSig, err := tagger.toC()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer C.git_signature_free(taggerSig)
|
|
||||||
|
|
||||||
ctarget := commit.gitObject.ptr
|
|
||||||
|
|
||||||
runtime.LockOSThread()
|
|
||||||
defer runtime.UnlockOSThread()
|
|
||||||
|
|
||||||
ret := C.git_tag_create(oid.toC(), v.ptr, cname, ctarget, taggerSig, cmessage, 0)
|
|
||||||
if ret < 0 {
|
|
||||||
return nil, MakeGitError(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
return oid, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Odb) Free() {
|
func (v *Odb) Free() {
|
||||||
runtime.SetFinalizer(v, nil)
|
runtime.SetFinalizer(v, nil)
|
||||||
C.git_odb_free(v.ptr)
|
C.git_odb_free(v.ptr)
|
||||||
|
|
167
tag.go
167
tag.go
|
@ -2,8 +2,14 @@ package git
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
|
||||||
|
extern int _go_git_tag_foreach(git_repository *repo, void *payload);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// Tag
|
// Tag
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
|
@ -42,3 +48,164 @@ func (t Tag) TargetId() *Oid {
|
||||||
func (t Tag) TargetType() ObjectType {
|
func (t Tag) TargetType() ObjectType {
|
||||||
return ObjectType(C.git_tag_target_type(t.cast_ptr))
|
return ObjectType(C.git_tag_target_type(t.cast_ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagsCollection struct {
|
||||||
|
repo *Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TagsCollection) Create(
|
||||||
|
name string, commit *Commit, tagger *Signature, message string) (*Oid, error) {
|
||||||
|
|
||||||
|
oid := new(Oid)
|
||||||
|
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
|
||||||
|
cmessage := C.CString(message)
|
||||||
|
defer C.free(unsafe.Pointer(cmessage))
|
||||||
|
|
||||||
|
taggerSig, err := tagger.toC()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer C.git_signature_free(taggerSig)
|
||||||
|
|
||||||
|
ctarget := commit.gitObject.ptr
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ret := C.git_tag_create(oid.toC(), c.repo.ptr, cname, ctarget, taggerSig, cmessage, 0)
|
||||||
|
if ret < 0 {
|
||||||
|
return nil, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateLightweight creates a new lightweight tag pointing to a commit
|
||||||
|
// and returns the id of the target object.
|
||||||
|
//
|
||||||
|
// The name of the tag is validated for consistency (see git_tag_create() for the rules
|
||||||
|
// https://libgit2.github.com/libgit2/#HEAD/group/tag/git_tag_create) and should
|
||||||
|
// not conflict with an already existing tag name.
|
||||||
|
//
|
||||||
|
// If force is true and a reference already exists with the given name, it'll be replaced.
|
||||||
|
//
|
||||||
|
// The created tag is a simple reference and can be queried using
|
||||||
|
// repo.References.Lookup("refs/tags/<name>"). The name of the tag (eg "v1.0.0")
|
||||||
|
// is queried with ref.Shorthand().
|
||||||
|
func (c *TagsCollection) CreateLightweight(name string, commit *Commit, force bool) (*Oid, error) {
|
||||||
|
|
||||||
|
oid := new(Oid)
|
||||||
|
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
|
||||||
|
ctarget := commit.gitObject.ptr
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
err := C.git_tag_create_lightweight(oid.toC(), c.repo.ptr, cname, ctarget, cbool(force))
|
||||||
|
if err < 0 {
|
||||||
|
return nil, MakeGitError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns the names of all the tags in the repository,
|
||||||
|
// eg: ["v1.0.1", "v2.0.0"].
|
||||||
|
func (c *TagsCollection) List() ([]string, error) {
|
||||||
|
var strC C.git_strarray
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ecode := C.git_tag_list(&strC, c.repo.ptr)
|
||||||
|
if ecode < 0 {
|
||||||
|
return nil, MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
defer C.git_strarray_free(&strC)
|
||||||
|
|
||||||
|
tags := makeStringsFromCStrings(strC.strings, int(strC.count))
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListWithMatch returns the names of all the tags in the repository
|
||||||
|
// that match a given pattern.
|
||||||
|
//
|
||||||
|
// The pattern is a standard fnmatch(3) pattern http://man7.org/linux/man-pages/man3/fnmatch.3.html
|
||||||
|
func (c *TagsCollection) ListWithMatch(pattern string) ([]string, error) {
|
||||||
|
var strC C.git_strarray
|
||||||
|
|
||||||
|
patternC := C.CString(pattern)
|
||||||
|
defer C.free(unsafe.Pointer(patternC))
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ecode := C.git_tag_list_match(&strC, patternC, c.repo.ptr)
|
||||||
|
if ecode < 0 {
|
||||||
|
return nil, MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
defer C.git_strarray_free(&strC)
|
||||||
|
|
||||||
|
tags := makeStringsFromCStrings(strC.strings, int(strC.count))
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagForeachCallback is called for each tag in the repository.
|
||||||
|
//
|
||||||
|
// The name is the full ref name eg: "refs/tags/v1.0.0".
|
||||||
|
//
|
||||||
|
// Note that the callback is called for lightweight tags as well,
|
||||||
|
// so repo.LookupTag() will return an error for these tags. Use
|
||||||
|
// repo.References.Lookup() instead.
|
||||||
|
type TagForeachCallback func(name string, id *Oid) error
|
||||||
|
type tagForeachData struct {
|
||||||
|
callback TagForeachCallback
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
//export gitTagForeachCb
|
||||||
|
func gitTagForeachCb(name *C.char, id *C.git_oid, handle unsafe.Pointer) int {
|
||||||
|
payload := pointerHandles.Get(handle)
|
||||||
|
data, ok := payload.(*tagForeachData)
|
||||||
|
if !ok {
|
||||||
|
panic("could not retrieve tag foreach CB handle")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := data.callback(C.GoString(name), newOidFromC(id))
|
||||||
|
if err != nil {
|
||||||
|
data.err = err
|
||||||
|
return C.GIT_EUSER
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foreach calls the callback for each tag in the repository.
|
||||||
|
func (c *TagsCollection) Foreach(callback TagForeachCallback) error {
|
||||||
|
data := tagForeachData{
|
||||||
|
callback: callback,
|
||||||
|
err: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
handle := pointerHandles.Track(&data)
|
||||||
|
defer pointerHandles.Untrack(handle)
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
err := C._go_git_tag_foreach(c.repo.ptr, handle)
|
||||||
|
if err == C.GIT_EUSER {
|
||||||
|
return data.err
|
||||||
|
}
|
||||||
|
if err < 0 {
|
||||||
|
return MakeGitError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
157
tag_test.go
157
tag_test.go
|
@ -1,6 +1,7 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -24,6 +25,146 @@ func TestCreateTag(t *testing.T) {
|
||||||
compareStrings(t, commitId.String(), tag.TargetId().String())
|
compareStrings(t, commitId.String(), tag.TargetId().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateTagLightweight(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
commitID, _ := seedTestRepo(t, repo)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
tagID, err := repo.Tags.CreateLightweight("v0.1.0", commit, false)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
_, err = repo.Tags.CreateLightweight("v0.1.0", commit, true)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
ref, err := repo.References.Lookup("refs/tags/v0.1.0")
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
compareStrings(t, "refs/tags/v0.1.0", ref.Name())
|
||||||
|
compareStrings(t, "v0.1.0", ref.Shorthand())
|
||||||
|
compareStrings(t, tagID.String(), commitID.String())
|
||||||
|
compareStrings(t, commitID.String(), ref.Target().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListTags(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
commitID, _ := seedTestRepo(t, repo)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
createTag(t, repo, commit, "v1.0.1", "Release v1.0.1")
|
||||||
|
|
||||||
|
commitID, _ = updateReadme(t, repo, "Release version 2")
|
||||||
|
|
||||||
|
commit, err = repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
createTag(t, repo, commit, "v2.0.0", "Release v2.0.0")
|
||||||
|
|
||||||
|
expected := []string{
|
||||||
|
"v1.0.1",
|
||||||
|
"v2.0.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := repo.Tags.List()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
compareStringList(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListTagsWithMatch(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
commitID, _ := seedTestRepo(t, repo)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
createTag(t, repo, commit, "v1.0.1", "Release v1.0.1")
|
||||||
|
|
||||||
|
commitID, _ = updateReadme(t, repo, "Release version 2")
|
||||||
|
|
||||||
|
commit, err = repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
createTag(t, repo, commit, "v2.0.0", "Release v2.0.0")
|
||||||
|
|
||||||
|
expected := []string{
|
||||||
|
"v2.0.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := repo.Tags.ListWithMatch("v2*")
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
compareStringList(t, expected, actual)
|
||||||
|
|
||||||
|
expected = []string{
|
||||||
|
"v1.0.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err = repo.Tags.ListWithMatch("v1*")
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
compareStringList(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTagForeach(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
commitID, _ := seedTestRepo(t, repo)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
tag1 := createTag(t, repo, commit, "v1.0.1", "Release v1.0.1")
|
||||||
|
|
||||||
|
commitID, _ = updateReadme(t, repo, "Release version 2")
|
||||||
|
|
||||||
|
commit, err = repo.LookupCommit(commitID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
tag2 := createTag(t, repo, commit, "v2.0.0", "Release v2.0.0")
|
||||||
|
|
||||||
|
expectedNames := []string{
|
||||||
|
"refs/tags/v1.0.1",
|
||||||
|
"refs/tags/v2.0.0",
|
||||||
|
}
|
||||||
|
actualNames := []string{}
|
||||||
|
expectedOids := []string{
|
||||||
|
tag1.String(),
|
||||||
|
tag2.String(),
|
||||||
|
}
|
||||||
|
actualOids := []string{}
|
||||||
|
|
||||||
|
err = repo.Tags.Foreach(func(name string, id *Oid) error {
|
||||||
|
actualNames = append(actualNames, name)
|
||||||
|
actualOids = append(actualOids, id.String())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
compareStringList(t, expectedNames, actualNames)
|
||||||
|
compareStringList(t, expectedOids, actualOids)
|
||||||
|
|
||||||
|
fakeErr := errors.New("fake error")
|
||||||
|
|
||||||
|
err = repo.Tags.Foreach(func(name string, id *Oid) error {
|
||||||
|
return fakeErr
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != fakeErr {
|
||||||
|
t.Fatalf("Tags.Foreach() did not return the expected error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func compareStrings(t *testing.T, expected, value string) {
|
func compareStrings(t *testing.T, expected, value string) {
|
||||||
if value != expected {
|
if value != expected {
|
||||||
t.Fatalf("expected '%v', actual '%v'", expected, value)
|
t.Fatalf("expected '%v', actual '%v'", expected, value)
|
||||||
|
@ -39,7 +180,21 @@ func createTestTag(t *testing.T, repo *Repository, commit *Commit) *Oid {
|
||||||
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
|
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
|
||||||
}
|
}
|
||||||
|
|
||||||
tagId, err := repo.CreateTag("v0.0.0", commit, sig, "This is a tag")
|
tagId, err := repo.Tags.Create("v0.0.0", commit, sig, "This is a tag")
|
||||||
|
checkFatal(t, err)
|
||||||
|
return tagId
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTag(t *testing.T, repo *Repository, commit *Commit, name, message string) *Oid {
|
||||||
|
loc, err := time.LoadLocation("Europe/Bucharest")
|
||||||
|
checkFatal(t, err)
|
||||||
|
sig := &Signature{
|
||||||
|
Name: "Rand Om Hacker",
|
||||||
|
Email: "random@hacker.com",
|
||||||
|
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
|
||||||
|
}
|
||||||
|
|
||||||
|
tagId, err := repo.Tags.Create(name, commit, sig, message)
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
return tagId
|
return tagId
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,4 +131,9 @@ int _go_git_index_remove_all(git_index *index, const git_strarray *pathspec, voi
|
||||||
return git_index_remove_all(index, pathspec, cb, callback);
|
return git_index_remove_all(index, pathspec, cb, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _go_git_tag_foreach(git_repository *repo, void *payload)
|
||||||
|
{
|
||||||
|
return git_tag_foreach(repo, (git_tag_foreach_cb)&gitTagForeachCb, payload);
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in New Issue