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.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 }