227 lines
6.9 KiB
Go
227 lines
6.9 KiB
Go
package git
|
|
|
|
/*
|
|
#include <git2.h>
|
|
*/
|
|
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.ptr, cDescribeOpts)
|
|
runtime.KeepAlive(c)
|
|
if ecode < 0 {
|
|
return nil, MakeGitError(ecode)
|
|
}
|
|
|
|
return newDescribeResultFromC(resultPtr), nil
|
|
}
|
|
|
|
// DescribeWorkdir describes the working tree. It means describe HEAD
|
|
// and appends <mark> (-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)
|
|
runtime.KeepAlive(repo)
|
|
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 {
|
|
doNotCompare
|
|
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)
|
|
runtime.KeepAlive(result)
|
|
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
|
|
}
|