diff --git a/describe.go b/describe.go new file mode 100644 index 0000000..c6f9a79 --- /dev/null +++ b/describe.go @@ -0,0 +1,222 @@ +package git + +/* +#include +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +// DescribeOptions represents the describe operation configuration. +// +// You can use DefaultDescribeOptions() to get default options. +type DescribeOptions struct { + // How many tags as candidates to consider to describe the input commit-ish. + // Increasing it above 10 will take slightly longer but may produce a more + // accurate result. 0 will cause only exact matches to be output. + MaxCandidatesTags uint // default: 10 + + // By default describe only shows annotated tags. Change this in order + // to show all refs from refs/tags or refs/. + Strategy DescribeOptionsStrategy // default: DescribeDefault + + // Only consider tags matching the given glob(7) pattern, excluding + // the "refs/tags/" prefix. Can be used to avoid leaking private + // tags from the repo. + Pattern string + + // When calculating the distance from the matching tag or + // reference, only walk down the first-parent ancestry. + OnlyFollowFirstParent bool + + // If no matching tag or reference is found, the describe + // operation would normally fail. If this option is set, it + // will instead fall back to showing the full id of the commit. + ShowCommitOidAsFallback bool +} + +// DefaultDescribeOptions returns default options for the describe operation. +func DefaultDescribeOptions() (DescribeOptions, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + opts := C.git_describe_options{} + ecode := C.git_describe_init_options(&opts, C.GIT_DESCRIBE_OPTIONS_VERSION) + if ecode < 0 { + return DescribeOptions{}, MakeGitError(ecode) + } + + return DescribeOptions{ + MaxCandidatesTags: uint(opts.max_candidates_tags), + Strategy: DescribeOptionsStrategy(opts.describe_strategy), + }, nil +} + +// DescribeFormatOptions can be used for formatting the describe string. +// +// You can use DefaultDescribeFormatOptions() to get default options. +type DescribeFormatOptions struct { + // Size of the abbreviated commit id to use. This value is the + // lower bound for the length of the abbreviated string. + AbbreviatedSize uint // default: 7 + + // Set to use the long format even when a shorter name could be used. + AlwaysUseLongFormat bool + + // If the workdir is dirty and this is set, this string will be + // appended to the description string. + DirtySuffix string +} + +// DefaultDescribeFormatOptions returns default options for formatting +// the output. +func DefaultDescribeFormatOptions() (DescribeFormatOptions, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + opts := C.git_describe_format_options{} + ecode := C.git_describe_init_format_options(&opts, C.GIT_DESCRIBE_FORMAT_OPTIONS_VERSION) + if ecode < 0 { + return DescribeFormatOptions{}, MakeGitError(ecode) + } + + return DescribeFormatOptions{ + AbbreviatedSize: uint(opts.abbreviated_size), + AlwaysUseLongFormat: opts.always_use_long_format == 1, + }, nil +} + +// DescribeOptionsStrategy behaves like the --tags and --all options +// to git-describe, namely they say to look for any reference in +// either refs/tags/ or refs/ respectively. +// +// By default it only shows annotated tags. +type DescribeOptionsStrategy uint + +// Describe strategy options. +const ( + DescribeDefault DescribeOptionsStrategy = C.GIT_DESCRIBE_DEFAULT + DescribeTags DescribeOptionsStrategy = C.GIT_DESCRIBE_TAGS + DescribeAll DescribeOptionsStrategy = C.GIT_DESCRIBE_ALL +) + +// Describe performs the describe operation on the commit. +func (c *Commit) Describe(opts *DescribeOptions) (*DescribeResult, error) { + var resultPtr *C.git_describe_result + + var cDescribeOpts *C.git_describe_options + if opts != nil { + var cpattern *C.char + if len(opts.Pattern) > 0 { + cpattern = C.CString(opts.Pattern) + defer C.free(unsafe.Pointer(cpattern)) + } + + cDescribeOpts = &C.git_describe_options{ + version: C.GIT_DESCRIBE_OPTIONS_VERSION, + max_candidates_tags: C.uint(opts.MaxCandidatesTags), + describe_strategy: C.uint(opts.Strategy), + pattern: cpattern, + only_follow_first_parent: cbool(opts.OnlyFollowFirstParent), + show_commit_oid_as_fallback: cbool(opts.ShowCommitOidAsFallback), + } + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_describe_commit(&resultPtr, c.gitObject.ptr, cDescribeOpts) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + + return newDescribeResultFromC(resultPtr), nil +} + +// DescribeWorkdir describes the working tree. It means describe HEAD +// and appends (-dirty by default) if the working tree is dirty. +func (repo *Repository) DescribeWorkdir(opts *DescribeOptions) (*DescribeResult, error) { + var resultPtr *C.git_describe_result + + var cDescribeOpts *C.git_describe_options + if opts != nil { + var cpattern *C.char + if len(opts.Pattern) > 0 { + cpattern = C.CString(opts.Pattern) + defer C.free(unsafe.Pointer(cpattern)) + } + + cDescribeOpts = &C.git_describe_options{ + version: C.GIT_DESCRIBE_OPTIONS_VERSION, + max_candidates_tags: C.uint(opts.MaxCandidatesTags), + describe_strategy: C.uint(opts.Strategy), + pattern: cpattern, + only_follow_first_parent: cbool(opts.OnlyFollowFirstParent), + show_commit_oid_as_fallback: cbool(opts.ShowCommitOidAsFallback), + } + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_describe_workdir(&resultPtr, repo.ptr, cDescribeOpts) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + + return newDescribeResultFromC(resultPtr), nil +} + +// DescribeResult represents the output from the 'git_describe_commit' +// and 'git_describe_workdir' functions in libgit2. +// +// Use Format() to get a string out of it. +type DescribeResult struct { + ptr *C.git_describe_result +} + +func newDescribeResultFromC(ptr *C.git_describe_result) *DescribeResult { + result := &DescribeResult{ + ptr: ptr, + } + runtime.SetFinalizer(result, (*DescribeResult).Free) + return result +} + +// Format prints the DescribeResult as a string. +func (result *DescribeResult) Format(opts *DescribeFormatOptions) (string, error) { + resultBuf := C.git_buf{} + + var cFormatOpts *C.git_describe_format_options + if opts != nil { + cDirtySuffix := C.CString(opts.DirtySuffix) + defer C.free(unsafe.Pointer(cDirtySuffix)) + + cFormatOpts = &C.git_describe_format_options{ + version: C.GIT_DESCRIBE_FORMAT_OPTIONS_VERSION, + abbreviated_size: C.uint(opts.AbbreviatedSize), + always_use_long_format: cbool(opts.AlwaysUseLongFormat), + dirty_suffix: cDirtySuffix, + } + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_describe_format(&resultBuf, result.ptr, cFormatOpts) + if ecode < 0 { + return "", MakeGitError(ecode) + } + defer C.git_buf_free(&resultBuf) + + return C.GoString(resultBuf.ptr), nil +} + +// Free cleans up the C reference. +func (result *DescribeResult) Free() { + runtime.SetFinalizer(result, nil) + C.git_describe_result_free(result.ptr) + result.ptr = nil +} diff --git a/describe_test.go b/describe_test.go new file mode 100644 index 0000000..25af107 --- /dev/null +++ b/describe_test.go @@ -0,0 +1,106 @@ +package git + +import ( + "path" + "runtime" + "strings" + "testing" +) + +func TestDescribeCommit(t *testing.T) { + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + describeOpts, err := DefaultDescribeOptions() + checkFatal(t, err) + + formatOpts, err := DefaultDescribeFormatOptions() + checkFatal(t, err) + + commitID, _ := seedTestRepo(t, repo) + + commit, err := repo.LookupCommit(commitID) + checkFatal(t, err) + + // No annotated tags can be used to describe master + _, err = commit.Describe(&describeOpts) + checkDescribeNoRefsFound(t, err) + + // Fallback + fallback := describeOpts + fallback.ShowCommitOidAsFallback = true + result, err := commit.Describe(&fallback) + checkFatal(t, err) + resultStr, err := result.Format(&formatOpts) + checkFatal(t, err) + compareStrings(t, "473bf77", resultStr) + + // Abbreviated + abbreviated := formatOpts + abbreviated.AbbreviatedSize = 2 + result, err = commit.Describe(&fallback) + checkFatal(t, err) + resultStr, err = result.Format(&abbreviated) + checkFatal(t, err) + compareStrings(t, "473b", resultStr) + + createTestTag(t, repo, commit) + + // Exact tag + patternOpts := describeOpts + patternOpts.Pattern = "v[0-9]*" + result, err = commit.Describe(&patternOpts) + checkFatal(t, err) + resultStr, err = result.Format(&formatOpts) + checkFatal(t, err) + compareStrings(t, "v0.0.0", resultStr) + + // Pattern no match + patternOpts.Pattern = "v[1-9]*" + result, err = commit.Describe(&patternOpts) + checkDescribeNoRefsFound(t, err) + + commitID, _ = updateReadme(t, repo, "update1") + commit, err = repo.LookupCommit(commitID) + checkFatal(t, err) + + // Tag-1 + result, err = commit.Describe(&describeOpts) + checkFatal(t, err) + resultStr, err = result.Format(&formatOpts) + checkFatal(t, err) + compareStrings(t, "v0.0.0-1-gd88ef8d", resultStr) + + // Strategy: All + describeOpts.Strategy = DescribeAll + result, err = commit.Describe(&describeOpts) + checkFatal(t, err) + resultStr, err = result.Format(&formatOpts) + checkFatal(t, err) + compareStrings(t, "heads/master", resultStr) + + repo.CreateBranch("hotfix", commit, false) + + // Workdir (branch) + result, err = repo.DescribeWorkdir(&describeOpts) + checkFatal(t, err) + resultStr, err = result.Format(&formatOpts) + checkFatal(t, err) + compareStrings(t, "heads/hotfix", resultStr) +} + +func checkDescribeNoRefsFound(t *testing.T, err error) { + // The failure happens at wherever we were called, not here + _, file, line, ok := runtime.Caller(1) + if !ok { + t.Fatalf("Unable to get caller") + } + if err == nil || !strings.Contains(err.Error(), "No reference found, cannot describe anything") { + t.Fatalf( + "%s:%v: was expecting error 'No reference found, cannot describe anything', got %v", + path.Base(file), + line, + err, + ) + } +} diff --git a/handles.go b/handles.go index a062231..ec62a48 100644 --- a/handles.go +++ b/handles.go @@ -10,15 +10,14 @@ type HandleList struct { sync.RWMutex // stores the Go pointers handles []interface{} - // Indicates which indices are in use, and keeps a pointer to slot int variable (the handle) - // in the Go world, so that the Go garbage collector does not free it. - set map[int]*int + // indicates which indices are in use + set map[int]bool } func NewHandleList() *HandleList { return &HandleList{ handles: make([]interface{}, 5), - set: make(map[int]*int), + set: make(map[int]bool), } } @@ -26,7 +25,7 @@ func NewHandleList() *HandleList { // list. You must only run this function while holding a write lock. func (v *HandleList) findUnusedSlot() int { for i := 1; i < len(v.handles); i++ { - _, isUsed := v.set[i] + isUsed := v.set[i] if !isUsed { return i } @@ -48,7 +47,7 @@ func (v *HandleList) Track(pointer interface{}) unsafe.Pointer { slot := v.findUnusedSlot() v.handles[slot] = pointer - v.set[slot] = &slot // Keep a pointer to slot in Go world, so it's not freed by GC. + v.set[slot] = true v.Unlock() diff --git a/reference.go b/reference.go index 140082f..d24e054 100644 --- a/reference.go +++ b/reference.go @@ -315,11 +315,6 @@ func (v *Reference) IsTag() bool { return C.git_reference_is_tag(v.ptr) == 1 } -// IsNote checks if the reference is a note. -func (v *Reference) IsNote() bool { - return C.git_reference_is_note(v.ptr) == 1 -} - func (v *Reference) Free() { runtime.SetFinalizer(v, nil) C.git_reference_free(v.ptr) @@ -430,22 +425,3 @@ func (v *ReferenceIterator) Free() { runtime.SetFinalizer(v, nil) C.git_reference_iterator_free(v.ptr) } - -// ReferenceIsValidName ensures the reference name is well-formed. -// -// Valid reference names must follow one of two patterns: -// -// 1. Top-level names must contain only capital letters and underscores, -// and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD"). -// -// 2. Names prefixed with "refs/" can be almost anything. You must avoid -// the characters '~', '^', ':', ' \ ', '?', '[', and '*', and the sequences -// ".." and " @ {" which have special meaning to revparse. -func ReferenceIsValidName(name string) bool { - cname := C.CString(name) - defer C.free(unsafe.Pointer(cname)) - if C.git_reference_is_valid_name(cname) == 1 { - return true - } - return false -} diff --git a/reference_test.go b/reference_test.go index 761daf8..f1546e2 100644 --- a/reference_test.go +++ b/reference_test.go @@ -176,48 +176,6 @@ func TestUtil(t *testing.T) { } } -func TestIsNote(t *testing.T) { - repo := createTestRepo(t) - defer cleanupTestRepo(t, repo) - - commitID, _ := seedTestRepo(t, repo) - - sig := &Signature{ - Name: "Rand Om Hacker", - Email: "random@hacker.com", - When: time.Now(), - } - - refname, err := repo.Notes.DefaultRef() - checkFatal(t, err) - - _, err = repo.Notes.Create(refname, sig, sig, commitID, "This is a note", false) - checkFatal(t, err) - - ref, err := repo.References.Lookup(refname) - checkFatal(t, err) - - if !ref.IsNote() { - t.Fatalf("%s should be a note", ref.Name()) - } - - ref, err = repo.References.Create("refs/heads/foo", commitID, true, "") - checkFatal(t, err) - - if ref.IsNote() { - t.Fatalf("%s should not be a note", ref.Name()) - } -} - -func TestReferenceIsValidName(t *testing.T) { - if !ReferenceIsValidName("HEAD") { - t.Errorf("HEAD should be a valid reference name") - } - if ReferenceIsValidName("HEAD1") { - t.Errorf("HEAD1 should not be a valid reference name") - } -} - func compareStringList(t *testing.T, expected, actual []string) { for i, v := range expected { if actual[i] != v { diff --git a/repository.go b/repository.go index 62fde6d..44509af 100644 --- a/repository.go +++ b/repository.go @@ -27,9 +27,6 @@ type Repository struct { // Notes represents the collection of notes and can be used to // read, write and delete notes from this repository. 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 { @@ -39,7 +36,6 @@ func newRepositoryFromC(ptr *C.git_repository) *Repository { repo.Submodules.repo = repo repo.References.repo = repo repo.Notes.repo = repo - repo.Tags.repo = repo runtime.SetFinalizer(repo, (*Repository).Free) @@ -321,6 +317,36 @@ func (v *Repository) CreateCommit( 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() { runtime.SetFinalizer(v, nil) C.git_odb_free(v.ptr) diff --git a/tag.go b/tag.go index ca85156..89ac8bd 100644 --- a/tag.go +++ b/tag.go @@ -2,14 +2,8 @@ package git /* #include - -extern int _go_git_tag_foreach(git_repository *repo, void *payload); */ import "C" -import ( - "runtime" - "unsafe" -) // Tag type Tag struct { @@ -48,164 +42,3 @@ func (t Tag) TargetId() *Oid { func (t Tag) TargetType() ObjectType { 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/"). 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 -} diff --git a/tag_test.go b/tag_test.go index 2fdfe00..74f9fec 100644 --- a/tag_test.go +++ b/tag_test.go @@ -1,7 +1,6 @@ package git import ( - "errors" "testing" "time" ) @@ -25,146 +24,6 @@ func TestCreateTag(t *testing.T) { 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) { if value != expected { t.Fatalf("expected '%v', actual '%v'", expected, value) @@ -180,21 +39,7 @@ func createTestTag(t *testing.T, repo *Repository, commit *Commit) *Oid { When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc), } - 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) + tagId, err := repo.CreateTag("v0.0.0", commit, sig, "This is a tag") checkFatal(t, err) return tagId } diff --git a/tree.go b/tree.go index f543c11..aad2c8d 100644 --- a/tree.go +++ b/tree.go @@ -55,24 +55,6 @@ func (t Tree) EntryByName(filename string) *TreeEntry { return newTreeEntry(entry) } -// EntryById performs a lookup for a tree entry with the given SHA value. -// -// It returns a *TreeEntry that is owned by the Tree. You don't have to -// free it, but you must not use it after the Tree is freed. -// -// Warning: this must examine every entry in the tree, so it is not fast. -func (t Tree) EntryById(id *Oid) *TreeEntry { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - entry := C.git_tree_entry_byid(t.cast_ptr, id.toC()) - if entry == nil { - return nil - } - - return newTreeEntry(entry) -} - // EntryByPath looks up an entry by its full path, recursing into // deeper trees if necessary (i.e. if there are slashes in the path) func (t Tree) EntryByPath(path string) (*TreeEntry, error) { diff --git a/tree_test.go b/tree_test.go deleted file mode 100644 index 4c6a4ed..0000000 --- a/tree_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package git - -import "testing" - -func TestTreeEntryById(t *testing.T) { - repo := createTestRepo(t) - defer cleanupTestRepo(t, repo) - - _, treeID := seedTestRepo(t, repo) - - tree, err := repo.LookupTree(treeID) - checkFatal(t, err) - - id, err := NewOid("257cc5642cb1a054f08cc83f2d943e56fd3ebe99") - checkFatal(t, err) - - entry := tree.EntryById(id) - - if entry == nil { - t.Fatalf("entry id %v was not found", id) - } -} diff --git a/wrapper.c b/wrapper.c index 1efe5d7..75cc03c 100644 --- a/wrapper.c +++ b/wrapper.c @@ -131,9 +131,4 @@ int _go_git_index_remove_all(git_index *index, const git_strarray *pathspec, voi 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 */