Merge branch 'master-v23'
This commit is contained in:
commit
6d3a3499f1
12
.travis.yml
12
.travis.yml
|
@ -1,19 +1,15 @@
|
|||
language: go
|
||||
|
||||
install:
|
||||
- cd "${HOME}"
|
||||
- wget -O libgit2-0.22.1.tar.gz https://github.com/libgit2/libgit2/archive/v0.22.1.tar.gz
|
||||
- tar -xzvf libgit2-0.22.1.tar.gz
|
||||
- cd libgit2-0.22.1 && mkdir build && cd build
|
||||
- cmake -DTHREADSAFE=ON -DBUILD_CLAR=OFF -DCMAKE_C_FLAGS=-fPIC -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DCMAKE_INSTALL_PREFIX=/usr/local .. && make && sudo make install
|
||||
- sudo ldconfig
|
||||
- cd "${TRAVIS_BUILD_DIR}"
|
||||
sudo: required
|
||||
|
||||
install: ./script/install-libgit2.sh
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
|
|
36
branch.go
36
branch.go
|
@ -90,31 +90,17 @@ func (repo *Repository) NewBranchIterator(flags BranchType) (*BranchIterator, er
|
|||
return newBranchIteratorFromC(repo, ptr), nil
|
||||
}
|
||||
|
||||
func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, msg string) (*Branch, error) {
|
||||
func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool) (*Branch, error) {
|
||||
|
||||
var ptr *C.git_reference
|
||||
cBranchName := C.CString(branchName)
|
||||
defer C.free(unsafe.Pointer(cBranchName))
|
||||
cForce := cbool(force)
|
||||
|
||||
cSignature, err := signature.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(cSignature)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_branch_create(&ptr, repo.ptr, cBranchName, target.cast_ptr, cForce, cSignature, cmsg)
|
||||
ret := C.git_branch_create(&ptr, repo.ptr, cBranchName, target.cast_ptr, cForce)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -132,30 +118,16 @@ func (b *Branch) Delete() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *Branch) Move(newBranchName string, force bool, signature *Signature, msg string) (*Branch, error) {
|
||||
func (b *Branch) Move(newBranchName string, force bool) (*Branch, error) {
|
||||
var ptr *C.git_reference
|
||||
cNewBranchName := C.CString(newBranchName)
|
||||
defer C.free(unsafe.Pointer(cNewBranchName))
|
||||
cForce := cbool(force)
|
||||
|
||||
cSignature, err := signature.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(cSignature)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_branch_move(&ptr, b.Reference.ptr, cNewBranchName, cForce, cSignature, cmsg)
|
||||
ret := C.git_branch_move(&ptr, b.Reference.ptr, cNewBranchName, cForce)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
|
14
checkout.go
14
checkout.go
|
@ -15,18 +15,24 @@ type CheckoutStrategy uint
|
|||
const (
|
||||
CheckoutNone CheckoutStrategy = C.GIT_CHECKOUT_NONE // Dry run, no actual updates
|
||||
CheckoutSafe CheckoutStrategy = C.GIT_CHECKOUT_SAFE // Allow safe updates that cannot overwrite uncommitted data
|
||||
CheckoutSafeCreate CheckoutStrategy = C.GIT_CHECKOUT_SAFE_CREATE // Allow safe updates plus creation of missing files
|
||||
CheckoutForce CheckoutStrategy = C.GIT_CHECKOUT_FORCE // Allow all updates to force working directory to look like index
|
||||
CheckoutRecreateMissing CheckoutStrategy = C.GIT_CHECKOUT_RECREATE_MISSING // Allow checkout to recreate missing files
|
||||
CheckoutAllowConflicts CheckoutStrategy = C.GIT_CHECKOUT_ALLOW_CONFLICTS // Allow checkout to make safe updates even if conflicts are found
|
||||
CheckoutRemoveUntracked CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_UNTRACKED // Remove untracked files not in index (that are not ignored)
|
||||
CheckoutRemoveIgnored CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_IGNORED // Remove ignored files not in index
|
||||
CheckoutUpdateOnly CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_ONLY // Only update existing files, don't create new ones
|
||||
CheckoutDontUpdateIndex CheckoutStrategy = C.GIT_CHECKOUT_DONT_UPDATE_INDEX // Normally checkout updates index entries as it goes; this stops that
|
||||
CheckoutNoRefresh CheckoutStrategy = C.GIT_CHECKOUT_NO_REFRESH // Don't refresh index/config/etc before doing checkout
|
||||
CheckoutSkipUnmerged CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files
|
||||
CheckoutUserOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
|
||||
CheckoutUseTheirs CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index
|
||||
CheckoutDisablePathspecMatch CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths
|
||||
CheckoutSkipUnmerged CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files (NOT IMPLEMENTED)
|
||||
CheckoutUserOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED)
|
||||
CheckoutUseTheirs CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED)
|
||||
CheckoutSkipLockedDirectories CheckoutStrategy = C.GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES // Ignore directories in use, they will be left empty
|
||||
CheckoutDontOverwriteIgnored CheckoutStrategy = C.GIT_CHECKOUT_DONT_OVERWRITE_IGNORED // Don't overwrite ignored files that exist in the checkout target
|
||||
CheckoutConflictStyleMerge CheckoutStrategy = C.GIT_CHECKOUT_CONFLICT_STYLE_MERGE // Write normal merge files for conflicts
|
||||
CheckoutConflictStyleDiff3 CheckoutStrategy = C.GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 // Include common ancestor data in diff3 format files for conflicts
|
||||
CheckoutDontRemoveExisting CheckoutStrategy = C.GIT_CHECKOUT_DONT_REMOVE_EXISTING // Don't overwrite existing files or folders
|
||||
CheckoutDontWriteIndex CheckoutStrategy = C.GIT_CHECKOUT_DONT_WRITE_INDEX // Normally checkout writes the index upon completion; this prevents that
|
||||
CheckoutUpdateSubmodules CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES // Recursively checkout submodules with same options (NOT IMPLEMENTED)
|
||||
CheckoutUpdateSubmodulesIfChanged CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED // Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED)
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@ func checkout(t *testing.T, repo *Repository, commit *Commit) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = repo.SetHeadDetached(commit.Id(), commit.Author(), "checkout")
|
||||
err = repo.SetHeadDetached(commit.Id())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
27
clone.go
27
clone.go
|
@ -11,19 +11,17 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
type RemoteCreateCallback func(repo Repository, name, url string) (*Remote, ErrorCode)
|
||||
type RemoteCreateCallback func(repo *Repository, name, url string) (*Remote, ErrorCode)
|
||||
|
||||
type CloneOptions struct {
|
||||
*CheckoutOpts
|
||||
*RemoteCallbacks
|
||||
*FetchOptions
|
||||
Bare bool
|
||||
CheckoutBranch string
|
||||
RemoteCreateCallback RemoteCreateCallback
|
||||
}
|
||||
|
||||
func Clone(url string, path string, options *CloneOptions) (*Repository, error) {
|
||||
repo := new(Repository)
|
||||
|
||||
curl := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(curl))
|
||||
|
||||
|
@ -40,30 +38,33 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error)
|
|||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
ret := C.git_clone(&repo.ptr, curl, cpath, copts)
|
||||
|
||||
var ptr *C.git_repository
|
||||
ret := C.git_clone(&ptr, curl, cpath, copts)
|
||||
freeCheckoutOpts(&copts.checkout_opts)
|
||||
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
return repo, nil
|
||||
return newRepositoryFromC(ptr), nil
|
||||
}
|
||||
|
||||
//export remoteCreateCallback
|
||||
func remoteCreateCallback(cremote unsafe.Pointer, crepo unsafe.Pointer, cname, curl *C.char, payload unsafe.Pointer) C.int {
|
||||
name := C.GoString(cname)
|
||||
url := C.GoString(curl)
|
||||
repo := Repository{(*C.git_repository)(crepo)}
|
||||
repo := newRepositoryFromC((*C.git_repository)(crepo))
|
||||
// We don't own this repository, so make sure we don't try to free it
|
||||
runtime.SetFinalizer(repo, nil)
|
||||
|
||||
if opts, ok := pointerHandles.Get(payload).(CloneOptions); ok {
|
||||
remote, err := opts.RemoteCreateCallback(repo, name, url)
|
||||
// clear finalizer as the calling C function will
|
||||
// free the remote itself
|
||||
runtime.SetFinalizer(remote, nil)
|
||||
|
||||
if err == ErrOk && remote != nil {
|
||||
// clear finalizer as the calling C function will
|
||||
// free the remote itself
|
||||
runtime.SetFinalizer(remote, nil)
|
||||
|
||||
cptr := (**C.git_remote)(cremote)
|
||||
*cptr = remote.ptr
|
||||
} else if err == ErrOk && remote == nil {
|
||||
|
@ -83,7 +84,7 @@ func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) {
|
|||
return
|
||||
}
|
||||
populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
|
||||
populateRemoteCallbacks(&ptr.remote_callbacks, opts.RemoteCallbacks)
|
||||
populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions)
|
||||
ptr.bare = cbool(opts.Bare)
|
||||
|
||||
if opts.RemoteCreateCallback != nil {
|
||||
|
|
|
@ -18,10 +18,20 @@ func TestClone(t *testing.T) {
|
|||
path, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
|
||||
ref, err := repo.References.Lookup("refs/heads/master")
|
||||
checkFatal(t, err)
|
||||
|
||||
repo2, err := Clone(repo.Path(), path, &CloneOptions{Bare: true})
|
||||
defer cleanupTestRepo(t, repo2)
|
||||
|
||||
checkFatal(t, err)
|
||||
|
||||
ref2, err := repo2.References.Lookup("refs/heads/master")
|
||||
checkFatal(t, err)
|
||||
|
||||
if ref.Cmp(ref2) != 0 {
|
||||
t.Fatal("reference in clone does not match original ref")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneWithCallback(t *testing.T) {
|
||||
|
@ -37,10 +47,10 @@ func TestCloneWithCallback(t *testing.T) {
|
|||
|
||||
opts := CloneOptions{
|
||||
Bare: true,
|
||||
RemoteCreateCallback: func(r Repository, name, url string) (*Remote, ErrorCode) {
|
||||
RemoteCreateCallback: func(r *Repository, name, url string) (*Remote, ErrorCode) {
|
||||
testPayload += 1
|
||||
|
||||
remote, err := r.CreateRemote(REMOTENAME, url)
|
||||
remote, err := r.Remotes.Create(REMOTENAME, url)
|
||||
if err != nil {
|
||||
return nil, ErrGeneric
|
||||
}
|
||||
|
@ -58,7 +68,7 @@ func TestCloneWithCallback(t *testing.T) {
|
|||
t.Fatal("Payload's value has not been changed")
|
||||
}
|
||||
|
||||
remote, err := repo2.LookupRemote(REMOTENAME)
|
||||
remote, err := repo2.Remotes.Lookup(REMOTENAME)
|
||||
if err != nil || remote == nil {
|
||||
t.Fatal("Remote was not created properly")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
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.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 <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)
|
||||
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
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
4
git.go
4
git.go
|
@ -77,8 +77,8 @@ const (
|
|||
ErrNonFastForward ErrorCode = C.GIT_ENONFASTFORWARD
|
||||
// Name/ref spec was not in a valid format
|
||||
ErrInvalidSpec ErrorCode = C.GIT_EINVALIDSPEC
|
||||
// Merge conflicts prevented operation
|
||||
ErrMergeConflict ErrorCode = C.GIT_EMERGECONFLICT
|
||||
// Checkout conflicts prevented operation
|
||||
ErrConflict ErrorCode = C.GIT_ECONFLICT
|
||||
// Lock file prevented operation
|
||||
ErrLocked ErrorCode = C.GIT_ELOCKED
|
||||
// Reference value does not match expected
|
||||
|
|
42
index.go
42
index.go
|
@ -12,7 +12,6 @@ import "C"
|
|||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -31,13 +30,18 @@ type Index struct {
|
|||
ptr *C.git_index
|
||||
}
|
||||
|
||||
type IndexTime struct {
|
||||
seconds int32
|
||||
nanoseconds uint32
|
||||
}
|
||||
|
||||
type IndexEntry struct {
|
||||
Ctime time.Time
|
||||
Mtime time.Time
|
||||
Ctime IndexTime
|
||||
Mtime IndexTime
|
||||
Mode Filemode
|
||||
Uid uint
|
||||
Gid uint
|
||||
Size uint
|
||||
Uid uint32
|
||||
Gid uint32
|
||||
Size uint32
|
||||
Id *Oid
|
||||
Path string
|
||||
}
|
||||
|
@ -47,26 +51,26 @@ func newIndexEntryFromC(entry *C.git_index_entry) *IndexEntry {
|
|||
return nil
|
||||
}
|
||||
return &IndexEntry{
|
||||
time.Unix(int64(entry.ctime.seconds), int64(entry.ctime.nanoseconds)),
|
||||
time.Unix(int64(entry.mtime.seconds), int64(entry.mtime.nanoseconds)),
|
||||
IndexTime { int32(entry.ctime.seconds), uint32(entry.ctime.nanoseconds) },
|
||||
IndexTime { int32(entry.mtime.seconds), uint32(entry.mtime.nanoseconds) },
|
||||
Filemode(entry.mode),
|
||||
uint(entry.uid),
|
||||
uint(entry.gid),
|
||||
uint(entry.file_size),
|
||||
uint32(entry.uid),
|
||||
uint32(entry.gid),
|
||||
uint32(entry.file_size),
|
||||
newOidFromC(&entry.id),
|
||||
C.GoString(entry.path),
|
||||
}
|
||||
}
|
||||
|
||||
func populateCIndexEntry(source *IndexEntry, dest *C.git_index_entry) {
|
||||
dest.ctime.seconds = C.git_time_t(source.Ctime.Unix())
|
||||
dest.ctime.nanoseconds = C.uint(source.Ctime.UnixNano())
|
||||
dest.mtime.seconds = C.git_time_t(source.Mtime.Unix())
|
||||
dest.mtime.nanoseconds = C.uint(source.Mtime.UnixNano())
|
||||
dest.mode = C.uint(source.Mode)
|
||||
dest.uid = C.uint(source.Uid)
|
||||
dest.gid = C.uint(source.Gid)
|
||||
dest.file_size = C.git_off_t(source.Size)
|
||||
dest.ctime.seconds = C.int32_t(source.Ctime.seconds)
|
||||
dest.ctime.nanoseconds = C.uint32_t(source.Ctime.nanoseconds)
|
||||
dest.mtime.seconds = C.int32_t(source.Mtime.seconds)
|
||||
dest.mtime.nanoseconds = C.uint32_t(source.Mtime.nanoseconds)
|
||||
dest.mode = C.uint32_t(source.Mode)
|
||||
dest.uid = C.uint32_t(source.Uid)
|
||||
dest.gid = C.uint32_t(source.Gid)
|
||||
dest.file_size = C.uint32_t(source.Size)
|
||||
dest.id = *source.Id.toC()
|
||||
dest.path = C.CString(source.Path)
|
||||
}
|
||||
|
|
10
merge.go
10
merge.go
|
@ -85,8 +85,8 @@ const (
|
|||
)
|
||||
|
||||
type MergeOptions struct {
|
||||
Version uint
|
||||
Flags MergeTreeFlag
|
||||
Version uint
|
||||
TreeFlags MergeTreeFlag
|
||||
|
||||
RenameThreshold uint
|
||||
TargetLimit uint
|
||||
|
@ -98,7 +98,7 @@ type MergeOptions struct {
|
|||
func mergeOptionsFromC(opts *C.git_merge_options) MergeOptions {
|
||||
return MergeOptions{
|
||||
Version: uint(opts.version),
|
||||
Flags: MergeTreeFlag(opts.flags),
|
||||
TreeFlags: MergeTreeFlag(opts.tree_flags),
|
||||
RenameThreshold: uint(opts.rename_threshold),
|
||||
TargetLimit: uint(opts.target_limit),
|
||||
FileFavor: MergeFileFavor(opts.file_favor),
|
||||
|
@ -124,7 +124,7 @@ func (mo *MergeOptions) toC() *C.git_merge_options {
|
|||
}
|
||||
return &C.git_merge_options{
|
||||
version: C.uint(mo.Version),
|
||||
flags: C.git_merge_tree_flag_t(mo.Flags),
|
||||
tree_flags: C.git_merge_tree_flag_t(mo.TreeFlags),
|
||||
rename_threshold: C.uint(mo.RenameThreshold),
|
||||
target_limit: C.uint(mo.TargetLimit),
|
||||
file_favor: C.git_merge_file_favor_t(mo.FileFavor),
|
||||
|
@ -364,7 +364,7 @@ func populateCMergeFileOptions(c *C.git_merge_file_options, options MergeFileOpt
|
|||
c.our_label = C.CString(options.OurLabel)
|
||||
c.their_label = C.CString(options.TheirLabel)
|
||||
c.favor = C.git_merge_file_favor_t(options.Favor)
|
||||
c.flags = C.git_merge_file_flags_t(options.Flags)
|
||||
c.flags = C.uint(options.Flags)
|
||||
}
|
||||
|
||||
func freeCMergeFileOptions(c *C.git_merge_file_options) {
|
||||
|
|
|
@ -11,7 +11,7 @@ func TestMergeWithSelf(t *testing.T) {
|
|||
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
master, err := repo.LookupReference("refs/heads/master")
|
||||
master, err := repo.References.Lookup("refs/heads/master")
|
||||
checkFatal(t, err)
|
||||
|
||||
mergeHead, err := repo.AnnotatedCommitFromRef(master)
|
||||
|
@ -29,7 +29,7 @@ func TestMergeAnalysisWithSelf(t *testing.T) {
|
|||
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
master, err := repo.LookupReference("refs/heads/master")
|
||||
master, err := repo.References.Lookup("refs/heads/master")
|
||||
checkFatal(t, err)
|
||||
|
||||
mergeHead, err := repo.AnnotatedCommitFromRef(master)
|
||||
|
@ -109,7 +109,7 @@ func appendCommit(t *testing.T, repo *Repository) (*Oid, *Oid) {
|
|||
tree, err := repo.LookupTree(treeId)
|
||||
checkFatal(t, err)
|
||||
|
||||
ref, err := repo.LookupReference("HEAD")
|
||||
ref, err := repo.References.Lookup("HEAD")
|
||||
checkFatal(t, err)
|
||||
|
||||
parent, err := ref.Peel(ObjectCommit)
|
||||
|
|
121
note.go
121
note.go
|
@ -10,6 +10,127 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// This object represents the possible operations which can be
|
||||
// performed on the collection of notes for a repository.
|
||||
type NoteCollection struct {
|
||||
repo *Repository
|
||||
}
|
||||
|
||||
// Create adds a note for an object
|
||||
func (c *NoteCollection) Create(
|
||||
ref string, author, committer *Signature, id *Oid,
|
||||
note string, force bool) (*Oid, error) {
|
||||
|
||||
oid := new(Oid)
|
||||
|
||||
var cref *C.char
|
||||
if ref == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(ref)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
authorSig, err := author.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(authorSig)
|
||||
|
||||
committerSig, err := committer.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(committerSig)
|
||||
|
||||
cnote := C.CString(note)
|
||||
defer C.free(unsafe.Pointer(cnote))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_note_create(
|
||||
oid.toC(), c.repo.ptr, cref, authorSig,
|
||||
committerSig, id.toC(), cnote, cbool(force))
|
||||
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
return oid, nil
|
||||
}
|
||||
|
||||
// Read reads the note for an object
|
||||
func (c *NoteCollection) Read(ref string, id *Oid) (*Note, error) {
|
||||
var cref *C.char
|
||||
if ref == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(ref)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
note := new(Note)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if ret := C.git_note_read(¬e.ptr, c.repo.ptr, cref, id.toC()); ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(note, (*Note).Free)
|
||||
return note, nil
|
||||
}
|
||||
|
||||
// Remove removes the note for an object
|
||||
func (c *NoteCollection) Remove(ref string, author, committer *Signature, id *Oid) error {
|
||||
var cref *C.char
|
||||
if ref == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(ref)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
authorSig, err := author.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(authorSig)
|
||||
|
||||
committerSig, err := committer.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(committerSig)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_note_remove(c.repo.ptr, cref, authorSig, committerSig, id.toC())
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultRef returns the default notes reference for a repository
|
||||
func (c *NoteCollection) DefaultRef() (string, error) {
|
||||
buf := C.git_buf{}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if ret := C.git_note_default_ref(&buf, c.repo.ptr); ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
|
||||
ret := C.GoString(buf.ptr)
|
||||
C.git_buf_free(&buf)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Note
|
||||
type Note struct {
|
||||
ptr *C.git_note
|
||||
|
|
14
note_test.go
14
note_test.go
|
@ -53,7 +53,7 @@ func TestNoteIterator(t *testing.T) {
|
|||
break
|
||||
}
|
||||
|
||||
note, err := repo.ReadNote("", commitId)
|
||||
note, err := repo.Notes.Read("", commitId)
|
||||
checkFatal(t, err)
|
||||
|
||||
if !reflect.DeepEqual(note.Id(), noteId) {
|
||||
|
@ -73,13 +73,13 @@ func TestRemoveNote(t *testing.T) {
|
|||
|
||||
note, _ := createTestNote(t, repo, commit)
|
||||
|
||||
_, err = repo.ReadNote("", commit.Id())
|
||||
_, err = repo.Notes.Read("", commit.Id())
|
||||
checkFatal(t, err)
|
||||
|
||||
err = repo.RemoveNote("", note.Author(), note.Committer(), commitId)
|
||||
err = repo.Notes.Remove("", note.Author(), note.Committer(), commitId)
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.ReadNote("", commit.Id())
|
||||
_, err = repo.Notes.Read("", commit.Id())
|
||||
if err == nil {
|
||||
t.Fatal("note remove failed")
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func TestDefaultNoteRef(t *testing.T) {
|
|||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
ref, err := repo.DefaultNoteRef()
|
||||
ref, err := repo.Notes.DefaultRef()
|
||||
checkFatal(t, err)
|
||||
|
||||
compareStrings(t, "refs/notes/commits", ref)
|
||||
|
@ -103,10 +103,10 @@ func createTestNote(t *testing.T, repo *Repository, commit *Commit) (*Note, *Oid
|
|||
When: time.Date(2015, 01, 05, 13, 0, 0, 0, loc),
|
||||
}
|
||||
|
||||
noteId, err := repo.CreateNote("", sig, sig, commit.Id(), "I am a note\n", false)
|
||||
noteId, err := repo.Notes.Create("", sig, sig, commit.Id(), "I am a note\n", false)
|
||||
checkFatal(t, err)
|
||||
|
||||
note, err := repo.ReadNote("", commit.Id())
|
||||
note, err := repo.Notes.Read("", commit.Id())
|
||||
checkFatal(t, err)
|
||||
|
||||
return note, noteId
|
||||
|
|
26
object.go
26
object.go
|
@ -22,6 +22,7 @@ type Object interface {
|
|||
Id() *Oid
|
||||
Type() ObjectType
|
||||
Owner() *Repository
|
||||
Peel(t ObjectType) (Object, error)
|
||||
}
|
||||
|
||||
type gitObject struct {
|
||||
|
@ -69,6 +70,31 @@ func (o *gitObject) Free() {
|
|||
C.git_object_free(o.ptr)
|
||||
}
|
||||
|
||||
// Peel recursively peels an object until an object of the specified type is met.
|
||||
//
|
||||
// If the query cannot be satisfied due to the object model, ErrInvalidSpec
|
||||
// will be returned (e.g. trying to peel a blob to a tree).
|
||||
//
|
||||
// If you pass ObjectAny as the target type, then the object will be peeled
|
||||
// until the type changes. A tag will be peeled until the referenced object
|
||||
// is no longer a tag, and a commit will be peeled to a tree. Any other object
|
||||
// type will return ErrInvalidSpec.
|
||||
//
|
||||
// If peeling a tag we discover an object which cannot be peeled to the target
|
||||
// type due to the object model, an error will be returned.
|
||||
func (o *gitObject) Peel(t ObjectType) (Object, error) {
|
||||
var cobj *C.git_object
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if err := C.git_object_peel(&cobj, o.ptr, C.git_otype(t)); err < 0 {
|
||||
return nil, MakeGitError(err)
|
||||
}
|
||||
|
||||
return allocObject(cobj, o.repo), nil
|
||||
}
|
||||
|
||||
func allocObject(cobj *C.git_object, repo *Repository) Object {
|
||||
obj := gitObject{
|
||||
ptr: cobj,
|
||||
|
|
|
@ -102,3 +102,63 @@ func TestObjectOwner(t *testing.T) {
|
|||
checkOwner(t, repo, commit)
|
||||
checkOwner(t, repo, tree)
|
||||
}
|
||||
|
||||
func TestObjectPeel(t *testing.T) {
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
commitID, treeID := seedTestRepo(t, repo)
|
||||
|
||||
var obj Object
|
||||
|
||||
commit, err := repo.LookupCommit(commitID)
|
||||
checkFatal(t, err)
|
||||
|
||||
obj, err = commit.Peel(ObjectAny)
|
||||
checkFatal(t, err)
|
||||
|
||||
if obj.Type() != ObjectTree {
|
||||
t.Fatalf("Wrong object type when peeling a commit, expected tree, have %v", obj.Type())
|
||||
}
|
||||
|
||||
obj, err = commit.Peel(ObjectTag)
|
||||
|
||||
if !IsErrorCode(err, ErrInvalidSpec) {
|
||||
t.Fatalf("Wrong error when peeling a commit to a tag, expected ErrInvalidSpec, have %v", err)
|
||||
}
|
||||
|
||||
tree, err := repo.LookupTree(treeID)
|
||||
checkFatal(t, err)
|
||||
|
||||
obj, err = tree.Peel(ObjectAny)
|
||||
|
||||
if !IsErrorCode(err, ErrInvalidSpec) {
|
||||
t.Fatalf("Wrong error when peeling a tree, expected ErrInvalidSpec, have %v", err)
|
||||
}
|
||||
|
||||
entry := tree.EntryByName("README")
|
||||
|
||||
blob, err := repo.LookupBlob(entry.Id)
|
||||
checkFatal(t, err)
|
||||
|
||||
obj, err = blob.Peel(ObjectAny)
|
||||
|
||||
if !IsErrorCode(err, ErrInvalidSpec) {
|
||||
t.Fatalf("Wrong error when peeling a blob, expected ErrInvalidSpec, have %v", err)
|
||||
}
|
||||
|
||||
tagID := createTestTag(t, repo, commit)
|
||||
|
||||
tag, err := repo.LookupTag(tagID)
|
||||
checkFatal(t, err)
|
||||
|
||||
obj, err = tag.Peel(ObjectAny)
|
||||
checkFatal(t, err)
|
||||
|
||||
if obj.Type() != ObjectCommit {
|
||||
t.Fatalf("Wrong object type when peeling a tag, expected commit, have %v", obj.Type())
|
||||
}
|
||||
|
||||
// TODO: Should test a tag that annotates a different object than a commit
|
||||
// but it's impossible at the moment to tag such an object.
|
||||
}
|
||||
|
|
8
odb.go
8
odb.go
|
@ -11,6 +11,7 @@ import (
|
|||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Odb struct {
|
||||
|
@ -106,7 +107,9 @@ func odbForEachCb(id *C.git_oid, handle unsafe.Pointer) int {
|
|||
}
|
||||
|
||||
err := data.callback(newOidFromC(id))
|
||||
fmt.Println("err %v", err)
|
||||
if err != nil {
|
||||
fmt.Println("returning EUSER")
|
||||
data.err = err
|
||||
return C.GIT_EUSER
|
||||
}
|
||||
|
@ -127,6 +130,7 @@ func (v *Odb) ForEach(callback OdbForEachCallback) error {
|
|||
defer pointerHandles.Untrack(handle)
|
||||
|
||||
ret := C._go_git_odb_foreach(v.ptr, handle)
|
||||
fmt.Println("ret %v", ret);
|
||||
if ret == C.GIT_EUSER {
|
||||
return data.err
|
||||
} else if ret < 0 {
|
||||
|
@ -172,13 +176,13 @@ func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
|
|||
// NewWriteStream opens a write stream to the ODB, which allows you to
|
||||
// create a new object in the database. The size and type must be
|
||||
// known in advance
|
||||
func (v *Odb) NewWriteStream(size int, otype ObjectType) (*OdbWriteStream, error) {
|
||||
func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, error) {
|
||||
stream := new(OdbWriteStream)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.size_t(size), C.git_otype(otype))
|
||||
ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_off_t(size), C.git_otype(otype))
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestOdbStream(t *testing.T) {
|
|||
|
||||
str := "hello, world!"
|
||||
|
||||
stream, error := odb.NewWriteStream(len(str), ObjectBlob)
|
||||
stream, error := odb.NewWriteStream(int64(len(str)), ObjectBlob)
|
||||
checkFatal(t, error)
|
||||
n, error := io.WriteString(stream, str)
|
||||
checkFatal(t, error)
|
||||
|
|
|
@ -11,17 +11,17 @@ func TestRemotePush(t *testing.T) {
|
|||
localRepo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, localRepo)
|
||||
|
||||
remote, err := localRepo.CreateRemote("test_push", repo.Path())
|
||||
remote, err := localRepo.Remotes.Create("test_push", repo.Path())
|
||||
checkFatal(t, err)
|
||||
|
||||
seedTestRepo(t, localRepo)
|
||||
|
||||
err = remote.Push([]string{"refs/heads/master"}, nil, nil, "")
|
||||
err = remote.Push([]string{"refs/heads/master"}, nil)
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = localRepo.LookupReference("refs/remotes/test_push/master")
|
||||
_, err = localRepo.References.Lookup("refs/remotes/test_push/master")
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.LookupReference("refs/heads/master")
|
||||
_, err = repo.References.Lookup("refs/heads/master")
|
||||
checkFatal(t, err)
|
||||
}
|
||||
|
|
178
reference.go
178
reference.go
|
@ -21,13 +21,137 @@ type Reference struct {
|
|||
repo *Repository
|
||||
}
|
||||
|
||||
type ReferenceCollection struct {
|
||||
repo *Repository
|
||||
}
|
||||
|
||||
func (c *ReferenceCollection) Lookup(name string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_reference_lookup(&ptr, c.repo.ptr, cname)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, c.repo), nil
|
||||
}
|
||||
|
||||
func (c *ReferenceCollection) Create(name string, id *Oid, force bool, msg string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_reference_create(&ptr, c.repo.ptr, cname, id.toC(), cbool(force), cmsg)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, c.repo), nil
|
||||
}
|
||||
|
||||
func (c *ReferenceCollection) CreateSymbolic(name, target string, force bool, msg string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
ctarget := C.CString(target)
|
||||
defer C.free(unsafe.Pointer(ctarget))
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_reference_symbolic_create(&ptr, c.repo.ptr, cname, ctarget, cbool(force), cmsg)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, c.repo), nil
|
||||
}
|
||||
|
||||
// EnsureLog ensures that there is a reflog for the given reference
|
||||
// name and creates an empty one if necessary.
|
||||
func (c *ReferenceCollection) EnsureLog(name string) error {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_reference_ensure_log(c.repo.ptr, cname)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasLog returns whether there is a reflog for the given reference
|
||||
// name
|
||||
func (c *ReferenceCollection) HasLog(name string) (bool, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_reference_has_log(c.repo.ptr, cname)
|
||||
if ret < 0 {
|
||||
return false, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return ret == 1, nil
|
||||
}
|
||||
|
||||
// Dwim looks up a reference by DWIMing its short name
|
||||
func (c *ReferenceCollection) Dwim(name string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var ptr *C.git_reference
|
||||
ret := C.git_reference_dwim(&ptr, c.repo.ptr, cname)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, c.repo), nil
|
||||
}
|
||||
|
||||
func newReferenceFromC(ptr *C.git_reference, repo *Repository) *Reference {
|
||||
ref := &Reference{ptr: ptr, repo: repo}
|
||||
runtime.SetFinalizer(ref, (*Reference).Free)
|
||||
return ref
|
||||
}
|
||||
|
||||
func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string) (*Reference, error) {
|
||||
func (v *Reference) SetSymbolicTarget(target string, msg string) (*Reference, error) {
|
||||
var ptr *C.git_reference
|
||||
|
||||
ctarget := C.CString(target)
|
||||
|
@ -36,12 +160,6 @@ func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string)
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
|
@ -50,7 +168,7 @@ func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string)
|
|||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, csig, cmsg)
|
||||
ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, cmsg)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -58,18 +176,12 @@ func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string)
|
|||
return newReferenceFromC(ptr, v.repo), nil
|
||||
}
|
||||
|
||||
func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Reference, error) {
|
||||
func (v *Reference) SetTarget(target *Oid, msg string) (*Reference, error) {
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
|
@ -78,7 +190,7 @@ func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Referen
|
|||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), csig, cmsg)
|
||||
ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), cmsg)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -100,17 +212,11 @@ func (v *Reference) Resolve() (*Reference, error) {
|
|||
return newReferenceFromC(ptr, v.repo), nil
|
||||
}
|
||||
|
||||
func (v *Reference) Rename(name string, force bool, sig *Signature, msg string) (*Reference, error) {
|
||||
func (v *Reference) Rename(name string, force bool, msg string) (*Reference, error) {
|
||||
var ptr *C.git_reference
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
|
@ -122,7 +228,7 @@ func (v *Reference) Rename(name string, force bool, sig *Signature, msg string)
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force), csig, cmsg)
|
||||
ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force), cmsg)
|
||||
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
|
@ -209,6 +315,11 @@ 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)
|
||||
|
@ -319,3 +430,22 @@ 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
|
||||
}
|
||||
|
|
|
@ -13,21 +13,14 @@ func TestRefModification(t *testing.T) {
|
|||
|
||||
commitId, treeId := seedTestRepo(t, repo)
|
||||
|
||||
loc, err := time.LoadLocation("Europe/Berlin")
|
||||
checkFatal(t, err)
|
||||
sig := &Signature{
|
||||
Name: "Rand Om Hacker",
|
||||
Email: "random@hacker.com",
|
||||
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
|
||||
}
|
||||
_, err = repo.CreateReference("refs/tags/tree", treeId, true, sig, "testTreeTag")
|
||||
_, err := repo.References.Create("refs/tags/tree", treeId, true, "testTreeTag")
|
||||
checkFatal(t, err)
|
||||
|
||||
tag, err := repo.LookupReference("refs/tags/tree")
|
||||
tag, err := repo.References.Lookup("refs/tags/tree")
|
||||
checkFatal(t, err)
|
||||
checkRefType(t, tag, ReferenceOid)
|
||||
|
||||
ref, err := repo.LookupReference("HEAD")
|
||||
ref, err := repo.References.Lookup("HEAD")
|
||||
checkFatal(t, err)
|
||||
checkRefType(t, ref, ReferenceSymbolic)
|
||||
|
||||
|
@ -51,9 +44,9 @@ func TestRefModification(t *testing.T) {
|
|||
t.Fatalf("Wrong ref target")
|
||||
}
|
||||
|
||||
_, err = tag.Rename("refs/tags/renamed", false, nil, "")
|
||||
_, err = tag.Rename("refs/tags/renamed", false, "")
|
||||
checkFatal(t, err)
|
||||
tag, err = repo.LookupReference("refs/tags/renamed")
|
||||
tag, err = repo.References.Lookup("refs/tags/renamed")
|
||||
checkFatal(t, err)
|
||||
checkRefType(t, ref, ReferenceOid)
|
||||
|
||||
|
@ -84,13 +77,13 @@ func TestReferenceIterator(t *testing.T) {
|
|||
commitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree)
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.CreateReference("refs/heads/one", commitId, true, sig, "headOne")
|
||||
_, err = repo.References.Create("refs/heads/one", commitId, true, "headOne")
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.CreateReference("refs/heads/two", commitId, true, sig, "headTwo")
|
||||
_, err = repo.References.Create("refs/heads/two", commitId, true, "headTwo")
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.CreateReference("refs/heads/three", commitId, true, sig, "headThree")
|
||||
_, err = repo.References.Create("refs/heads/three", commitId, true, "headThree")
|
||||
checkFatal(t, err)
|
||||
|
||||
iter, err := repo.NewReferenceIterator()
|
||||
|
@ -143,7 +136,7 @@ func TestReferenceOwner(t *testing.T) {
|
|||
|
||||
commitId, _ := seedTestRepo(t, repo)
|
||||
|
||||
ref, err := repo.CreateReference("refs/heads/foo", commitId, true, nil, "")
|
||||
ref, err := repo.References.Create("refs/heads/foo", commitId, true, "")
|
||||
checkFatal(t, err)
|
||||
|
||||
owner := ref.Owner()
|
||||
|
@ -162,10 +155,10 @@ func TestUtil(t *testing.T) {
|
|||
|
||||
commitId, _ := seedTestRepo(t, repo)
|
||||
|
||||
ref, err := repo.CreateReference("refs/heads/foo", commitId, true, nil, "")
|
||||
ref, err := repo.References.Create("refs/heads/foo", commitId, true, "")
|
||||
checkFatal(t, err)
|
||||
|
||||
ref2, err := repo.DwimReference("foo")
|
||||
ref2, err := repo.References.Dwim("foo")
|
||||
checkFatal(t, err)
|
||||
|
||||
if ref.Cmp(ref2) != 0 {
|
||||
|
@ -176,13 +169,55 @@ func TestUtil(t *testing.T) {
|
|||
t.Fatalf("refs/heads/foo has no foo shorthand")
|
||||
}
|
||||
|
||||
hasLog, err := repo.HasLog("refs/heads/foo")
|
||||
hasLog, err := repo.References.HasLog("refs/heads/foo")
|
||||
checkFatal(t, err)
|
||||
if !hasLog {
|
||||
t.Fatalf("branches have logs by default")
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
284
remote.go
284
remote.go
|
@ -69,6 +69,51 @@ type RemoteCallbacks struct {
|
|||
PushUpdateReferenceCallback
|
||||
}
|
||||
|
||||
type FetchPrune uint
|
||||
|
||||
const (
|
||||
// Use the setting from the configuration
|
||||
FetchPruneUnspecified FetchPrune = C.GIT_FETCH_PRUNE_UNSPECIFIED
|
||||
// Force pruning on
|
||||
FetchPruneOn FetchPrune = C.GIT_FETCH_PRUNE
|
||||
// Force pruning off
|
||||
FetchNoPrune FetchPrune = C.GIT_FETCH_NO_PRUNE
|
||||
)
|
||||
|
||||
type DownloadTags uint
|
||||
|
||||
const (
|
||||
|
||||
// Use the setting from the configuration.
|
||||
DownloadTagsUnspecified DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED
|
||||
// Ask the server for tags pointing to objects we're already
|
||||
// downloading.
|
||||
DownloadTagsAuto DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_AUTO
|
||||
|
||||
// Don't ask for any tags beyond the refspecs.
|
||||
DownloadTagsNone DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_NONE
|
||||
|
||||
// Ask for the all the tags.
|
||||
DownloadTagsAll DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_ALL
|
||||
)
|
||||
|
||||
type FetchOptions struct {
|
||||
// Callbacks to use for this fetch operation
|
||||
RemoteCallbacks RemoteCallbacks
|
||||
// Whether to perform a prune after the fetch
|
||||
Prune FetchPrune
|
||||
// Whether to write the results to FETCH_HEAD. Defaults to
|
||||
// on. Leave this default in order to behave like git.
|
||||
UpdateFetchhead bool
|
||||
|
||||
// Determines how to behave regarding tags on the remote, such
|
||||
// as auto-downloading tags for objects we're downloading or
|
||||
// downloading all of them.
|
||||
//
|
||||
// The default is to auto-follow tags.
|
||||
DownloadTags DownloadTags
|
||||
}
|
||||
|
||||
type Remote struct {
|
||||
ptr *C.git_remote
|
||||
callbacks RemoteCallbacks
|
||||
|
@ -108,6 +153,9 @@ type HostkeyCertificate struct {
|
|||
}
|
||||
|
||||
type PushOptions struct {
|
||||
// Callbacks to use for this push operation
|
||||
RemoteCallbacks RemoteCallbacks
|
||||
|
||||
PbParallelism uint
|
||||
}
|
||||
|
||||
|
@ -123,6 +171,12 @@ func newRemoteHeadFromC(ptr *C.git_remote_head) RemoteHead {
|
|||
}
|
||||
}
|
||||
|
||||
func untrackCalbacksPayload(callbacks *C.git_remote_callbacks) {
|
||||
if callbacks != nil && callbacks.payload != nil {
|
||||
pointerHandles.Untrack(callbacks.payload)
|
||||
}
|
||||
}
|
||||
|
||||
func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
|
||||
C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
|
||||
if callbacks == nil {
|
||||
|
@ -160,7 +214,9 @@ func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C
|
|||
url := C.GoString(_url)
|
||||
username_from_url := C.GoString(_username_from_url)
|
||||
ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
|
||||
*_cred = cred.ptr
|
||||
if cred != nil {
|
||||
*_cred = cred.ptr
|
||||
}
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
|
@ -267,41 +323,22 @@ func RemoteIsValidName(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (r *Remote) SetCallbacks(callbacks *RemoteCallbacks) error {
|
||||
r.callbacks = *callbacks
|
||||
|
||||
var ccallbacks C.git_remote_callbacks
|
||||
populateRemoteCallbacks(&ccallbacks, &r.callbacks)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_remote_set_callbacks(r.ptr, &ccallbacks)
|
||||
if ecode < 0 {
|
||||
return MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Remote) Free() {
|
||||
runtime.SetFinalizer(r, nil)
|
||||
|
||||
callbacks := C.git_remote_get_callbacks(r.ptr)
|
||||
if callbacks != nil && callbacks.payload != nil {
|
||||
pointerHandles.Untrack(callbacks.payload)
|
||||
}
|
||||
|
||||
C.git_remote_free(r.ptr)
|
||||
}
|
||||
|
||||
func (repo *Repository) ListRemotes() ([]string, error) {
|
||||
type RemoteCollection struct {
|
||||
repo *Repository
|
||||
}
|
||||
|
||||
func (c *RemoteCollection) List() ([]string, error) {
|
||||
var r C.git_strarray
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_remote_list(&r, repo.ptr)
|
||||
ecode := C.git_remote_list(&r, c.repo.ptr)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
@ -311,7 +348,7 @@ func (repo *Repository) ListRemotes() ([]string, error) {
|
|||
return remotes, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
|
||||
func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
|
||||
remote := &Remote{}
|
||||
|
||||
cname := C.CString(name)
|
||||
|
@ -322,7 +359,7 @@ func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_create(&remote.ptr, repo.ptr, cname, curl)
|
||||
ret := C.git_remote_create(&remote.ptr, c.repo.ptr, cname, curl)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -330,21 +367,21 @@ func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
|
|||
return remote, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) DeleteRemote(name string) error {
|
||||
func (c *RemoteCollection) Delete(name string) error {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_delete(repo.ptr, cname)
|
||||
ret := C.git_remote_delete(c.repo.ptr, cname)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) {
|
||||
func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch string) (*Remote, error) {
|
||||
remote := &Remote{}
|
||||
|
||||
cname := C.CString(name)
|
||||
|
@ -357,7 +394,7 @@ func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_create_with_fetchspec(&remote.ptr, repo.ptr, cname, curl, cfetch)
|
||||
ret := C.git_remote_create_with_fetchspec(&remote.ptr, c.repo.ptr, cname, curl, cfetch)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -365,18 +402,16 @@ func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch
|
|||
return remote, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) CreateAnonymousRemote(url, fetch string) (*Remote, error) {
|
||||
func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
|
||||
remote := &Remote{}
|
||||
|
||||
curl := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(curl))
|
||||
cfetch := C.CString(fetch)
|
||||
defer C.free(unsafe.Pointer(cfetch))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_create_anonymous(&remote.ptr, repo.ptr, curl, cfetch)
|
||||
ret := C.git_remote_create_anonymous(&remote.ptr, c.repo.ptr, curl)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -384,7 +419,7 @@ func (repo *Repository) CreateAnonymousRemote(url, fetch string) (*Remote, error
|
|||
return remote, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) LookupRemote(name string) (*Remote, error) {
|
||||
func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
|
||||
remote := &Remote{}
|
||||
|
||||
cname := C.CString(name)
|
||||
|
@ -393,7 +428,7 @@ func (repo *Repository) LookupRemote(name string) (*Remote, error) {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_lookup(&remote.ptr, repo.ptr, cname)
|
||||
ret := C.git_remote_lookup(&remote.ptr, c.repo.ptr, cname)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -401,22 +436,6 @@ func (repo *Repository) LookupRemote(name string) (*Remote, error) {
|
|||
return remote, nil
|
||||
}
|
||||
|
||||
func (o *Remote) Save() error {
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_save(o.ptr)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Remote) Owner() Repository {
|
||||
return Repository{C.git_remote_owner(o.ptr)}
|
||||
}
|
||||
|
||||
func (o *Remote) Name() string {
|
||||
return C.GoString(C.git_remote_name(o.ptr))
|
||||
}
|
||||
|
@ -429,42 +448,48 @@ func (o *Remote) PushUrl() string {
|
|||
return C.GoString(C.git_remote_pushurl(o.ptr))
|
||||
}
|
||||
|
||||
func (o *Remote) SetUrl(url string) error {
|
||||
func (c *RemoteCollection) SetUrl(remote, url string) error {
|
||||
curl := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(curl))
|
||||
cremote := C.CString(remote)
|
||||
defer C.free(unsafe.Pointer(cremote))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_set_url(o.ptr, curl)
|
||||
ret := C.git_remote_set_url(c.repo.ptr, cremote, curl)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Remote) SetPushUrl(url string) error {
|
||||
func (c *RemoteCollection) SetPushUrl(remote, url string) error {
|
||||
curl := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(curl))
|
||||
cremote := C.CString(remote)
|
||||
defer C.free(unsafe.Pointer(cremote))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_set_pushurl(o.ptr, curl)
|
||||
ret := C.git_remote_set_pushurl(c.repo.ptr, cremote, curl)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Remote) AddFetch(refspec string) error {
|
||||
func (c *RemoteCollection) AddFetch(remote, refspec string) error {
|
||||
crefspec := C.CString(refspec)
|
||||
defer C.free(unsafe.Pointer(crefspec))
|
||||
cremote := C.CString(remote)
|
||||
defer C.free(unsafe.Pointer(cremote))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_add_fetch(o.ptr, crefspec)
|
||||
ret := C.git_remote_add_fetch(c.repo.ptr, cremote, crefspec)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
@ -525,30 +550,16 @@ func (o *Remote) FetchRefspecs() ([]string, error) {
|
|||
return refspecs, nil
|
||||
}
|
||||
|
||||
func (o *Remote) SetFetchRefspecs(refspecs []string) error {
|
||||
crefspecs := C.git_strarray{}
|
||||
crefspecs.count = C.size_t(len(refspecs))
|
||||
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
||||
defer freeStrarray(&crefspecs)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_set_fetch_refspecs(o.ptr, &crefspecs)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Remote) AddPush(refspec string) error {
|
||||
func (c *RemoteCollection) AddPush(remote, refspec string) error {
|
||||
crefspec := C.CString(refspec)
|
||||
defer C.free(unsafe.Pointer(crefspec))
|
||||
cremote := C.CString(remote)
|
||||
defer C.free(unsafe.Pointer(cremote))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_add_push(o.ptr, crefspec)
|
||||
ret := C.git_remote_add_push(c.repo.ptr, cremote, crefspec)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
@ -570,53 +581,37 @@ func (o *Remote) PushRefspecs() ([]string, error) {
|
|||
return refspecs, nil
|
||||
}
|
||||
|
||||
func (o *Remote) SetPushRefspecs(refspecs []string) error {
|
||||
crefspecs := C.git_strarray{}
|
||||
crefspecs.count = C.size_t(len(refspecs))
|
||||
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
||||
defer freeStrarray(&crefspecs)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_set_push_refspecs(o.ptr, &crefspecs)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Remote) ClearRefspecs() {
|
||||
C.git_remote_clear_refspecs(o.ptr)
|
||||
}
|
||||
|
||||
func (o *Remote) RefspecCount() uint {
|
||||
return uint(C.git_remote_refspec_count(o.ptr))
|
||||
}
|
||||
|
||||
func (o *Remote) SetUpdateFetchHead(val bool) {
|
||||
C.git_remote_set_update_fetchhead(o.ptr, cbool(val))
|
||||
func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
|
||||
C.git_fetch_init_options(options, C.GIT_FETCH_OPTIONS_VERSION)
|
||||
if opts == nil {
|
||||
return;
|
||||
}
|
||||
populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
|
||||
options.prune = C.git_fetch_prune_t(opts.Prune)
|
||||
options.update_fetchhead = cbool(opts.UpdateFetchhead)
|
||||
options.download_tags = C.git_remote_autotag_option_t(opts.DownloadTags)
|
||||
}
|
||||
|
||||
func (o *Remote) UpdateFetchHead() bool {
|
||||
return C.git_remote_update_fetchhead(o.ptr) > 0
|
||||
func populatePushOptions(options *C.git_push_options, opts *PushOptions) {
|
||||
C.git_push_init_options(options, C.GIT_PUSH_OPTIONS_VERSION)
|
||||
if opts == nil {
|
||||
return
|
||||
}
|
||||
|
||||
options.pb_parallelism = C.uint(opts.PbParallelism)
|
||||
|
||||
populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
|
||||
}
|
||||
|
||||
// Fetch performs a fetch operation. refspecs specifies which refspecs
|
||||
// to use for this fetch, use an empty list to use the refspecs from
|
||||
// the configuration; sig and msg specify what to use for the reflog
|
||||
// entries. Leave nil and "" to use defaults.
|
||||
func (o *Remote) Fetch(refspecs []string, sig *Signature, msg string) error {
|
||||
|
||||
var csig *C.git_signature = nil
|
||||
if sig != nil {
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
}
|
||||
|
||||
// the configuration; msg specifies what to use for the reflog
|
||||
// entries. Leave "" to use defaults.
|
||||
func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error {
|
||||
var cmsg *C.char = nil
|
||||
if msg != "" {
|
||||
cmsg = C.CString(msg)
|
||||
|
@ -628,29 +623,36 @@ func (o *Remote) Fetch(refspecs []string, sig *Signature, msg string) error {
|
|||
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
||||
defer freeStrarray(&crefspecs)
|
||||
|
||||
var coptions C.git_fetch_options
|
||||
populateFetchOptions(&coptions, opts);
|
||||
defer untrackCalbacksPayload(&coptions.callbacks)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_fetch(o.ptr, &crefspecs, csig, cmsg)
|
||||
ret := C.git_remote_fetch(o.ptr, &crefspecs, &coptions, cmsg)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Remote) ConnectFetch() error {
|
||||
return o.Connect(ConnectDirectionFetch)
|
||||
func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks) error {
|
||||
return o.Connect(ConnectDirectionFetch, callbacks)
|
||||
}
|
||||
|
||||
func (o *Remote) ConnectPush() error {
|
||||
return o.Connect(ConnectDirectionPush)
|
||||
func (o *Remote) ConnectPush(callbacks *RemoteCallbacks) error {
|
||||
return o.Connect(ConnectDirectionPush, callbacks)
|
||||
}
|
||||
|
||||
func (o *Remote) Connect(direction ConnectDirection) error {
|
||||
func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks) error {
|
||||
var ccallbacks C.git_remote_callbacks;
|
||||
populateRemoteCallbacks(&ccallbacks, callbacks)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if ret := C.git_remote_connect(o.ptr, C.git_direction(direction)); ret != 0 {
|
||||
if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks); ret != 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
|
@ -702,39 +704,20 @@ func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
|
|||
return heads, nil
|
||||
}
|
||||
|
||||
func (o *Remote) Push(refspecs []string, opts *PushOptions, sig *Signature, msg string) error {
|
||||
var csig *C.git_signature = nil
|
||||
if sig != nil {
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
}
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
var copts C.git_push_options
|
||||
C.git_push_init_options(&copts, C.GIT_PUSH_OPTIONS_VERSION)
|
||||
if opts != nil {
|
||||
copts.pb_parallelism = C.uint(opts.PbParallelism)
|
||||
}
|
||||
|
||||
func (o *Remote) Push(refspecs []string, opts *PushOptions) error {
|
||||
crefspecs := C.git_strarray{}
|
||||
crefspecs.count = C.size_t(len(refspecs))
|
||||
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
||||
defer freeStrarray(&crefspecs)
|
||||
|
||||
var coptions C.git_push_options
|
||||
populatePushOptions(&coptions, opts)
|
||||
defer untrackCalbacksPayload(&coptions.callbacks)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_push(o.ptr, &crefspecs, &copts, csig, cmsg)
|
||||
ret := C.git_remote_push(o.ptr, &crefspecs, &coptions)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
@ -745,11 +728,14 @@ func (o *Remote) PruneRefs() bool {
|
|||
return C.git_remote_prune_refs(o.ptr) > 0
|
||||
}
|
||||
|
||||
func (o *Remote) Prune() error {
|
||||
func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
|
||||
var ccallbacks C.git_remote_callbacks;
|
||||
populateRemoteCallbacks(&ccallbacks, callbacks)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_remote_prune(o.ptr)
|
||||
ret := C.git_remote_prune(o.ptr, &ccallbacks)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
|
|
@ -3,35 +3,13 @@ package git
|
|||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRefspecs(t *testing.T) {
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
remote, err := repo.CreateAnonymousRemote("git://foo/bar", "refs/heads/*:refs/heads/*")
|
||||
checkFatal(t, err)
|
||||
|
||||
expected := []string{
|
||||
"refs/heads/*:refs/remotes/origin/*",
|
||||
"refs/pull/*/head:refs/remotes/origin/*",
|
||||
}
|
||||
|
||||
err = remote.SetFetchRefspecs(expected)
|
||||
checkFatal(t, err)
|
||||
|
||||
actual, err := remote.FetchRefspecs()
|
||||
checkFatal(t, err)
|
||||
|
||||
compareStringList(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestListRemotes(t *testing.T) {
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
_, err := repo.CreateRemote("test", "git://foo/bar")
|
||||
_, err := repo.Remotes.Create("test", "git://foo/bar")
|
||||
|
||||
checkFatal(t, err)
|
||||
|
||||
|
@ -39,7 +17,7 @@ func TestListRemotes(t *testing.T) {
|
|||
"test",
|
||||
}
|
||||
|
||||
actual, err := repo.ListRemotes()
|
||||
actual, err := repo.Remotes.List()
|
||||
checkFatal(t, err)
|
||||
|
||||
compareStringList(t, expected, actual)
|
||||
|
@ -58,18 +36,18 @@ func TestCertificateCheck(t *testing.T) {
|
|||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
remote, err := repo.CreateRemote("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
checkFatal(t, err)
|
||||
|
||||
callbacks := RemoteCallbacks{
|
||||
CertificateCheckCallback: func(cert *Certificate, valid bool, hostname string) ErrorCode {
|
||||
return assertHostname(cert, valid, hostname, t)
|
||||
options := FetchOptions {
|
||||
RemoteCallbacks: RemoteCallbacks{
|
||||
CertificateCheckCallback: func(cert *Certificate, valid bool, hostname string) ErrorCode {
|
||||
return assertHostname(cert, valid, hostname, t)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = remote.SetCallbacks(&callbacks)
|
||||
checkFatal(t, err)
|
||||
err = remote.Fetch([]string{}, nil, "")
|
||||
err = remote.Fetch([]string{}, &options, "")
|
||||
checkFatal(t, err)
|
||||
}
|
||||
|
||||
|
@ -77,10 +55,10 @@ func TestRemoteConnect(t *testing.T) {
|
|||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
remote, err := repo.CreateRemote("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
checkFatal(t, err)
|
||||
|
||||
err = remote.ConnectFetch()
|
||||
err = remote.ConnectFetch(nil)
|
||||
checkFatal(t, err)
|
||||
}
|
||||
|
||||
|
@ -88,10 +66,10 @@ func TestRemoteLs(t *testing.T) {
|
|||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
remote, err := repo.CreateRemote("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
checkFatal(t, err)
|
||||
|
||||
err = remote.ConnectFetch()
|
||||
err = remote.ConnectFetch(nil)
|
||||
checkFatal(t, err)
|
||||
|
||||
heads, err := remote.Ls()
|
||||
|
@ -106,10 +84,10 @@ func TestRemoteLsFiltering(t *testing.T) {
|
|||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
remote, err := repo.CreateRemote("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
checkFatal(t, err)
|
||||
|
||||
err = remote.ConnectFetch()
|
||||
err = remote.ConnectFetch(nil)
|
||||
checkFatal(t, err)
|
||||
|
||||
heads, err := remote.Ls("master")
|
||||
|
@ -139,10 +117,10 @@ func TestRemotePruneRefs(t *testing.T) {
|
|||
err = config.SetBool("remote.origin.prune", true)
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.CreateRemote("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
_, err = repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
|
||||
checkFatal(t, err)
|
||||
|
||||
remote, err := repo.LookupRemote("origin")
|
||||
remote, err := repo.Remotes.Lookup("origin")
|
||||
checkFatal(t, err)
|
||||
|
||||
if !remote.PruneRefs() {
|
||||
|
@ -159,13 +137,7 @@ func TestRemotePrune(t *testing.T) {
|
|||
checkFatal(t, err)
|
||||
defer commit.Free()
|
||||
|
||||
sig := &Signature{
|
||||
Name: "Rand Om Hacker",
|
||||
Email: "random@hacker.com",
|
||||
When: time.Now(),
|
||||
}
|
||||
|
||||
remoteRef, err := remoteRepo.CreateBranch("test-prune", commit, true, sig, "branch test-prune")
|
||||
remoteRef, err := remoteRepo.CreateBranch("test-prune", commit, true)
|
||||
checkFatal(t, err)
|
||||
|
||||
repo := createTestRepo(t)
|
||||
|
@ -176,13 +148,13 @@ func TestRemotePrune(t *testing.T) {
|
|||
defer config.Free()
|
||||
|
||||
remoteUrl := fmt.Sprintf("file://%s", remoteRepo.Workdir())
|
||||
remote, err := repo.CreateRemote("origin", remoteUrl)
|
||||
remote, err := repo.Remotes.Create("origin", remoteUrl)
|
||||
checkFatal(t, err)
|
||||
|
||||
err = remote.Fetch([]string{"test-prune"}, sig, "")
|
||||
err = remote.Fetch([]string{"test-prune"}, nil, "")
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.CreateReference("refs/remotes/origin/test-prune", head, true, sig, "remote reference")
|
||||
_, err = repo.References.Create("refs/remotes/origin/test-prune", head, true, "remote reference")
|
||||
checkFatal(t, err)
|
||||
|
||||
err = remoteRef.Delete()
|
||||
|
@ -191,16 +163,16 @@ func TestRemotePrune(t *testing.T) {
|
|||
err = config.SetBool("remote.origin.prune", true)
|
||||
checkFatal(t, err)
|
||||
|
||||
rr, err := repo.LookupRemote("origin")
|
||||
rr, err := repo.Remotes.Lookup("origin")
|
||||
checkFatal(t, err)
|
||||
|
||||
err = rr.ConnectFetch()
|
||||
err = rr.ConnectFetch(nil)
|
||||
checkFatal(t, err)
|
||||
|
||||
err = rr.Prune()
|
||||
err = rr.Prune(nil)
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = repo.LookupReference("refs/remotes/origin/test-prune")
|
||||
_, err = repo.References.Lookup("refs/remotes/origin/test-prune")
|
||||
if err == nil {
|
||||
t.Fatal("Expected error getting a pruned reference")
|
||||
}
|
||||
|
|
371
repository.go
371
repository.go
|
@ -12,76 +12,99 @@ import (
|
|||
|
||||
// Repository
|
||||
type Repository struct {
|
||||
ptr *C.git_repository
|
||||
ptr *C.git_repository
|
||||
// Remotes represents the collection of remotes and can be
|
||||
// used to add, remove and configure remotes for this
|
||||
// repository.
|
||||
Remotes RemoteCollection
|
||||
// Submodules represents the collection of submodules and can
|
||||
// be used to add, remove and configure submodules in this
|
||||
// repostiory.
|
||||
Submodules SubmoduleCollection
|
||||
// References represents the collection of references and can
|
||||
// be used to create, remove or update refernces for this repository.
|
||||
References ReferenceCollection
|
||||
// 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 {
|
||||
repo := &Repository{ptr: ptr}
|
||||
|
||||
repo.Remotes.repo = repo
|
||||
repo.Submodules.repo = repo
|
||||
repo.References.repo = repo
|
||||
repo.Notes.repo = repo
|
||||
repo.Tags.repo = repo
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
|
||||
return repo
|
||||
}
|
||||
|
||||
func OpenRepository(path string) (*Repository, error) {
|
||||
repo := new(Repository)
|
||||
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_repository_open(&repo.ptr, cpath)
|
||||
var ptr *C.git_repository
|
||||
ret := C.git_repository_open(&ptr, cpath)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
return repo, nil
|
||||
return newRepositoryFromC(ptr), nil
|
||||
}
|
||||
|
||||
func OpenRepositoryExtended(path string) (*Repository, error) {
|
||||
repo := new(Repository)
|
||||
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_repository_open_ext(&repo.ptr, cpath, 0, nil)
|
||||
var ptr *C.git_repository
|
||||
ret := C.git_repository_open_ext(&ptr, cpath, 0, nil)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
return repo, nil
|
||||
return newRepositoryFromC(ptr), nil
|
||||
}
|
||||
|
||||
func InitRepository(path string, isbare bool) (*Repository, error) {
|
||||
repo := new(Repository)
|
||||
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_repository_init(&repo.ptr, cpath, ucbool(isbare))
|
||||
var ptr *C.git_repository
|
||||
ret := C.git_repository_init(&ptr, cpath, ucbool(isbare))
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
return repo, nil
|
||||
return newRepositoryFromC(ptr), nil
|
||||
}
|
||||
|
||||
func NewRepositoryWrapOdb(odb *Odb) (repo *Repository, err error) {
|
||||
repo = new(Repository)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_repository_wrap_odb(&repo.ptr, odb.ptr)
|
||||
var ptr *C.git_repository
|
||||
ret := C.git_repository_wrap_odb(&ptr, odb.ptr)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
return repo, nil
|
||||
return newRepositoryFromC(ptr), nil
|
||||
}
|
||||
|
||||
func (v *Repository) SetRefdb(refdb *Refdb) {
|
||||
|
@ -176,22 +199,6 @@ func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
|
|||
return obj.(*Tag), nil
|
||||
}
|
||||
|
||||
func (v *Repository) LookupReference(name string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_reference_lookup(&ptr, v.ptr, cname)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, v), nil
|
||||
}
|
||||
|
||||
func (v *Repository) Head() (*Reference, error) {
|
||||
var ptr *C.git_reference
|
||||
|
||||
|
@ -206,49 +213,25 @@ func (v *Repository) Head() (*Reference, error) {
|
|||
return newReferenceFromC(ptr, v), nil
|
||||
}
|
||||
|
||||
func (v *Repository) SetHead(refname string, sig *Signature, msg string) error {
|
||||
func (v *Repository) SetHead(refname string) error {
|
||||
cname := C.CString(refname)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg != "" {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_repository_set_head(v.ptr, cname, csig, cmsg)
|
||||
ecode := C.git_repository_set_head(v.ptr, cname)
|
||||
if ecode != 0 {
|
||||
return MakeGitError(ecode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Repository) SetHeadDetached(id *Oid, sig *Signature, msg string) error {
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg != "" {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
func (v *Repository) SetHeadDetached(id *Oid) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_repository_set_head_detached(v.ptr, id.toC(), csig, cmsg)
|
||||
ecode := C.git_repository_set_head_detached(v.ptr, id.toC())
|
||||
if ecode != 0 {
|
||||
return MakeGitError(ecode)
|
||||
}
|
||||
|
@ -267,71 +250,6 @@ func (v *Repository) IsHeadDetached() (bool, error) {
|
|||
return ret != 0, nil
|
||||
}
|
||||
|
||||
func (v *Repository) CreateReference(name string, id *Oid, force bool, sig *Signature, msg string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_reference_create(&ptr, v.ptr, cname, id.toC(), cbool(force), csig, cmsg)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, v), nil
|
||||
}
|
||||
|
||||
func (v *Repository) CreateSymbolicReference(name, target string, force bool, sig *Signature, msg string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
ctarget := C.CString(target)
|
||||
defer C.free(unsafe.Pointer(ctarget))
|
||||
|
||||
csig, err := sig.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(csig)
|
||||
|
||||
var cmsg *C.char
|
||||
if msg == "" {
|
||||
cmsg = nil
|
||||
} else {
|
||||
cmsg = C.CString(msg)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
}
|
||||
|
||||
var ptr *C.git_reference
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_reference_symbolic_create(&ptr, v.ptr, cname, ctarget, cbool(force), csig, cmsg)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, v), nil
|
||||
}
|
||||
|
||||
func (v *Repository) Walk() (*RevWalk, error) {
|
||||
|
||||
var walkPtr *C.git_revwalk
|
||||
|
@ -403,36 +321,6 @@ 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)
|
||||
|
@ -513,169 +401,6 @@ func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) {
|
|||
return bld, nil
|
||||
}
|
||||
|
||||
// EnsureLog ensures that there is a reflog for the given reference
|
||||
// name and creates an empty one if necessary.
|
||||
func (v *Repository) EnsureLog(name string) error {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_reference_ensure_log(v.ptr, cname)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasLog returns whether there is a reflog for the given reference
|
||||
// name
|
||||
func (v *Repository) HasLog(name string) (bool, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_reference_has_log(v.ptr, cname)
|
||||
if ret < 0 {
|
||||
return false, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return ret == 1, nil
|
||||
}
|
||||
|
||||
// DwimReference looks up a reference by DWIMing its short name
|
||||
func (v *Repository) DwimReference(name string) (*Reference, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var ptr *C.git_reference
|
||||
ret := C.git_reference_dwim(&ptr, v.ptr, cname)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return newReferenceFromC(ptr, v), nil
|
||||
}
|
||||
|
||||
// CreateNote adds a note for an object
|
||||
func (v *Repository) CreateNote(
|
||||
ref string, author, committer *Signature, id *Oid,
|
||||
note string, force bool) (*Oid, error) {
|
||||
|
||||
oid := new(Oid)
|
||||
|
||||
var cref *C.char
|
||||
if ref == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(ref)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
authorSig, err := author.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(authorSig)
|
||||
|
||||
committerSig, err := committer.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(committerSig)
|
||||
|
||||
cnote := C.CString(note)
|
||||
defer C.free(unsafe.Pointer(cnote))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_note_create(
|
||||
oid.toC(), v.ptr, cref, authorSig,
|
||||
committerSig, id.toC(), cnote, cbool(force))
|
||||
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
return oid, nil
|
||||
}
|
||||
|
||||
// ReadNote reads the note for an object
|
||||
func (v *Repository) ReadNote(ref string, id *Oid) (*Note, error) {
|
||||
var cref *C.char
|
||||
if ref == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(ref)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
note := new(Note)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if ret := C.git_note_read(¬e.ptr, v.ptr, cref, id.toC()); ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(note, (*Note).Free)
|
||||
return note, nil
|
||||
}
|
||||
|
||||
// RemoveNote removes the note for an object
|
||||
func (v *Repository) RemoveNote(ref string, author, committer *Signature, id *Oid) error {
|
||||
var cref *C.char
|
||||
if ref == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(ref)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
authorSig, err := author.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(authorSig)
|
||||
|
||||
committerSig, err := committer.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer C.git_signature_free(committerSig)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_note_remove(v.ptr, cref, authorSig, committerSig, id.toC())
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultNoteRef returns the default notes reference for a repository
|
||||
func (v *Repository) DefaultNoteRef() (string, error) {
|
||||
var ptr *C.char
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if ret := C.git_note_default_ref(&ptr, v.ptr); ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
|
||||
return C.GoString(ptr), nil
|
||||
}
|
||||
|
||||
type RepositoryState int
|
||||
|
||||
const (
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#include <git2.h>
|
||||
*/
|
||||
import "C"
|
||||
import "runtime"
|
||||
|
||||
type ResetType int
|
||||
|
||||
const (
|
||||
ResetSoft ResetType = C.GIT_RESET_SOFT
|
||||
ResetMixed ResetType = C.GIT_RESET_MIXED
|
||||
ResetHard ResetType = C.GIT_RESET_HARD
|
||||
)
|
||||
|
||||
func (r *Repository) ResetToCommit(commit *Commit, resetType ResetType, opts *CheckoutOpts) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
ret := C.git_reset(r.ptr, commit.gitObject.ptr, C.git_reset_t(resetType), opts.toC())
|
||||
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResetToCommit(t *testing.T) {
|
||||
repo := createTestRepo(t)
|
||||
seedTestRepo(t, repo)
|
||||
// create commit to reset to
|
||||
commitId, _ := updateReadme(t, repo, "testing reset")
|
||||
// create commit to reset from
|
||||
nextCommitId, _ := updateReadme(t, repo, "will be reset")
|
||||
|
||||
// confirm that we wrote "will be reset" to the readme
|
||||
newBytes, err := ioutil.ReadFile(pathInRepo(repo, "README"))
|
||||
checkFatal(t, err)
|
||||
if string(newBytes) != "will be reset" {
|
||||
t.Fatalf("expected %s to equal 'will be reset'", string(newBytes))
|
||||
}
|
||||
|
||||
// confirm that the head of the repo is the next commit id
|
||||
head, err := repo.Head()
|
||||
checkFatal(t, err)
|
||||
if head.Target().String() != nextCommitId.String() {
|
||||
t.Fatalf(
|
||||
"expected to be at latest commit %s, but was %s",
|
||||
nextCommitId.String(),
|
||||
head.Target().String(),
|
||||
)
|
||||
}
|
||||
|
||||
commitToResetTo, err := repo.LookupCommit(commitId)
|
||||
checkFatal(t, err)
|
||||
|
||||
repo.ResetToCommit(commitToResetTo, ResetHard, &CheckoutOpts{})
|
||||
|
||||
// check that the file now reads "testing reset" like it did before
|
||||
bytes, err := ioutil.ReadFile(pathInRepo(repo, "README"))
|
||||
checkFatal(t, err)
|
||||
if string(bytes) != "testing reset" {
|
||||
t.Fatalf("expected %s to equal 'testing reset'", string(bytes))
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ func TestRevparseExt(t *testing.T) {
|
|||
|
||||
_, treeId := seedTestRepo(t, repo)
|
||||
|
||||
ref, err := repo.CreateReference("refs/heads/master", treeId, true, nil, "")
|
||||
ref, err := repo.References.Create("refs/heads/master", treeId, true, "")
|
||||
checkFatal(t, err)
|
||||
|
||||
obj, ref, err := repo.RevparseExt("master")
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
VENDORED_PATH=vendor/libgit2
|
||||
|
||||
cd $VENDORED_PATH &&
|
||||
mkdir -p install/lib &&
|
||||
mkdir -p build &&
|
||||
cd build &&
|
||||
cmake -DTHREADSAFE=ON \
|
||||
-DBUILD_CLAR=OFF \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_C_FLAGS=-fPIC \
|
||||
-DCMAKE_BUILD_TYPE="RelWithDebInfo" \
|
||||
-DCMAKE_INSTALL_PREFIX=../install \
|
||||
.. &&
|
||||
|
||||
cmake --build .
|
|
@ -1,3 +1,5 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Install libgit2 to git2go in dynamic mode on Travis
|
||||
#
|
||||
|
||||
set -ex
|
||||
|
||||
# We don't want to build libgit2 on the next branch, as we carry a
|
||||
# submodule with the exact version we support
|
||||
if [ "x$TRAVIS_BRANCH" = "xnext" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "${HOME}"
|
||||
wget -O libgit2-0.23.1.tar.gz https://github.com/libgit2/libgit2/archive/v0.23.1.tar.gz
|
||||
tar -xzvf libgit2-0.23.1.tar.gz
|
||||
cd libgit2-0.23.1 && mkdir build && cd build
|
||||
cmake -DTHREADSAFE=ON -DBUILD_CLAR=OFF -DCMAKE_BUILD_TYPE="RelWithDebInfo" .. && make && sudo make install
|
||||
sudo ldconfig
|
||||
cd "${TRAVIS_BUILD_DIR}"
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
export BUILD="$PWD/vendor/libgit2/build"
|
||||
export PCFILE="$BUILD/libgit2.pc"
|
||||
|
||||
FLAGS=$(pkg-config --static --libs $PCFILE) || exit 1
|
||||
export CGO_LDFLAGS="$BUILD/libgit2.a -L$BUILD ${FLAGS}"
|
||||
export CGO_CFLAGS="-I$PWD/vendor/libgit2/include"
|
||||
|
||||
$@
|
120
submodule.go
120
submodule.go
|
@ -14,9 +14,8 @@ import (
|
|||
// SubmoduleUpdateOptions
|
||||
type SubmoduleUpdateOptions struct {
|
||||
*CheckoutOpts
|
||||
*RemoteCallbacks
|
||||
*FetchOptions
|
||||
CloneCheckoutStrategy CheckoutStrategy
|
||||
Signature *Signature
|
||||
}
|
||||
|
||||
// Submodule
|
||||
|
@ -27,7 +26,6 @@ type Submodule struct {
|
|||
type SubmoduleUpdate int
|
||||
|
||||
const (
|
||||
SubmoduleUpdateReset SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_RESET
|
||||
SubmoduleUpdateCheckout SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_CHECKOUT
|
||||
SubmoduleUpdateRebase SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_REBASE
|
||||
SubmoduleUpdateMerge SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_MERGE
|
||||
|
@ -37,7 +35,6 @@ const (
|
|||
type SubmoduleIgnore int
|
||||
|
||||
const (
|
||||
SubmoduleIgnoreReset SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_RESET
|
||||
SubmoduleIgnoreNone SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_NONE
|
||||
SubmoduleIgnoreUntracked SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_UNTRACKED
|
||||
SubmoduleIgnoreDirty SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_DIRTY
|
||||
|
@ -71,13 +68,17 @@ const (
|
|||
SubmoduleRecurseOndemand SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_ONDEMAND
|
||||
)
|
||||
|
||||
type SubmoduleCollection struct {
|
||||
repo *Repository
|
||||
}
|
||||
|
||||
func SubmoduleStatusIsUnmodified(status int) bool {
|
||||
o := SubmoduleStatus(status) & ^(SubmoduleStatusInHead | SubmoduleStatusInIndex |
|
||||
SubmoduleStatusInConfig | SubmoduleStatusInWd)
|
||||
return o == 0
|
||||
}
|
||||
|
||||
func (repo *Repository) LookupSubmodule(name string) (*Submodule, error) {
|
||||
func (c *SubmoduleCollection) Lookup(name string) (*Submodule, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
|
@ -86,7 +87,7 @@ func (repo *Repository) LookupSubmodule(name string) (*Submodule, error) {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_lookup(&sub.ptr, repo.ptr, cname)
|
||||
ret := C.git_submodule_lookup(&sub.ptr, c.repo.ptr, cname)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -107,21 +108,21 @@ func SubmoduleVisitor(csub unsafe.Pointer, name *C.char, handle unsafe.Pointer)
|
|||
}
|
||||
}
|
||||
|
||||
func (repo *Repository) ForeachSubmodule(cbk SubmoduleCbk) error {
|
||||
func (c *SubmoduleCollection) Foreach(cbk SubmoduleCbk) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
handle := pointerHandles.Track(cbk)
|
||||
defer pointerHandles.Untrack(handle)
|
||||
|
||||
ret := C._go_git_visit_submodule(repo.ptr, handle)
|
||||
ret := C._go_git_visit_submodule(c.repo.ptr, handle)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) AddSubmodule(url, path string, use_git_link bool) (*Submodule, error) {
|
||||
func (c *SubmoduleCollection) Add(url, path string, use_git_link bool) (*Submodule, error) {
|
||||
curl := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(curl))
|
||||
cpath := C.CString(path)
|
||||
|
@ -132,7 +133,7 @@ func (repo *Repository) AddSubmodule(url, path string, use_git_link bool) (*Subm
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_add_setup(&sub.ptr, repo.ptr, curl, cpath, cbool(use_git_link))
|
||||
ret := C.git_submodule_add_setup(&sub.ptr, c.repo.ptr, curl, cpath, cbool(use_git_link))
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
@ -161,23 +162,6 @@ func (sub *Submodule) AddToIndex(write_index bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (sub *Submodule) Save() error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_save(sub.ptr)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sub *Submodule) Owner() *Repository {
|
||||
repo := C.git_submodule_owner(sub.ptr)
|
||||
//FIXME: how to handle dangling references ?
|
||||
return &Repository{repo}
|
||||
}
|
||||
|
||||
func (sub *Submodule) Name() string {
|
||||
n := C.git_submodule_name(sub.ptr)
|
||||
return C.GoString(n)
|
||||
|
@ -193,14 +177,16 @@ func (sub *Submodule) Url() string {
|
|||
return C.GoString(n)
|
||||
}
|
||||
|
||||
func (sub *Submodule) SetUrl(url string) error {
|
||||
func (c *SubmoduleCollection) SetUrl(submodule, url string) error {
|
||||
csubmodule := C.CString(submodule)
|
||||
defer C.free(unsafe.Pointer(csubmodule))
|
||||
curl := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(curl))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_set_url(sub.ptr, curl)
|
||||
ret := C.git_submodule_set_url(c.repo.ptr, csubmodule, curl)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
@ -236,9 +222,19 @@ func (sub *Submodule) Ignore() SubmoduleIgnore {
|
|||
return SubmoduleIgnore(o)
|
||||
}
|
||||
|
||||
func (sub *Submodule) SetIgnore(ignore SubmoduleIgnore) SubmoduleIgnore {
|
||||
o := C.git_submodule_set_ignore(sub.ptr, C.git_submodule_ignore_t(ignore))
|
||||
return SubmoduleIgnore(o)
|
||||
func (c *SubmoduleCollection) SetIgnore(submodule string, ignore SubmoduleIgnore) error {
|
||||
csubmodule := C.CString(submodule)
|
||||
defer C.free(unsafe.Pointer(csubmodule))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_set_ignore(c.repo.ptr, csubmodule, C.git_submodule_ignore_t(ignore))
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sub *Submodule) UpdateStrategy() SubmoduleUpdate {
|
||||
|
@ -246,20 +242,33 @@ func (sub *Submodule) UpdateStrategy() SubmoduleUpdate {
|
|||
return SubmoduleUpdate(o)
|
||||
}
|
||||
|
||||
func (sub *Submodule) SetUpdate(update SubmoduleUpdate) SubmoduleUpdate {
|
||||
o := C.git_submodule_set_update(sub.ptr, C.git_submodule_update_t(update))
|
||||
return SubmoduleUpdate(o)
|
||||
func (c *SubmoduleCollection) SetUpdate(submodule string, update SubmoduleUpdate) error {
|
||||
csubmodule := C.CString(submodule)
|
||||
defer C.free(unsafe.Pointer(csubmodule))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_set_update(c.repo.ptr, csubmodule, C.git_submodule_update_t(update))
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sub *Submodule) FetchRecurseSubmodules() SubmoduleRecurse {
|
||||
return SubmoduleRecurse(C.git_submodule_fetch_recurse_submodules(sub.ptr))
|
||||
}
|
||||
|
||||
func (sub *Submodule) SetFetchRecurseSubmodules(recurse SubmoduleRecurse) error {
|
||||
func (c *SubmoduleCollection) SetFetchRecurseSubmodules(submodule string, recurse SubmoduleRecurse) error {
|
||||
csubmodule := C.CString(submodule)
|
||||
defer C.free(unsafe.Pointer(csubmodule))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, C.git_submodule_recurse_t(recurse))
|
||||
ret := C.git_submodule_set_fetch_recurse_submodules(c.repo.ptr, csubmodule, C.git_submodule_recurse_t(recurse))
|
||||
if ret < 0 {
|
||||
return MakeGitError(C.int(ret))
|
||||
}
|
||||
|
@ -289,38 +298,15 @@ func (sub *Submodule) Sync() error {
|
|||
}
|
||||
|
||||
func (sub *Submodule) Open() (*Repository, error) {
|
||||
repo := new(Repository)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_open(&repo.ptr, sub.ptr)
|
||||
var ptr *C.git_repository
|
||||
ret := C.git_submodule_open(&ptr, sub.ptr)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (sub *Submodule) Reload(force bool) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_reload(sub.ptr, cbool(force))
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) ReloadAllSubmodules(force bool) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_submodule_reload_all(repo.ptr, cbool(force))
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
return newRepositoryFromC(ptr), nil
|
||||
}
|
||||
|
||||
func (sub *Submodule) Update(init bool, opts *SubmoduleUpdateOptions) error {
|
||||
|
@ -349,14 +335,8 @@ func populateSubmoduleUpdateOptions(ptr *C.git_submodule_update_options, opts *S
|
|||
}
|
||||
|
||||
populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
|
||||
populateRemoteCallbacks(&ptr.remote_callbacks, opts.RemoteCallbacks)
|
||||
populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions)
|
||||
ptr.clone_checkout_strategy = C.uint(opts.CloneCheckoutStrategy)
|
||||
|
||||
sig, err := opts.Signature.toC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr.signature = sig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ func TestSubmoduleForeach(t *testing.T) {
|
|||
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
_, err := repo.AddSubmodule("http://example.org/submodule", "submodule", true)
|
||||
_, err := repo.Submodules.Add("http://example.org/submodule", "submodule", true)
|
||||
checkFatal(t, err)
|
||||
|
||||
i := 0
|
||||
err = repo.ForeachSubmodule(func(sub *Submodule, name string) int {
|
||||
err = repo.Submodules.Foreach(func(sub *Submodule, name string) int {
|
||||
i++
|
||||
return 0
|
||||
})
|
||||
|
|
167
tag.go
167
tag.go
|
@ -2,8 +2,14 @@ package git
|
|||
|
||||
/*
|
||||
#include <git2.h>
|
||||
|
||||
extern int _go_git_tag_foreach(git_repository *repo, void *payload);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Tag
|
||||
type Tag struct {
|
||||
|
@ -42,3 +48,164 @@ 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/<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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -24,6 +25,146 @@ 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)
|
||||
|
@ -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),
|
||||
}
|
||||
|
||||
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)
|
||||
return tagId
|
||||
}
|
||||
|
|
18
tree.go
18
tree.go
|
@ -55,6 +55,24 @@ 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) {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
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)
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@ int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLin
|
|||
lcb = (git_diff_line_cb)&diffForEachLineCb;
|
||||
}
|
||||
|
||||
return git_diff_foreach(diff, fcb, hcb, lcb, payload);
|
||||
return git_diff_foreach(diff, fcb, NULL, hcb, lcb, payload);
|
||||
}
|
||||
|
||||
int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload)
|
||||
|
@ -85,7 +85,7 @@ int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const
|
|||
lcb = (git_diff_line_cb)&diffForEachLineCb;
|
||||
}
|
||||
|
||||
return git_diff_blobs(old, old_path, new, new_path, opts, fcb, hcb, lcb, payload);
|
||||
return git_diff_blobs(old, old_path, new, new_path, opts, fcb, NULL, hcb, lcb, payload);
|
||||
}
|
||||
|
||||
void _go_git_setup_diff_notify_callbacks(git_diff_options *opts) {
|
||||
|
@ -136,4 +136,9 @@ 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 */
|
||||
|
|
Loading…
Reference in New Issue