From 179b69ce21fd1742c4f51e4ae0f2c1ef6929019e Mon Sep 17 00:00:00 2001 From: Axel Wagner Date: Wed, 22 May 2013 14:41:42 +0200 Subject: [PATCH 01/66] Support for index-entries --- index.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/index.go b/index.go index 72b1d5b..90a49de 100644 --- a/index.go +++ b/index.go @@ -7,7 +7,9 @@ package git */ import "C" import ( + "fmt" "runtime" + "time" "unsafe" ) @@ -15,6 +17,18 @@ type Index struct { ptr *C.git_index } +type IndexEntry struct { + ptr *C.git_index_entry + Ctime time.Time + Mtime time.Time + Mode uint + Uid uint + Gid uint + Size uint + Oid *Oid + Path string +} + func newIndexFromC(ptr *C.git_index) *Index { idx := &Index{ptr} runtime.SetFinalizer(idx, (*Index).Free) @@ -47,3 +61,29 @@ func (v *Index) Free() { runtime.SetFinalizer(v, nil) C.git_index_free(v.ptr) } + +func (v *Index) EntryCount() uint { + return uint(C.git_index_entrycount(v.ptr)) +} + +func newIndexEntryFromC(entry *C.git_index_entry) *IndexEntry { + return &IndexEntry{ + entry, + time.Unix(int64(entry.ctime.seconds), int64(entry.ctime.nanoseconds)), + time.Unix(int64(entry.mtime.seconds), int64(entry.mtime.nanoseconds)), + uint(entry.mode), + uint(entry.uid), + uint(entry.gid), + uint(entry.file_size), + newOidFromC(&entry.oid), + C.GoString(entry.path), + } +} + +func (v *Index) EntryByIndex(index uint) (*IndexEntry, error) { + centry := C.git_index_get_byindex(v.ptr, C.size_t(index)) + if centry == nil { + return nil, fmt.Errorf("Index out of Bounds") + } + return newIndexEntryFromC(centry), nil +} From ff5150e6c9a0e9f82eb3c26df96f8839242589ca Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Tue, 8 Oct 2013 02:07:06 +0200 Subject: [PATCH 02/66] branch: Implemented branch functions. --- branch.go | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 branch.go diff --git a/branch.go b/branch.go new file mode 100644 index 0000000..8dd55a3 --- /dev/null +++ b/branch.go @@ -0,0 +1,199 @@ +package git + +/* +#cgo pkg-config: libgit2 +#include +#include +*/ +import "C" + +import ( + "errors" + "strings" + "unsafe" +) + +var ErrEUser = errors.New("Error in user callback function") + +type ListFlags uint + +type BranchT uint + +const ( + BRANCH_LOCAL BranchT = C.GIT_BRANCH_LOCAL + BRANCH_REMOTE = C.GIT_BRANCH_REMOTE +) + +const ( + REFS_DIR = "refs/" + REFS_HEADS_DIR = REFS_DIR + "heads/" + REFS_TAGS_DIR = REFS_DIR + "tags/" + REFS_REMOTES_DIR = REFS_DIR + "remotes/" +) + +type Branch struct { + Reference +} + +func (repo *Repository) BranchCreate(branchName string, target *Commit, force bool) (*Reference, error) { + ref := new(Reference) + cBranchName := C.CString(branchName) + cForce := cbool(force) + err := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce) + if err < 0 { + return nil, LastError() + } + return ref, nil +} + +func (branch *Branch) BranchDelete() error { + if err := C.git_branch_delete(branch.ptr); err < 0 { + return LastError() + } + return nil +} + +type BranchForeachCB func(name string, flags ListFlags, payload interface{}) error + +func (repo *Repository) BranchForeach(flags ListFlags, callback BranchForeachCB, payload interface{}) error { + iter, err := repo.NewReferenceIterator() + if err != nil { + return err + } + + for { + ref, err := iter.Next() + if err == ErrIterOver { + break + } + + if (flags == ListFlags(BRANCH_LOCAL)) && strings.HasPrefix(ref.Name(), REFS_HEADS_DIR) { + name := strings.TrimPrefix(ref.Name(), REFS_HEADS_DIR) + err = callback(name, ListFlags(BRANCH_LOCAL), payload) + if err != nil { + return err + } + } + + if (flags == ListFlags(BRANCH_REMOTE)) && strings.HasPrefix(ref.Name(), REFS_REMOTES_DIR) { + name := strings.TrimPrefix(ref.Name(), REFS_REMOTES_DIR) + err = callback(name, ListFlags(BRANCH_REMOTE), payload) + if err != nil { + return err + } + } + } + + if err == ErrIterOver { + err = nil + } + return err +} + +func (branch *Branch) Move(newBranchName string, force bool) (*Branch, error) { + newBranch := new(Branch) + cNewBranchName := C.CString(newBranchName) + cForce := cbool(force) + + err := C.git_branch_move(&newBranch.ptr, branch.ptr, cNewBranchName, cForce) + if err < 0 { + return nil, LastError() + } + return newBranch, nil +} + +func (branch *Branch) IsHead() (bool, error) { + isHead := C.git_branch_is_head(branch.ptr) + switch isHead { + case 1: + return true, nil + case 0: + return false, nil + default: + return false, LastError() + } + +} + +func (repo *Repository) BranchLookup(branchName string, branchType BranchT) (*Branch, error) { + branch := new(Branch) + cName := C.CString(branchName) + + err := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(branchType)) + if err < 0 { + return nil, LastError() + } + return branch, nil +} + +func (branch *Branch) Name() (string, error) { + var cName *C.char + defer C.free(unsafe.Pointer(cName)) + + err := C.git_branch_name(&cName, branch.ptr) + if err < 0 { + return "", LastError() + } + + return C.GoString(cName), nil +} + +func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { + cName := C.CString(canonicalBranchName) + + // Obtain the length of the name + ret := C.git_branch_remote_name(nil, 0, repo.ptr, cName) + if ret < 0 { + return "", LastError() + } + + cBuf := (*C.char)(C.malloc(C.size_t(ret))) + defer C.free(unsafe.Pointer(cBuf)) + + // Actually obtain the name + ret = C.git_branch_remote_name(cBuf, C.size_t(ret), repo.ptr, cName) + if ret < 0 { + return "", LastError() + } + + return C.GoString(cBuf), nil +} + +func (branch *Branch) SetUpstream(upstreamName string) error { + cName := C.CString(upstreamName) + + err := C.git_branch_set_upstream(branch.ptr, cName) + if err < 0 { + return LastError() + } + return nil +} + +func (branch *Branch) Upstream() (*Branch, error) { + upstream := new(Branch) + err := C.git_branch_upstream(&upstream.ptr, branch.ptr) + if err < 0 { + return nil, LastError() + } + return upstream, nil +} + +func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) { + cName := C.CString(canonicalBranchName) + + // Obtain the length of the name + ret := C.git_branch_upstream_name(nil, 0, repo.ptr, cName) + if ret < 0 { + return "", LastError() + } + + cBuf := (*C.char)(C.malloc(C.size_t(ret))) + defer C.free(unsafe.Pointer(cBuf)) + + // Actually obtain the name + ret = C.git_branch_upstream_name(cBuf, C.size_t(ret), repo.ptr, cName) + if ret < 0 { + return "", LastError() + } + return C.GoString(cBuf), nil +} From f03cec5375d22bda9efebb01e78d9e752ee2b498 Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Tue, 8 Oct 2013 14:39:05 +0200 Subject: [PATCH 03/66] branch: Changed BranchT to BranchType --- branch.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/branch.go b/branch.go index 8dd55a3..651edb2 100644 --- a/branch.go +++ b/branch.go @@ -17,11 +17,11 @@ var ErrEUser = errors.New("Error in user callback function") type ListFlags uint -type BranchT uint +type BranchType uint const ( - BRANCH_LOCAL BranchT = C.GIT_BRANCH_LOCAL - BRANCH_REMOTE = C.GIT_BRANCH_REMOTE + BRANCH_LOCAL BranchType = C.GIT_BRANCH_LOCAL + BRANCH_REMOTE = C.GIT_BRANCH_REMOTE ) const ( @@ -115,7 +115,7 @@ func (branch *Branch) IsHead() (bool, error) { } -func (repo *Repository) BranchLookup(branchName string, branchType BranchT) (*Branch, error) { +func (repo *Repository) BranchLookup(branchName string, branchType BranchType) (*Branch, error) { branch := new(Branch) cName := C.CString(branchName) From 771e0c11bc8b1f00cdd6fdddbfe114957aa77ce2 Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Tue, 8 Oct 2013 14:44:11 +0200 Subject: [PATCH 04/66] branch: Variable names don't repeat its type name any longer --- branch.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/branch.go b/branch.go index 651edb2..e431f07 100644 --- a/branch.go +++ b/branch.go @@ -46,8 +46,8 @@ func (repo *Repository) BranchCreate(branchName string, target *Commit, force bo return ref, nil } -func (branch *Branch) BranchDelete() error { - if err := C.git_branch_delete(branch.ptr); err < 0 { +func (b *Branch) BranchDelete() error { + if err := C.git_branch_delete(b.ptr); err < 0 { return LastError() } return nil @@ -90,20 +90,20 @@ func (repo *Repository) BranchForeach(flags ListFlags, callback BranchForeachCB, return err } -func (branch *Branch) Move(newBranchName string, force bool) (*Branch, error) { +func (b *Branch) Move(newBranchName string, force bool) (*Branch, error) { newBranch := new(Branch) cNewBranchName := C.CString(newBranchName) cForce := cbool(force) - err := C.git_branch_move(&newBranch.ptr, branch.ptr, cNewBranchName, cForce) + err := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce) if err < 0 { return nil, LastError() } return newBranch, nil } -func (branch *Branch) IsHead() (bool, error) { - isHead := C.git_branch_is_head(branch.ptr) +func (b *Branch) IsHead() (bool, error) { + isHead := C.git_branch_is_head(b.ptr) switch isHead { case 1: return true, nil @@ -115,22 +115,22 @@ func (branch *Branch) IsHead() (bool, error) { } -func (repo *Repository) BranchLookup(branchName string, branchType BranchType) (*Branch, error) { +func (repo *Repository) BranchLookup(branchName string, bt BranchType) (*Branch, error) { branch := new(Branch) cName := C.CString(branchName) - err := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(branchType)) + err := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(bt)) if err < 0 { return nil, LastError() } return branch, nil } -func (branch *Branch) Name() (string, error) { +func (b *Branch) Name() (string, error) { var cName *C.char defer C.free(unsafe.Pointer(cName)) - err := C.git_branch_name(&cName, branch.ptr) + err := C.git_branch_name(&cName, b.ptr) if err < 0 { return "", LastError() } @@ -159,19 +159,19 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { return C.GoString(cBuf), nil } -func (branch *Branch) SetUpstream(upstreamName string) error { +func (b *Branch) SetUpstream(upstreamName string) error { cName := C.CString(upstreamName) - err := C.git_branch_set_upstream(branch.ptr, cName) + err := C.git_branch_set_upstream(b.ptr, cName) if err < 0 { return LastError() } return nil } -func (branch *Branch) Upstream() (*Branch, error) { +func (b *Branch) Upstream() (*Branch, error) { upstream := new(Branch) - err := C.git_branch_upstream(&upstream.ptr, branch.ptr) + err := C.git_branch_upstream(&upstream.ptr, b.ptr) if err < 0 { return nil, LastError() } From 6372ec052fb752122bc0662783b8450bbe2ce983 Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Tue, 8 Oct 2013 14:49:03 +0200 Subject: [PATCH 05/66] branch: Renamed BranchCreate to CreateBranch --- branch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/branch.go b/branch.go index e431f07..7a4e4cb 100644 --- a/branch.go +++ b/branch.go @@ -35,7 +35,7 @@ type Branch struct { Reference } -func (repo *Repository) BranchCreate(branchName string, target *Commit, force bool) (*Reference, error) { +func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool) (*Reference, error) { ref := new(Reference) cBranchName := C.CString(branchName) cForce := cbool(force) From 4c4da3a84621cc57e90bfe55b16342796c80aceb Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Tue, 8 Oct 2013 14:52:22 +0200 Subject: [PATCH 06/66] branch: Renamed BranchLookup to LookupBrnach --- branch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/branch.go b/branch.go index 7a4e4cb..07f3f41 100644 --- a/branch.go +++ b/branch.go @@ -115,7 +115,7 @@ func (b *Branch) IsHead() (bool, error) { } -func (repo *Repository) BranchLookup(branchName string, bt BranchType) (*Branch, error) { +func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Branch, error) { branch := new(Branch) cName := C.CString(branchName) From ed86064871639a956beb5592dc5b64e3d536f882 Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Thu, 10 Oct 2013 10:39:49 +0200 Subject: [PATCH 07/66] branch:BranchForeach: Correct handling of the ListFlags --- branch.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/branch.go b/branch.go index 07f3f41..11e12da 100644 --- a/branch.go +++ b/branch.go @@ -15,10 +15,10 @@ import ( var ErrEUser = errors.New("Error in user callback function") -type ListFlags uint - type BranchType uint +type ListFlags BranchType + const ( BRANCH_LOCAL BranchType = C.GIT_BRANCH_LOCAL BRANCH_REMOTE = C.GIT_BRANCH_REMOTE @@ -62,12 +62,18 @@ func (repo *Repository) BranchForeach(flags ListFlags, callback BranchForeachCB, } for { + var branchLocal bool + var branchRemote bool + ref, err := iter.Next() if err == ErrIterOver { break } - if (flags == ListFlags(BRANCH_LOCAL)) && strings.HasPrefix(ref.Name(), REFS_HEADS_DIR) { + if flags&ListFlags(BRANCH_LOCAL) > 0 { + branchLocal = true + } + if branchLocal && strings.HasPrefix(ref.Name(), REFS_HEADS_DIR) { name := strings.TrimPrefix(ref.Name(), REFS_HEADS_DIR) err = callback(name, ListFlags(BRANCH_LOCAL), payload) if err != nil { @@ -75,7 +81,10 @@ func (repo *Repository) BranchForeach(flags ListFlags, callback BranchForeachCB, } } - if (flags == ListFlags(BRANCH_REMOTE)) && strings.HasPrefix(ref.Name(), REFS_REMOTES_DIR) { + if flags&ListFlags(BRANCH_REMOTE) > 0 { + branchRemote = true + } + if branchRemote && strings.HasPrefix(ref.Name(), REFS_REMOTES_DIR) { name := strings.TrimPrefix(ref.Name(), REFS_REMOTES_DIR) err = callback(name, ListFlags(BRANCH_REMOTE), payload) if err != nil { From 961db94aa21da58a77968099c6b97890e6235d10 Mon Sep 17 00:00:00 2001 From: Johann Weging Date: Wed, 30 Oct 2013 15:01:08 +0100 Subject: [PATCH 08/66] branch: Deleted BranchForeach --- branch.go | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/branch.go b/branch.go index 11e12da..d30748f 100644 --- a/branch.go +++ b/branch.go @@ -8,17 +8,11 @@ package git import "C" import ( - "errors" - "strings" "unsafe" ) -var ErrEUser = errors.New("Error in user callback function") - type BranchType uint -type ListFlags BranchType - const ( BRANCH_LOCAL BranchType = C.GIT_BRANCH_LOCAL BRANCH_REMOTE = C.GIT_BRANCH_REMOTE @@ -53,52 +47,6 @@ func (b *Branch) BranchDelete() error { return nil } -type BranchForeachCB func(name string, flags ListFlags, payload interface{}) error - -func (repo *Repository) BranchForeach(flags ListFlags, callback BranchForeachCB, payload interface{}) error { - iter, err := repo.NewReferenceIterator() - if err != nil { - return err - } - - for { - var branchLocal bool - var branchRemote bool - - ref, err := iter.Next() - if err == ErrIterOver { - break - } - - if flags&ListFlags(BRANCH_LOCAL) > 0 { - branchLocal = true - } - if branchLocal && strings.HasPrefix(ref.Name(), REFS_HEADS_DIR) { - name := strings.TrimPrefix(ref.Name(), REFS_HEADS_DIR) - err = callback(name, ListFlags(BRANCH_LOCAL), payload) - if err != nil { - return err - } - } - - if flags&ListFlags(BRANCH_REMOTE) > 0 { - branchRemote = true - } - if branchRemote && strings.HasPrefix(ref.Name(), REFS_REMOTES_DIR) { - name := strings.TrimPrefix(ref.Name(), REFS_REMOTES_DIR) - err = callback(name, ListFlags(BRANCH_REMOTE), payload) - if err != nil { - return err - } - } - } - - if err == ErrIterOver { - err = nil - } - return err -} - func (b *Branch) Move(newBranchName string, force bool) (*Branch, error) { newBranch := new(Branch) cNewBranchName := C.CString(newBranchName) From 313e1126dd0c974910de74f1b6bbc0fdcbbfd06b Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Thu, 2 Jan 2014 23:33:08 +0000 Subject: [PATCH 09/66] add git_submodule_recurse_t type --- submodule.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/submodule.go b/submodule.go index 48ea151..dadc785 100644 --- a/submodule.go +++ b/submodule.go @@ -56,6 +56,13 @@ const ( SubmoduleStatusWdUntracked = C.GIT_SUBMODULE_STATUS_WD_UNTRACKED ) +type SubmoduleRecurse int +const ( + SubmoduleRecurseNo SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_NO + SubmoduleRecurseYes = C.GIT_SUBMODULE_RECURSE_YES + SubmoduleRecurseOnDemand = C.GIT_SUBMODULE_RECURSE_ONDEMAND +) + func SubmoduleStatusIsUnmodified(status int) bool { o := SubmoduleStatus(status) & ^(SubmoduleStatusInHead | SubmoduleStatusInIndex | SubmoduleStatusInConfig | SubmoduleStatusInWd) @@ -236,11 +243,11 @@ func (sub *Submodule) FetchRecurseSubmodules() bool { return true } -func (sub *Submodule) SetFetchRecurseSubmodules(v bool) error { +func (sub *Submodule) SetFetchRecurseSubmodules(v SubmoduleRecurse) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, cbool(v)) + ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, C.git_submodule_recurse_t(v)) if ret < 0 { return LastError() } From e825d66fba2cb4169c7f3b0a43c491cf9e8c0738 Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Sat, 4 Jan 2014 00:40:21 +0000 Subject: [PATCH 10/66] work in progress wrapping git_clone --- clone.go | 69 ++++++++++++++++++++++++++++++++++++++++++++ git.go | 2 +- remote.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.c | 14 +++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 clone.go create mode 100644 remote.go diff --git a/clone.go b/clone.go new file mode 100644 index 0000000..672c325 --- /dev/null +++ b/clone.go @@ -0,0 +1,69 @@ +package git + +/* +#include +#include + +static git_clone_options git_clone_options_init() { + git_clone_options ret = GIT_CLONE_OPTIONS_INIT; + return ret; +} + +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type CloneOptions struct { + *CheckoutOpts + *RemoteCallbacks + Bare bool + IgnoreCertErrors bool + RemoteName string + CheckoutBranch string +} + +func Clone(url string, path string, options *CloneOptions) (*Repository, error) { + repo := new(Repository) + + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + + cpath := C.CString(path) + defer C.free(unsafe.Pointer(cpath)) + + var copts C.git_clone_options + populateCloneOptions(&copts, options) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_clone(&repo.ptr, curl, cpath, &copts) + if ret < 0 { + return nil, LastError() + } + + runtime.SetFinalizer(repo, (*Repository).Free) + return repo, nil +} + +func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { + *ptr = C.git_clone_options_init() + if opts == nil { + return + } + populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts) + populateRemoteCallbacks(&ptr.remote_callbacks, opts.RemoteCallbacks) + if opts.Bare { + ptr.bare = 1 + } else { + ptr.bare = 0 + } + if opts.IgnoreCertErrors { + ptr.ignore_cert_errors = 1 + } else { + ptr.ignore_cert_errors = 0 + } +} + diff --git a/git.go b/git.go index 28196c8..07892e4 100644 --- a/git.go +++ b/git.go @@ -1,7 +1,7 @@ package git /* -#cgo pkg-config: libgit2 +#cgo pkg-config: --static libgit2 #include #include */ diff --git a/remote.go b/remote.go new file mode 100644 index 0000000..47866ed --- /dev/null +++ b/remote.go @@ -0,0 +1,85 @@ +package git + +/* +#include +#include + +static git_remote_callbacks git_remote_callbacks_init() { + git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; + return ret; +} + +extern void _setup_callbacks(git_remote_callbacks *callbacks); + +*/ +import "C" +import ( + "unsafe" +) + +type RemoteCompletion uint +const ( + RemoteCompletionDownload RemoteCompletion = C.GIT_REMOTE_COMPLETION_DOWNLOAD + RemoteCompletionIndexing = C.GIT_REMOTE_COMPLETION_INDEXING + RemoteCompletionError = C.GIT_REMOTE_COMPLETION_ERROR +) + +type ProgressCallback func(str string) int +type CompletionCallback func(RemoteCompletion) int +type CredentialsCallback func(url string, username_from_url string, allowed_types uint) int // FIXME +type TransferProgressCallback func() int // FIXME +type UpdateTipsCallback func(refname string, a *Oid, b *Oid) int + +//export progressCallback +func progressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + str := C.GoStringN(_str, _len) + return callbacks.ProgressCallback(str) +} + +//export completionCallback +func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + return callbacks.CompletionCallback((RemoteCompletion)(completion_type)) +} + +//export credentialsCallback +func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + //cred := C.GoString(_cred) + url := C.GoString(_url) + username_from_url := C.GoString(_username_from_url) + return callbacks.CredentialsCallback(url, username_from_url, allowed_types) +} + +//export transferProgressCallback +func transferProgressCallback(stats C.git_transfer_progress, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + return callbacks.TransferProgressCallback() +} + +//export updateTipsCallback +func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + refname := C.GoString(_refname) + a := newOidFromC(_a) + b := newOidFromC(_b) + return callbacks.UpdateTipsCallback(refname, a, b) +} + +type RemoteCallbacks struct { + ProgressCallback + CompletionCallback + CredentialsCallback + TransferProgressCallback + UpdateTipsCallback +} + +func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { + *ptr = C.git_remote_callbacks_init() + if callbacks == nil { + return + } + C._setup_callbacks(ptr) + ptr.payload = unsafe.Pointer(callbacks) +} diff --git a/wrapper.c b/wrapper.c index 2af3974..ef05c2d 100644 --- a/wrapper.c +++ b/wrapper.c @@ -24,4 +24,18 @@ int _go_git_odb_foreach(git_odb *db, void *payload) { return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload); } + +void _setup_callbacks(git_remote_callbacks *callbacks) { + typedef int (*progress_cb)(const char *str, int len, void *data); + typedef int (*completion_cb)(git_remote_completion_type type, void *data); + typedef int (*credentials_cb)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data); + typedef int (*transfer_progress_cb)(const git_transfer_progress *stats, void *data); + typedef int (*update_tips_cb)(const char *refname, const git_oid *a, const git_oid *b, void *data); + callbacks->progress = (progress_cb)progressCallback; + callbacks->completion = (completion_cb)completionCallback; + callbacks->credentials = (credentials_cb)credentialsCallback; + callbacks->transfer_progress = (transfer_progress_cb)transferProgressCallback; + callbacks->update_tips = (update_tips_cb)updateTipsCallback; +} + /* EOF */ From 5d8a14d108ac963a4865cd03e20e56b28ee9626e Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Sun, 5 Jan 2014 20:55:32 +0000 Subject: [PATCH 11/66] wrappers for git_cred, git_transfer_progress. don't call nil callbacks. --- remote.go | 128 ++++++++++++++++++++++++++++++++++----------------- transport.go | 79 +++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 42 deletions(-) create mode 100644 transport.go diff --git a/remote.go b/remote.go index 47866ed..ebf1fd4 100644 --- a/remote.go +++ b/remote.go @@ -13,9 +13,11 @@ extern void _setup_callbacks(git_remote_callbacks *callbacks); */ import "C" -import ( - "unsafe" -) +import "unsafe" + +type TransferProgress struct { + ptr *C.git_transfer_progress +} type RemoteCompletion uint const ( @@ -26,47 +28,10 @@ const ( type ProgressCallback func(str string) int type CompletionCallback func(RemoteCompletion) int -type CredentialsCallback func(url string, username_from_url string, allowed_types uint) int // FIXME -type TransferProgressCallback func() int // FIXME +type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (int, Cred) +type TransferProgressCallback func(stats TransferProgress) int type UpdateTipsCallback func(refname string, a *Oid, b *Oid) int -//export progressCallback -func progressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) - str := C.GoStringN(_str, _len) - return callbacks.ProgressCallback(str) -} - -//export completionCallback -func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) - return callbacks.CompletionCallback((RemoteCompletion)(completion_type)) -} - -//export credentialsCallback -func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) - //cred := C.GoString(_cred) - url := C.GoString(_url) - username_from_url := C.GoString(_username_from_url) - return callbacks.CredentialsCallback(url, username_from_url, allowed_types) -} - -//export transferProgressCallback -func transferProgressCallback(stats C.git_transfer_progress, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) - return callbacks.TransferProgressCallback() -} - -//export updateTipsCallback -func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) - refname := C.GoString(_refname) - a := newOidFromC(_a) - b := newOidFromC(_b) - return callbacks.UpdateTipsCallback(refname, a, b) -} - type RemoteCallbacks struct { ProgressCallback CompletionCallback @@ -83,3 +48,82 @@ func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallb C._setup_callbacks(ptr) ptr.payload = unsafe.Pointer(callbacks) } + +//export progressCallback +func progressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + if callbacks.ProgressCallback == nil { + return 0 + } + str := C.GoStringN(_str, _len) + return callbacks.ProgressCallback(str) +} + +//export completionCallback +func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + if callbacks.CompletionCallback == nil { + return 0 + } + return callbacks.CompletionCallback((RemoteCompletion)(completion_type)) +} + +//export credentialsCallback +func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + if callbacks.CredentialsCallback == nil { + return 0 + } + url := C.GoString(_url) + username_from_url := C.GoString(_username_from_url) + ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types)) + if gcred, ok := cred.(gitCred); ok { + *_cred = gcred.ptr + } + return ret +} + +//export transferProgressCallback +func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + if callbacks.TransferProgressCallback == nil { + return 0 + } + return callbacks.TransferProgressCallback(TransferProgress{stats}) +} + +//export updateTipsCallback +func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + if callbacks.UpdateTipsCallback == nil { + return 0 + } + refname := C.GoString(_refname) + a := newOidFromC(_a) + b := newOidFromC(_b) + return callbacks.UpdateTipsCallback(refname, a, b) +} + +func (o TransferProgress) TotalObjects() uint { + return uint(o.ptr.total_objects) +} + +func (o TransferProgress) IndexedObjects() uint { + return uint(o.ptr.indexed_objects) +} + +func (o TransferProgress) ReceivedObjects() uint { + return uint(o.ptr.received_objects) +} + +func (o TransferProgress) LocalObjects() uint { + return uint(o.ptr.local_objects) +} + +func (o TransferProgress) TotalDeltas() uint { + return uint(o.ptr.total_deltas) +} + +func (o TransferProgress) ReceivedBytes() uint { + return uint(o.ptr.received_bytes) +} diff --git a/transport.go b/transport.go new file mode 100644 index 0000000..e97a70c --- /dev/null +++ b/transport.go @@ -0,0 +1,79 @@ +package git + +/* +#include +#include +*/ +import "C" +import "unsafe" + +type CredType uint +const ( + CredTypeUserpassPlaintext CredType = C.GIT_CREDTYPE_USERPASS_PLAINTEXT + CredTypeSshKey = C.GIT_CREDTYPE_SSH_KEY + CredTypeSshCustom = C.GIT_CREDTYPE_SSH_CUSTOM + CredTypeDefault = C.GIT_CREDTYPE_DEFAULT +) + +type Cred interface { + HasUsername() bool + Type() CredType +} + +type gitCred struct { + ptr *C.git_cred +} + +func (o gitCred) HasUsername() bool { + if C.git_cred_has_username(o.ptr) == 1 { + return true + } + return false +} + +func (o gitCred) Type() CredType { + return (CredType)(o.ptr.credtype); +} + +func credFromC(ptr *C.git_cred) Cred { + return gitCred{ptr} +} + +func NewCredUserpassPlaintext(username string, password string) (int, Cred) { + cred := gitCred{} + cusername := C.CString(username) + defer C.free(unsafe.Pointer(cusername)) + cpassword := C.CString(password) + defer C.free(unsafe.Pointer(cpassword)) + ret := C.git_cred_userpass_plaintext_new(&cred.ptr, cusername, cpassword) + return int(ret), cred +} + +func NewCredSshKey(username string, publickey string, privatekey string, passphrase string) (int, Cred) { + cred := gitCred{} + cusername := C.CString(username) + defer C.free(unsafe.Pointer(cusername)) + cpublickey := C.CString(publickey) + defer C.free(unsafe.Pointer(cpublickey)) + cprivatekey := C.CString(privatekey) + defer C.free(unsafe.Pointer(cprivatekey)) + cpassphrase := C.CString(passphrase) + defer C.free(unsafe.Pointer(cpassphrase)) + ret := C.git_cred_ssh_key_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase) + return int(ret), cred +} + +func NewCredSshKeyFromAgent(username string) (int, Cred) { + cred := gitCred{} + cusername := C.CString(username) + defer C.free(unsafe.Pointer(cusername)) + ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername) + return int(ret), cred +} + +func NewCredDefault() (int, Cred) { + cred := gitCred{} + ret := C.git_cred_default_new(&cred.ptr) + return int(ret), cred +} + From d1245446685ccdc632b6a9cee65391cbe4eac4df Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Mon, 6 Jan 2014 16:55:29 +0000 Subject: [PATCH 12/66] minor --- remote.go | 12 ++++-------- wrapper.c | 7 ++++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/remote.go b/remote.go index ebf1fd4..0645291 100644 --- a/remote.go +++ b/remote.go @@ -4,12 +4,8 @@ package git #include #include -static git_remote_callbacks git_remote_callbacks_init() { - git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; - return ret; -} - -extern void _setup_callbacks(git_remote_callbacks *callbacks); +extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); +extern git_remote_callbacks _go_git_remote_callbacks_init(); */ import "C" @@ -41,11 +37,11 @@ type RemoteCallbacks struct { } func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { - *ptr = C.git_remote_callbacks_init() + *ptr = C._go_git_remote_callbacks_init() if callbacks == nil { return } - C._setup_callbacks(ptr) + C._go_git_setup_callbacks(ptr) ptr.payload = unsafe.Pointer(callbacks) } diff --git a/wrapper.c b/wrapper.c index ef05c2d..4543822 100644 --- a/wrapper.c +++ b/wrapper.c @@ -25,7 +25,7 @@ int _go_git_odb_foreach(git_odb *db, void *payload) return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload); } -void _setup_callbacks(git_remote_callbacks *callbacks) { +void _go_git_setup_callbacks(git_remote_callbacks *callbacks) { typedef int (*progress_cb)(const char *str, int len, void *data); typedef int (*completion_cb)(git_remote_completion_type type, void *data); typedef int (*credentials_cb)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data); @@ -38,4 +38,9 @@ void _setup_callbacks(git_remote_callbacks *callbacks) { callbacks->update_tips = (update_tips_cb)updateTipsCallback; } +git_remote_callbacks _go_git_remote_callbacks_init() { + git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; + return ret; +} + /* EOF */ From 32bf5f0a234e0c3cd00dc8eec349ee820f765f19 Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Mon, 6 Jan 2014 20:05:35 +0000 Subject: [PATCH 13/66] wip wrapping git_remote --- clone.go | 11 ++++ remote.go | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.c | 8 +++ 3 files changed, 212 insertions(+) diff --git a/clone.go b/clone.go index 672c325..425e179 100644 --- a/clone.go +++ b/clone.go @@ -37,6 +37,17 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) var copts C.git_clone_options populateCloneOptions(&copts, options) + // finish populating clone options here so we can defer CString free + if len(options.RemoteName) != 0 { + copts.remote_name = C.CString(options.RemoteName) + defer C.free(unsafe.Pointer(copts.remote_name)) + } + + if len(options.CheckoutBranch) != 0 { + copts.checkout_branch = C.CString(options.CheckoutBranch) + defer C.free(unsafe.Pointer(copts.checkout_branch)) + } + runtime.LockOSThread() defer runtime.UnlockOSThread() ret := C.git_clone(&repo.ptr, curl, cpath, &copts) diff --git a/remote.go b/remote.go index 0645291..5300c42 100644 --- a/remote.go +++ b/remote.go @@ -6,10 +6,13 @@ package git extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); extern git_remote_callbacks _go_git_remote_callbacks_init(); +extern void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n); +extern char *_go_git_get_strarray_n(git_strarray *array, size_t n); */ import "C" import "unsafe" +import "runtime" type TransferProgress struct { ptr *C.git_transfer_progress @@ -36,6 +39,30 @@ type RemoteCallbacks struct { UpdateTipsCallback } +type Remote interface { + Save() int + Owner() Repository + Name() string + Url() string + PushUrl() string + + SetUrl(url string) int + SetPushUrl(url string) int + + AddFetch(refspec string) int + GetFetchRefspecs() (err int, refspecs []string) + SetFetchRefspecs(refspecs []string) int + AddPush(refspec string) int + GetPushRefspecs() (err int, refspecs []string) + SetPushRefspecs(refspecs []string) int + ClearRefspecs() + RefspecCount() uint +} + +type gitRemote struct { + ptr *C.git_remote +} + func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { *ptr = C._go_git_remote_callbacks_init() if callbacks == nil { @@ -123,3 +150,169 @@ func (o TransferProgress) TotalDeltas() uint { func (o TransferProgress) ReceivedBytes() uint { return uint(o.ptr.received_bytes) } + +func RemoteIsValidName(name string) bool { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + if C.git_remote_is_valid_name(cname) == 1 { + return true + } + return false +} + +func freeRemote(o *gitRemote) { + C.git_remote_free(o.ptr) +} + +func CreateRemote(repo *Repository, name string, url string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + + ret := C.git_remote_create(&remote.ptr, repo.ptr, cname, curl) + return int(ret), remote +} + +func CreateRemoteWithFetchspec(repo *Repository, name string, url string, fetch string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + cfetch := C.CString(fetch) + defer C.free(unsafe.Pointer(cfetch)) + + ret := C.git_remote_create_with_fetchspec(&remote.ptr, repo.ptr, cname, curl, cfetch) + return int(ret), remote +} + +func CreateRemoteInMemory(repo *Repository, fetch string, url string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + cfetch := C.CString(fetch) + defer C.free(unsafe.Pointer(cfetch)) + + ret := C.git_remote_create_inmemory(&remote.ptr, repo.ptr, cfetch, curl) + return int(ret), remote +} + +func LoadRemote(repo *Repository, name string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_remote_load(&remote.ptr, repo.ptr, cname) + return int(ret), remote +} + +func (o *gitRemote) Save() int { + return int(C.git_remote_save(o.ptr)) +} + +func (o *gitRemote) Owner() Repository { + return Repository{C.git_remote_owner(o.ptr)} +} + +func (o *gitRemote) Name() string { + return C.GoString(C.git_remote_name(o.ptr)) +} + +func (o *gitRemote) Url() string { + return C.GoString(C.git_remote_url(o.ptr)) +} + +func (o *gitRemote) PushUrl() string { + return C.GoString(C.git_remote_pushurl(o.ptr)) +} + +func (o *gitRemote) SetUrl(url string) int { + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + return int(C.git_remote_set_url(o.ptr, curl)) +} + +func (o *gitRemote) SetPushUrl(url string) int { + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + return int(C.git_remote_set_pushurl(o.ptr, curl)) +} + +func (o *gitRemote) AddFetch(refspec string) int { + crefspec := C.CString(refspec) + defer C.free(unsafe.Pointer(crefspec)) + return int(C.git_remote_add_fetch(o.ptr, crefspec)) +} + +func (o *gitRemote) GetFetchRefspecs() (err int, refspecs []string) { + crefspecs := C.git_strarray{} + err = int(C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)) + defer C.git_strarray_free(&crefspecs) + refspecs = make([]string, crefspecs.count) + + for i := 0; i < int(crefspecs.count); i++ { + refspecs[i] = C.GoString(C._go_git_get_strarray_n(&crefspecs, C.size_t(i))) + } + return +} + +func (o *gitRemote) SetFetchRefspecs(refspecs []string) int { + crefspecs := C.git_strarray{} + crefspecs.count = C.size_t(len(refspecs)) + crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count)))) + for i, refspec := range refspecs { + C._go_git_set_strarray_n(&crefspecs, C.CString(refspec), C.size_t(i)) + } + defer C.git_strarray_free(&crefspecs) + + return int(C.git_remote_set_fetch_refspecs(o.ptr, &crefspecs)) +} + +func (o *gitRemote) AddPush(refspec string) int { + crefspec := C.CString(refspec) + defer C.free(unsafe.Pointer(crefspec)) + return int(C.git_remote_add_push(o.ptr, crefspec)) +} + +func (o *gitRemote) GetPushRefspecs() (err int, refspecs []string) { + crefspecs := C.git_strarray{} + err = int(C.git_remote_get_push_refspecs(&crefspecs, o.ptr)) + defer C.git_strarray_free(&crefspecs) + refspecs = make([]string, crefspecs.count) + + for i := 0; i < int(crefspecs.count); i++ { + refspecs[i] = C.GoString(C._go_git_get_strarray_n(&crefspecs, C.size_t(i))) + } + return +} + +func (o *gitRemote) SetPushRefspecs(refspecs []string) int { + crefspecs := C.git_strarray{} + crefspecs.count = C.size_t(len(refspecs)) + crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count)))) + for i, refspec := range refspecs { + C._go_git_set_strarray_n(&crefspecs, C.CString(refspec), C.size_t(i)) + } + defer C.git_strarray_free(&crefspecs) + + return int(C.git_remote_set_push_refspecs(o.ptr, &crefspecs)) +} + +func (o *gitRemote) ClearRefspecs() { + C.git_remote_clear_refspecs(o.ptr) +} + +func (o *gitRemote) RefspecCount() uint { + return uint(C.git_remote_refspec_count(o.ptr)) +} + diff --git a/wrapper.c b/wrapper.c index 4543822..7519a96 100644 --- a/wrapper.c +++ b/wrapper.c @@ -43,4 +43,12 @@ git_remote_callbacks _go_git_remote_callbacks_init() { return ret; } +void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n) { + array->strings[n] = str; +} + +char *_go_git_get_strarray_n(git_strarray *array, size_t n) { + return array->strings[n]; +} + /* EOF */ From 054268a63418b03892bfd4c6a509a0294660074b Mon Sep 17 00:00:00 2001 From: Tobias Haar Date: Fri, 24 Jan 2014 01:10:23 +0000 Subject: [PATCH 14/66] added write method --- index.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/index.go b/index.go index ac5148c..fb32010 100644 --- a/index.go +++ b/index.go @@ -49,6 +49,18 @@ func (v *Index) WriteTree() (*Oid, error) { return oid, nil } +func (v *Index) Write() (error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_index_write(v.ptr) + if ret < 0 { + return LastError() + } + + return nil +} + func (v *Index) Free() { runtime.SetFinalizer(v, nil) C.git_index_free(v.ptr) From 4ce2eb713bda2cb361f6d2b58502bea758ca980e Mon Sep 17 00:00:00 2001 From: Claudiu-Vlad Ursache Date: Sat, 25 Jan 2014 22:18:32 +0100 Subject: [PATCH 15/66] Add Odb hash function. --- odb.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/odb.go b/odb.go index 638ef74..6d18ce9 100644 --- a/odb.go +++ b/odb.go @@ -79,6 +79,22 @@ func (v *Odb) ForEach() chan *Oid { return ch } +// Hash determines the object-ID (sha1) of a data buffer. +func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) { + oid = new(Oid) + header := (*reflect.SliceHeader)(unsafe.Pointer(&data)) + ptr := (*C.char)(unsafe.Pointer(header.Data)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_odb_hash(oid.toC(), unsafe.Pointer(ptr), C.size_t(header.Len), C.git_otype(otype)); + if ret < 0 { + err = LastError() + } + return +} + // NewReadStream opens a read stream from the ODB. Reading from it will give you the // contents of the object. func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) { From 53f2ebce5f5124eff6b8e0ac2c45651d043899fa Mon Sep 17 00:00:00 2001 From: Claudiu-Vlad Ursache Date: Sat, 25 Jan 2014 22:18:43 +0100 Subject: [PATCH 16/66] Test for Odb hash function. --- odb_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/odb_test.go b/odb_test.go index 3c7624c..a4f8943 100644 --- a/odb_test.go +++ b/odb_test.go @@ -32,4 +32,31 @@ func TestOdbStream(t *testing.T) { if stream.Id.Cmp(expectedId) != 0 { t.Fatal("Wrong data written") } +} + +func TestOdbHash(t *testing.T) { + + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + _, _ = seedTestRepo(t, repo) + + odb, error := repo.Odb() + checkFatal(t, error) + + str := `tree 115fcae49287c82eb55bb275cbbd4556fbed72b7 +parent 66e1c476199ebcd3e304659992233132c5a52c6c +author John Doe 1390682018 +0000 +committer John Doe 1390682018 +0000 + +Initial commit.`; + + oid, error := odb.Hash([]byte(str), ObjectCommit) + checkFatal(t, error) + + coid, error := odb.Write([]byte(str), ObjectCommit) + checkFatal(t, error) + + if oid.Cmp(coid) != 0 { + t.Fatal("Hash and write Oids are different") + } } \ No newline at end of file From bf209ca2ba293116bdd3062ba9ff5ac071f9ddd5 Mon Sep 17 00:00:00 2001 From: Claudiu-Vlad Ursache Date: Sun, 26 Jan 2014 12:36:05 +0100 Subject: [PATCH 17/66] Remove unnecessary cast. --- odb.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/odb.go b/odb.go index 6d18ce9..953791c 100644 --- a/odb.go +++ b/odb.go @@ -83,12 +83,12 @@ func (v *Odb) ForEach() chan *Oid { func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) { oid = new(Oid) header := (*reflect.SliceHeader)(unsafe.Pointer(&data)) - ptr := (*C.char)(unsafe.Pointer(header.Data)) + ptr := unsafe.Pointer(header.Data) runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_odb_hash(oid.toC(), unsafe.Pointer(ptr), C.size_t(header.Len), C.git_otype(otype)); + ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype)); if ret < 0 { err = LastError() } From f66502aaf44862a8671285e80327d808afee155f Mon Sep 17 00:00:00 2001 From: Aidan Nulman Date: Wed, 29 Jan 2014 18:01:26 -0500 Subject: [PATCH 18/66] update git2go to support latest libgit2 development commit (id: 66af84) --- git.go | 20 ++++++++++---------- reference.go | 22 ++++++++++++++++++---- reference_test.go | 17 +++++++++++------ repository.go | 29 ++++++++++++++++++++++------- submodule.go | 12 ++++++++++-- 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/git.go b/git.go index 6f81293..c663d2e 100644 --- a/git.go +++ b/git.go @@ -9,8 +9,8 @@ import "C" import ( "bytes" "errors" - "unsafe" "strings" + "unsafe" ) const ( @@ -89,7 +89,7 @@ func (oid *Oid) Equal(oid2 *Oid) bool { } func (oid *Oid) IsZero() bool { - for _, a := range(oid.bytes) { + for _, a := range oid.bytes { if a != '0' { return false } @@ -123,10 +123,10 @@ func ShortenOids(ids []*Oid, minlen int) (int, error) { type GitError struct { Message string - Code int + Code int } -func (e GitError) Error() string{ +func (e GitError) Error() string { return e.Message } @@ -139,14 +139,14 @@ func LastError() error { } func cbool(b bool) C.int { - if (b) { + if b { return C.int(1) } return C.int(0) } func ucbool(b bool) C.uint { - if (b) { + if b { return C.uint(1) } return C.uint(0) @@ -159,13 +159,13 @@ func Discover(start string, across_fs bool, ceiling_dirs []string) (string, erro cstart := C.CString(start) defer C.free(unsafe.Pointer(cstart)) - retpath := (*C.char)(C.malloc(C.GIT_PATH_MAX)) - defer C.free(unsafe.Pointer(retpath)) + retpath := (*C.git_buf)(C.malloc(C.GIT_PATH_MAX)) + defer C.git_buf_free(retpath) - r := C.git_repository_discover(retpath, C.GIT_PATH_MAX, cstart, cbool(across_fs), ceildirs) + r := C.git_repository_discover(retpath, cstart, cbool(across_fs), ceildirs) if r == 0 { - return C.GoString(retpath), nil + return C.GoString(retpath.ptr), nil } return "", LastError() diff --git a/reference.go b/reference.go index 525e092..8060146 100644 --- a/reference.go +++ b/reference.go @@ -11,6 +11,7 @@ import ( ) type ReferenceType int + const ( ReferenceSymbolic ReferenceType = C.GIT_REF_SYMBOLIC ReferenceOid = C.GIT_REF_OID @@ -27,12 +28,19 @@ func newReferenceFromC(ptr *C.git_reference) *Reference { return ref } -func (v *Reference) SetSymbolicTarget(target string) (*Reference, error) { +func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string) (*Reference, error) { var ptr *C.git_reference + ctarget := C.CString(target) defer C.free(unsafe.Pointer(ctarget)) - ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget) + csig := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, csig, cmsg) if ret < 0 { return nil, LastError() } @@ -40,10 +48,16 @@ func (v *Reference) SetSymbolicTarget(target string) (*Reference, error) { return newReferenceFromC(ptr), nil } -func (v *Reference) SetTarget(target *Oid) (*Reference, error) { +func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Reference, error) { var ptr *C.git_reference - ret := C.git_reference_set_target(&ptr, v.ptr, target.toC()) + csig := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), csig, cmsg) if ret < 0 { return nil, LastError() } diff --git a/reference_test.go b/reference_test.go index f955a2c..ab62522 100644 --- a/reference_test.go +++ b/reference_test.go @@ -14,7 +14,14 @@ func TestRefModification(t *testing.T) { commitId, treeId := seedTestRepo(t, repo) - _, err := repo.CreateReference("refs/tags/tree", treeId, true) + 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") checkFatal(t, err) tag, err := repo.LookupReference("refs/tags/tree") @@ -78,13 +85,13 @@ func TestIterator(t *testing.T) { commitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree) checkFatal(t, err) - _, err = repo.CreateReference("refs/heads/one", commitId, true) + _, err = repo.CreateReference("refs/heads/one", commitId, true, sig, "headOne") checkFatal(t, err) - _, err = repo.CreateReference("refs/heads/two", commitId, true) + _, err = repo.CreateReference("refs/heads/two", commitId, true, sig, "headTwo") checkFatal(t, err) - _, err = repo.CreateReference("refs/heads/three", commitId, true) + _, err = repo.CreateReference("refs/heads/three", commitId, true, sig, "headThree") checkFatal(t, err) iter, err := repo.NewReferenceIterator() @@ -108,7 +115,6 @@ func TestIterator(t *testing.T) { t.Fatal("Iteration not over") } - sort.Strings(list) compareStringList(t, expected, list) @@ -129,7 +135,6 @@ func TestIterator(t *testing.T) { t.Fatalf("Wrong number of references returned %v", count) } - // test the channel iteration list = []string{} iter, err = repo.NewReferenceIterator() diff --git a/repository.go b/repository.go index 34df0aa..31a2d05 100644 --- a/repository.go +++ b/repository.go @@ -6,8 +6,8 @@ package git */ import "C" import ( - "unsafe" "runtime" + "unsafe" ) // Repository @@ -125,12 +125,19 @@ func (v *Repository) LookupReference(name string) (*Reference, error) { return newReferenceFromC(ptr), nil } -func (v *Repository) CreateReference(name string, oid *Oid, force bool) (*Reference, error) { +func (v *Repository) CreateReference(name string, oid *Oid, force bool, sig *Signature, msg string) (*Reference, error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) + + csig := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + var ptr *C.git_reference - ecode := C.git_reference_create(&ptr, v.ptr, cname, oid.toC(), cbool(force)) + ecode := C.git_reference_create(&ptr, v.ptr, cname, oid.toC(), cbool(force), csig, cmsg) if ecode < 0 { return nil, LastError() } @@ -138,14 +145,22 @@ func (v *Repository) CreateReference(name string, oid *Oid, force bool) (*Refere return newReferenceFromC(ptr), nil } -func (v *Repository) CreateSymbolicReference(name, target string, force bool) (*Reference, error) { +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 := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + var ptr *C.git_reference - ecode := C.git_reference_symbolic_create(&ptr, v.ptr, cname, ctarget, cbool(force)) + ecode := C.git_reference_symbolic_create(&ptr, v.ptr, cname, ctarget, cbool(force), csig, cmsg) if ecode < 0 { return nil, LastError() } @@ -180,7 +195,7 @@ func (v *Repository) CreateCommit( var cparents []*C.git_commit = nil var parentsarg **C.git_commit = nil - nparents:= len(parents) + nparents := len(parents) if nparents > 0 { cparents = make([]*C.git_commit, nparents) for i, v := range parents { @@ -226,7 +241,7 @@ func (repo *Repository) Path() string { return C.GoString(C.git_repository_path(repo.ptr)) } -func (repo *Repository) IsBare() (bool) { +func (repo *Repository) IsBare() bool { return C.git_repository_is_bare(repo.ptr) != 0 } diff --git a/submodule.go b/submodule.go index 9819b87..903d784 100644 --- a/submodule.go +++ b/submodule.go @@ -55,6 +55,14 @@ const ( SubmoduleStatusWdUntracked = C.GIT_SUBMODULE_STATUS_WD_UNTRACKED ) +type SubmoduleRecurse int + +const ( + SubmoduleRecurseNo SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_NO + SubmoduleRecurseYes = C.GIT_SUBMODULE_RECURSE_YES + SubmoduleRecurseOndemand = C.GIT_SUBMODULE_RECURSE_ONDEMAND +) + func SubmoduleStatusIsUnmodified(status int) bool { o := SubmoduleStatus(status) & ^(SubmoduleStatusInHead | SubmoduleStatusInIndex | SubmoduleStatusInConfig | SubmoduleStatusInWd) @@ -212,8 +220,8 @@ func (sub *Submodule) FetchRecurseSubmodules() bool { return true } -func (sub *Submodule) SetFetchRecurseSubmodules(v bool) error { - ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, cbool(v)) +func (sub *Submodule) SetFetchRecurseSubmodules(recurse SubmoduleRecurse) error { + ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, C.git_submodule_recurse_t(recurse)) if ret < 0 { return LastError() } From 53b5ecacbef4a149681734b32f7af3a42db66397 Mon Sep 17 00:00:00 2001 From: lye Date: Thu, 20 Feb 2014 00:24:11 -0600 Subject: [PATCH 19/66] Add Is$Type methods to Reference. This patch adds the following methods to Reference: IsBranch() bool IsRemote() bool IsTag() bool which correspond to the `git_reference_is_$type` functions in libgit2. --- reference.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/reference.go b/reference.go index 8e33354..24b5835 100644 --- a/reference.go +++ b/reference.go @@ -122,6 +122,18 @@ func (v *Reference) Type() ReferenceType { return ReferenceType(C.git_reference_type(v.ptr)) } +func (v *Reference) IsBranch() bool { + return C.git_reference_is_branch(v.ptr) == 1 +} + +func (v *Reference) IsRemote() bool { + return C.git_reference_is_remote(v.ptr) == 1 +} + +func (v *Reference) IsTag() bool { + return C.git_reference_is_tag(v.ptr) == 1 +} + func (v *Reference) Free() { runtime.SetFinalizer(v, nil) C.git_reference_free(v.ptr) From c6d1bde37cc7f3bd213fc182fd9f60a7cd685419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 23 Feb 2014 16:08:19 +0100 Subject: [PATCH 20/66] Return SubmoduleRecurse --- submodule.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/submodule.go b/submodule.go index fa1c436..9abf333 100644 --- a/submodule.go +++ b/submodule.go @@ -237,14 +237,10 @@ func (sub *Submodule) SetUpdate(update SubmoduleUpdate) SubmoduleUpdate { return SubmoduleUpdate(o) } -func (sub *Submodule) FetchRecurseSubmodules() bool { - if 0 == C.git_submodule_fetch_recurse_submodules(sub.ptr) { - return false - } - return true +func (sub *Submodule) FetchRecurseSubmodules() SubmoduleRecurse { + return SubmoduleRecurse(C.git_submodule_fetch_recurse_submodules(sub.ptr)); } - func (sub *Submodule) SetFetchRecurseSubmodules(recurse SubmoduleRecurse) error { runtime.LockOSThread() defer runtime.UnlockOSThread() From fbd8698002c3eb398215f6dd6778a34edff5c2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 11 Sep 2013 23:31:24 +0200 Subject: [PATCH 21/66] Add a few missing config setters and getters --- config.go | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/config.go b/config.go index 2aa073a..adaa069 100644 --- a/config.go +++ b/config.go @@ -14,7 +14,7 @@ type Config struct { ptr *C.git_config } -func (c *Config) LookupInt32(name string) (v int32, err error) { +func (c *Config) LookupInt32(name string) (int32, error) { var out C.int32_t cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -30,7 +30,7 @@ func (c *Config) LookupInt32(name string) (v int32, err error) { return int32(out), nil } -func (c *Config) LookupInt64(name string) (v int64, err error) { +func (c *Config) LookupInt64(name string) (int64, error) { var out C.int64_t cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -46,7 +46,7 @@ func (c *Config) LookupInt64(name string) (v int64, err error) { return int64(out), nil } -func (c *Config) LookupString(name string) (v string, err error) { +func (c *Config) LookupString(name string) (string, error) { var ptr *C.char cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -62,7 +62,21 @@ func (c *Config) LookupString(name string) (v string, err error) { return C.GoString(ptr), nil } -func (c *Config) Set(name, value string) (err error) { + +func (c *Config) LookupBool(name string) (bool, error) { + var out C.int + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_config_get_bool(&out, c.ptr, cname) + if ret < 0 { + return false, LastError() + } + + return out != 0, nil +} + +func (c *Config) SetString(name, value string) (err error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -84,3 +98,70 @@ func (c *Config) Free() { runtime.SetFinalizer(c, nil) C.git_config_free(c.ptr) } + +func (c *Config) SetInt32(name string, value int32) (err error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_config_set_int32(c.ptr, cname, C.int32_t(value)) + if ret < 0 { + return LastError() + } + + return nil +} + +func (c *Config) SetInt64(name string, value int64) (err error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_config_set_int64(c.ptr, cname, C.int64_t(value)) + if ret < 0 { + return LastError() + } + + return nil +} + +func (c *Config) SetBool(name string, value bool) (err error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_config_set_bool(c.ptr, cname, cbool(value)) + if ret < 0 { + return LastError() + } + + return nil +} + +func (c *Config) SetMultivar(name, regexp, value string) (err error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + cregexp := C.CString(regexp) + defer C.free(unsafe.Pointer(cregexp)) + + cvalue := C.CString(value) + defer C.free(unsafe.Pointer(cvalue)) + + ret := C.git_config_set_multivar(c.ptr, cname, cregexp, cvalue) + if ret < 0 { + return LastError() + } + + return nil +} + +func (c *Config) Delete(name string) error { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_config_delete_entry(c.ptr, cname) + + if ret < 0 { + return LastError() + } + + return nil +} From 129105d410a9fe188d64bab5833d9c13f981101f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Sep 2013 01:01:52 +0200 Subject: [PATCH 22/66] Add a few more missing config functions --- config.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/config.go b/config.go index adaa069..76d25c7 100644 --- a/config.go +++ b/config.go @@ -10,10 +10,61 @@ import ( "unsafe" ) +type ConfigLevel int + +const ( + // System-wide configuration file; /etc/gitconfig on Linux systems + ConfigLevelSystem ConfigLevel = C.GIT_CONFIG_LEVEL_SYSTEM + + // XDG compatible configuration file; typically ~/.config/git/config + ConfigLevelXDG ConfigLevel = C.GIT_CONFIG_LEVEL_XDG + + // User-specific configuration file (also called Global configuration + // file); typically ~/.gitconfig + ConfigLevelGlobal ConfigLevel = C.GIT_CONFIG_LEVEL_GLOBAL + + // Repository specific configuration file; $WORK_DIR/.git/config on + // non-bare repos + ConfigLevelLocal ConfigLevel = C.GIT_CONFIG_LEVEL_LOCAL + + // Application specific configuration file; freely defined by applications + ConfigLevelApp ConfigLevel = C.GIT_CONFIG_LEVEL_APP + + // Represents the highest level available config file (i.e. the most + // specific config file available that actually is loaded) + ConfigLevelHighest ConfigLevel = C.GIT_CONFIG_HIGHEST_LEVEL +) + + type Config struct { ptr *C.git_config } +// NewConfig creates a new empty configuration object +func NewConfig() (*Config, error) { + config := new(Config) + + ret := C.git_config_new(&config.ptr) + if ret < 0 { + return nil, LastError() + } + + return config, nil +} + +// AddFile adds a file-backed backend to the config object at the specified level. +func (c *Config) AddFile(path string, level ConfigLevel, force bool) error { + cpath := C.CString(path) + defer C.free(unsafe.Pointer(cpath)) + + ret := C.git_config_add_file_ondisk(c.ptr, cpath, C.git_config_level_t(level), cbool(force)) + if ret < 0 { + return LastError() + } + + return nil +} + func (c *Config) LookupInt32(name string) (int32, error) { var out C.int32_t cname := C.CString(name) @@ -165,3 +216,38 @@ func (c *Config) Delete(name string) error { return nil } + +// OpenLevel creates a single-level focused config object from a multi-level one +func (c *Config) OpenLevel(parent *Config, level ConfigLevel) (*Config, error) { + config := new(Config) + ret := C.git_config_open_level(&config.ptr, parent.ptr, C.git_config_level_t(level)) + if ret < 0 { + return nil, LastError() + } + + return config, nil +} + +// OpenOndisk creates a new config instance containing a single on-disk file +func OpenOndisk(parent *Config, path string) (*Config, error) { + cpath := C.CString(path) + defer C.free(unsafe.Pointer(cpath)) + + config := new(Config) + ret := C.git_config_open_ondisk(&config.ptr, cpath) + if ret < 0 { + return nil, LastError() + } + + return config, nil +} + +// Refresh refreshes the configuration to reflect any changes made externally e.g. on disk +func (c *Config) Refresh() error { + ret := C.git_config_refresh(c.ptr) + if ret < 0 { + return LastError() + } + + return nil +} From af2446b1da13a86df348e8f167a220a849619b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Sep 2013 01:39:35 +0200 Subject: [PATCH 23/66] Add iterators and ConfigEntry --- config.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/config.go b/config.go index 76d25c7..f1fafde 100644 --- a/config.go +++ b/config.go @@ -35,6 +35,19 @@ const ( ConfigLevelHighest ConfigLevel = C.GIT_CONFIG_HIGHEST_LEVEL ) +type ConfigEntry struct { + Name string + Value string + Level ConfigLevel +} + +func newConfigEntryFromC(centry *C.git_config_entry) *ConfigEntry { + return &ConfigEntry{ + Name: C.GoString(centry.name), + Value: C.GoString(centry.value), + Level: ConfigLevel(centry.level), + } +} type Config struct { ptr *C.git_config @@ -127,6 +140,55 @@ func (c *Config) LookupBool(name string) (bool, error) { return out != 0, nil } +func (c *Config) NewMultivarIterator(name, regexp string) (*ConfigIterator, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + var cregexp *C.char + if regexp == "" { + cregexp = nil + } else { + cregexp = C.CString(regexp) + defer C.free(unsafe.Pointer(cregexp)) + } + + iter := new(ConfigIterator) + ret := C.git_config_multivar_iterator_new(&iter.ptr, c.ptr, cname, cregexp) + if ret < 0 { + return nil, LastError() + } + + runtime.SetFinalizer(iter, (*ConfigIterator).Free) + return iter, nil +} + +// NewIterator creates an iterator over each entry in the +// configuration +func (c *Config) NewIterator() (*ConfigIterator, error) { + iter := new(ConfigIterator) + ret := C.git_config_iterator_new(&iter.ptr, c.ptr) + if ret < 0 { + return nil, LastError() + } + + return iter, nil +} + +// NewIteratorGlob creates an iterator over each entry in the +// configuration whose name matches the given regular expression +func (c *Config) NewIteratorGlob(regexp string) (*ConfigIterator, error) { + iter := new(ConfigIterator) + cregexp := C.CString(regexp) + defer C.free(unsafe.Pointer(cregexp)) + + ret := C.git_config_iterator_glob_new(&iter.ptr, c.ptr, cregexp) + if ret < 0 { + return nil, LastError() + } + + return iter, nil +} + func (c *Config) SetString(name, value string) (err error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -251,3 +313,25 @@ func (c *Config) Refresh() error { return nil } + +type ConfigIterator struct { + ptr *C.git_config_iterator +} + +// Next returns the next entry for this iterator +func (iter *ConfigIterator) Next() (*ConfigEntry, error) { + var centry *C.git_config_entry + + ret := C.git_config_next(¢ry, iter.ptr) + if ret < 0 { + return nil, LastError() + } + + return newConfigEntryFromC(centry), nil +} + +func (iter *ConfigIterator) Free() { + runtime.SetFinalizer(iter, nil) + C.free(unsafe.Pointer(iter.ptr)) +} + From fc0a2f56e892d9175289c89c627de66edcb7f778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 21 Sep 2013 23:01:37 +0200 Subject: [PATCH 24/66] Lock the thread so we can get the error message --- config.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/config.go b/config.go index f1fafde..7665b20 100644 --- a/config.go +++ b/config.go @@ -57,8 +57,10 @@ type Config struct { func NewConfig() (*Config, error) { config := new(Config) - ret := C.git_config_new(&config.ptr) - if ret < 0 { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if ret := C.git_config_new(&config.ptr); ret < 0 { return nil, LastError() } @@ -70,6 +72,10 @@ func (c *Config) AddFile(path string, level ConfigLevel, force bool) error { cpath := C.CString(path) defer C.free(unsafe.Pointer(cpath)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_config_add_file_ondisk(c.ptr, cpath, C.git_config_level_t(level), cbool(force)) if ret < 0 { return LastError() @@ -118,8 +124,7 @@ func (c *Config) LookupString(name string) (string, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_config_get_string(&ptr, c.ptr, cname) - if ret < 0 { + if ret := C.git_config_get_string(&ptr, c.ptr, cname); ret < 0 { return "", LastError() } @@ -132,6 +137,9 @@ func (c *Config) LookupBool(name string) (bool, error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_get_bool(&out, c.ptr, cname) if ret < 0 { return false, LastError() @@ -153,6 +161,10 @@ func (c *Config) NewMultivarIterator(name, regexp string) (*ConfigIterator, erro } iter := new(ConfigIterator) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_multivar_iterator_new(&iter.ptr, c.ptr, cname, cregexp) if ret < 0 { return nil, LastError() @@ -166,6 +178,10 @@ func (c *Config) NewMultivarIterator(name, regexp string) (*ConfigIterator, erro // configuration func (c *Config) NewIterator() (*ConfigIterator, error) { iter := new(ConfigIterator) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_iterator_new(&iter.ptr, c.ptr) if ret < 0 { return nil, LastError() @@ -181,6 +197,9 @@ func (c *Config) NewIteratorGlob(regexp string) (*ConfigIterator, error) { cregexp := C.CString(regexp) defer C.free(unsafe.Pointer(cregexp)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_iterator_glob_new(&iter.ptr, c.ptr, cregexp) if ret < 0 { return nil, LastError() @@ -228,6 +247,9 @@ func (c *Config) SetInt64(name string, value int64) (err error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_set_int64(c.ptr, cname, C.int64_t(value)) if ret < 0 { return LastError() @@ -240,6 +262,9 @@ func (c *Config) SetBool(name string, value bool) (err error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_set_bool(c.ptr, cname, cbool(value)) if ret < 0 { return LastError() @@ -258,6 +283,9 @@ func (c *Config) SetMultivar(name, regexp, value string) (err error) { cvalue := C.CString(value) defer C.free(unsafe.Pointer(cvalue)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_set_multivar(c.ptr, cname, cregexp, cvalue) if ret < 0 { return LastError() @@ -270,6 +298,9 @@ func (c *Config) Delete(name string) error { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_delete_entry(c.ptr, cname) if ret < 0 { @@ -282,6 +313,10 @@ func (c *Config) Delete(name string) error { // OpenLevel creates a single-level focused config object from a multi-level one func (c *Config) OpenLevel(parent *Config, level ConfigLevel) (*Config, error) { config := new(Config) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_config_open_level(&config.ptr, parent.ptr, C.git_config_level_t(level)) if ret < 0 { return nil, LastError() @@ -296,8 +331,11 @@ func OpenOndisk(parent *Config, path string) (*Config, error) { defer C.free(unsafe.Pointer(cpath)) config := new(Config) - ret := C.git_config_open_ondisk(&config.ptr, cpath) - if ret < 0 { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if ret := C.git_config_open_ondisk(&config.ptr, cpath); ret < 0 { return nil, LastError() } @@ -306,8 +344,10 @@ func OpenOndisk(parent *Config, path string) (*Config, error) { // Refresh refreshes the configuration to reflect any changes made externally e.g. on disk func (c *Config) Refresh() error { - ret := C.git_config_refresh(c.ptr) - if ret < 0 { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if ret := C.git_config_refresh(c.ptr); ret < 0 { return LastError() } From ca2c3c6db287f469736ff635167cd54f29b8a067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 26 Feb 2014 14:51:04 +0100 Subject: [PATCH 25/66] Add a few reference utility functions --- reference.go | 11 +++++++++++ reference_test.go | 27 ++++++++++++++++++++++++++ repository.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/reference.go b/reference.go index a2f1636..4a839a7 100644 --- a/reference.go +++ b/reference.go @@ -134,6 +134,17 @@ func (v *Reference) Delete() error { return nil } +// Cmp compares both references, retursn 0 on equality, otherwise a +// stable sorting. +func (v *Reference) Cmp(ref2 *Reference) int { + return int(C.git_reference_cmp(v.ptr, ref2.ptr)) +} + +// Shorthand returns a "human-readable" short reference name +func (v *Reference) Shorthand() string { + return C.GoString(C.git_reference_shorthand(v.ptr)) +} + func (v *Reference) Name() string { return C.GoString(C.git_reference_name(v.ptr)) } diff --git a/reference_test.go b/reference_test.go index 156960a..ffa9f35 100644 --- a/reference_test.go +++ b/reference_test.go @@ -159,6 +159,33 @@ func TestIterator(t *testing.T) { compareStringList(t, expected, list) } +func TestUtil(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + commitId, _ := seedTestRepo(t, repo) + + ref, err := repo.CreateReference("refs/heads/foo", commitId, true, nil, "") + checkFatal(t, err) + + ref2, err := repo.DwimReference("foo") + checkFatal(t, err) + + if ref.Cmp(ref2) != 0 { + t.Fatalf("foo didn't dwim to the right thing") + } + + if ref.Shorthand() != "foo" { + t.Fatalf("refs/heads/foo has no foo shorthand") + } + + hasLog, err := repo.HasLog("refs/heads/foo") + checkFatal(t, err) + if !hasLog { + t.Fatalf("branches ahve logs by default") + } +} + func compareStringList(t *testing.T, expected, actual []string) { for i, v := range expected { if actual[i] != v { diff --git a/repository.go b/repository.go index 48c2b46..5f0cd0b 100644 --- a/repository.go +++ b/repository.go @@ -331,3 +331,52 @@ func (v *Repository) RevparseSingle(spec string) (Object, error) { return allocObject(ptr), 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() + + if ret := C.git_reference_ensure_log(v.ptr, cname); ret < 0 { + return LastError() + } + + 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, LastError() + } + + 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 + if ret := C.git_reference_dwim(&ptr, v.ptr, cname); ret < 0 { + return nil, LastError() + } + + return newReferenceFromC(ptr), nil +} From 2c8de242eeff532feb5258d4f150739d307d7e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 26 Feb 2014 15:01:23 +0100 Subject: [PATCH 26/66] Allow for a default in reflog messages We don't have a way to represent a NULL string, so if the user passes an empty string, let's pass NULL down so we tell libgit2 to use the default. --- reference.go | 27 +++++++++++++++++++++------ repository.go | 18 ++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/reference.go b/reference.go index a2f1636..f7ea190 100644 --- a/reference.go +++ b/reference.go @@ -40,8 +40,13 @@ func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string) csig := sig.toC() defer C.free(unsafe.Pointer(csig)) - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, csig, cmsg) if ret < 0 { @@ -60,8 +65,13 @@ func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Referen csig := sig.toC() defer C.free(unsafe.Pointer(csig)) - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), csig, cmsg) if ret < 0 { @@ -93,8 +103,13 @@ func (v *Reference) Rename(name string, force bool, sig *Signature, msg string) csig := sig.toC() defer C.free(unsafe.Pointer(csig)) - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/repository.go b/repository.go index 48c2b46..e4eaaed 100644 --- a/repository.go +++ b/repository.go @@ -153,8 +153,13 @@ func (v *Repository) CreateReference(name string, oid *Oid, force bool, sig *Sig csig := sig.toC() defer C.free(unsafe.Pointer(csig)) - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } var ptr *C.git_reference @@ -179,8 +184,13 @@ func (v *Repository) CreateSymbolicReference(name, target string, force bool, si csig := sig.toC() defer C.free(unsafe.Pointer(csig)) - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } var ptr *C.git_reference From 1e01cae286652885432c3d65d0693363e1b4a05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 26 Feb 2014 15:18:47 +0100 Subject: [PATCH 27/66] Remove pointer to git_index_entry We have all the data --- index.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/index.go b/index.go index 90a49de..2bf3d04 100644 --- a/index.go +++ b/index.go @@ -18,7 +18,6 @@ type Index struct { } type IndexEntry struct { - ptr *C.git_index_entry Ctime time.Time Mtime time.Time Mode uint @@ -68,7 +67,6 @@ func (v *Index) EntryCount() uint { func newIndexEntryFromC(entry *C.git_index_entry) *IndexEntry { return &IndexEntry{ - entry, time.Unix(int64(entry.ctime.seconds), int64(entry.ctime.nanoseconds)), time.Unix(int64(entry.mtime.seconds), int64(entry.mtime.nanoseconds)), uint(entry.mode), From 14f902afed482faefc58aa3af005cb8f2a0b050d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 26 Feb 2014 15:22:48 +0100 Subject: [PATCH 28/66] Adjust to oid -> id --- index.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.go b/index.go index 2bf3d04..3ebb605 100644 --- a/index.go +++ b/index.go @@ -24,7 +24,7 @@ type IndexEntry struct { Uid uint Gid uint Size uint - Oid *Oid + Id *Oid Path string } @@ -73,7 +73,7 @@ func newIndexEntryFromC(entry *C.git_index_entry) *IndexEntry { uint(entry.uid), uint(entry.gid), uint(entry.file_size), - newOidFromC(&entry.oid), + newOidFromC(&entry.id), C.GoString(entry.path), } } From 3e5586bd8d532c929aecf778fc094e4f86588d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 26 Feb 2014 15:30:16 +0100 Subject: [PATCH 29/66] Remove 'oid' as id name Following the cleanup from libgit2, let's not use 'oid' unless we mean the name of the data type. In the other cases, we mean an identifier, hence the name 'id'. --- repository.go | 24 ++++++++++++------------ walk.go | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/repository.go b/repository.go index 48c2b46..1d58d7e 100644 --- a/repository.go +++ b/repository.go @@ -85,13 +85,13 @@ func (v *Repository) Index() (*Index, error) { return newIndexFromC(ptr), nil } -func (v *Repository) lookupType(oid *Oid, t ObjectType) (Object, error) { +func (v *Repository) lookupType(id *Oid, t ObjectType) (Object, error) { var ptr *C.git_object runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_object_lookup(&ptr, v.ptr, oid.toC(), C.git_otype(t)) + ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t)) if ret < 0 { return nil, LastError() } @@ -99,12 +99,12 @@ func (v *Repository) lookupType(oid *Oid, t ObjectType) (Object, error) { return allocObject(ptr), nil } -func (v *Repository) Lookup(oid *Oid) (Object, error) { - return v.lookupType(oid, ObjectAny) +func (v *Repository) Lookup(id *Oid) (Object, error) { + return v.lookupType(id, ObjectAny) } -func (v *Repository) LookupTree(oid *Oid) (*Tree, error) { - obj, err := v.lookupType(oid, ObjectTree) +func (v *Repository) LookupTree(id *Oid) (*Tree, error) { + obj, err := v.lookupType(id, ObjectTree) if err != nil { return nil, err } @@ -112,8 +112,8 @@ func (v *Repository) LookupTree(oid *Oid) (*Tree, error) { return obj.(*Tree), nil } -func (v *Repository) LookupCommit(oid *Oid) (*Commit, error) { - obj, err := v.lookupType(oid, ObjectCommit) +func (v *Repository) LookupCommit(id *Oid) (*Commit, error) { + obj, err := v.lookupType(id, ObjectCommit) if err != nil { return nil, err } @@ -121,8 +121,8 @@ func (v *Repository) LookupCommit(oid *Oid) (*Commit, error) { return obj.(*Commit), nil } -func (v *Repository) LookupBlob(oid *Oid) (*Blob, error) { - obj, err := v.lookupType(oid, ObjectBlob) +func (v *Repository) LookupBlob(id *Oid) (*Blob, error) { + obj, err := v.lookupType(id, ObjectBlob) if err != nil { return nil, err } @@ -146,7 +146,7 @@ func (v *Repository) LookupReference(name string) (*Reference, error) { return newReferenceFromC(ptr), nil } -func (v *Repository) CreateReference(name string, oid *Oid, force bool, sig *Signature, msg string) (*Reference, error) { +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)) @@ -161,7 +161,7 @@ func (v *Repository) CreateReference(name string, oid *Oid, force bool, sig *Sig runtime.LockOSThread() defer runtime.UnlockOSThread() - ecode := C.git_reference_create(&ptr, v.ptr, cname, oid.toC(), cbool(force), csig, cmsg) + ecode := C.git_reference_create(&ptr, v.ptr, cname, id.toC(), cbool(force), csig, cmsg) if ecode < 0 { return nil, LastError() } diff --git a/walk.go b/walk.go index 6979b6b..619188d 100644 --- a/walk.go +++ b/walk.go @@ -46,11 +46,11 @@ func (v *RevWalk) PushHead() (err error) { return } -func (v *RevWalk) Next(oid *Oid) (err error) { +func (v *RevWalk) Next(id *Oid) (err error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_revwalk_next(oid.toC(), v.ptr) + ret := C.git_revwalk_next(id.toC(), v.ptr) switch { case ret == ITEROVER: err = io.EOF From 499f52a3549503604f30663211361e2fbd3cf202 Mon Sep 17 00:00:00 2001 From: Jesper Hansen Date: Sun, 7 Jul 2013 16:43:44 +0200 Subject: [PATCH 30/66] Added git error code to the error object. --- checkout.go | 4 ++-- commit.go | 2 +- config.go | 8 ++++---- git.go | 27 ++++++++++++++++++--------- index.go | 4 ++-- odb.go | 4 ++-- packbuilder.go | 10 +++++----- reference.go | 16 ++++++++-------- repository.go | 31 ++++++++++++++++--------------- submodule.go | 26 +++++++++++++------------- tree.go | 6 +++--- walk.go | 4 ++-- 12 files changed, 76 insertions(+), 66 deletions(-) diff --git a/checkout.go b/checkout.go index f4c1d4e..d3cd47b 100644 --- a/checkout.go +++ b/checkout.go @@ -65,7 +65,7 @@ func (v *Repository) Checkout(opts *CheckoutOpts) error { ret := C.git_checkout_head(v.ptr, &copts) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -81,7 +81,7 @@ func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error { ret := C.git_checkout_index(v.ptr, index.ptr, &copts) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil diff --git a/commit.go b/commit.go index 0c64c76..0edebb6 100644 --- a/commit.go +++ b/commit.go @@ -31,7 +31,7 @@ func (c Commit) Tree() (*Tree, error) { err := C.git_commit_tree(&ptr, c.ptr) if err < 0 { - return nil, LastError() + return nil, MakeGitError(err) } return allocObject(ptr).(*Tree), nil diff --git a/config.go b/config.go index 7665b20..2234a43 100644 --- a/config.go +++ b/config.go @@ -94,7 +94,7 @@ func (c *Config) LookupInt32(name string) (int32, error) { ret := C.git_config_get_int32(&out, c.ptr, cname) if ret < 0 { - return 0, LastError() + return 0, MakeGitError(ret) } return int32(out), nil @@ -110,7 +110,7 @@ func (c *Config) LookupInt64(name string) (int64, error) { ret := C.git_config_get_int64(&out, c.ptr, cname) if ret < 0 { - return 0, LastError() + return 0, MakeGitError(ret) } return int64(out), nil @@ -125,7 +125,7 @@ func (c *Config) LookupString(name string) (string, error) { defer runtime.UnlockOSThread() if ret := C.git_config_get_string(&ptr, c.ptr, cname); ret < 0 { - return "", LastError() + return "", MakeGitError(ret) } return C.GoString(ptr), nil @@ -220,7 +220,7 @@ func (c *Config) SetString(name, value string) (err error) { ret := C.git_config_set_string(c.ptr, cname, cvalue) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil diff --git a/git.go b/git.go index 72ea33e..7c76c30 100644 --- a/git.go +++ b/git.go @@ -61,8 +61,8 @@ func NewOidFromString(s string) (*Oid, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - if C.git_oid_fromstr(o.toC(), cs) < 0 { - return nil, LastError() + if ret := C.git_oid_fromstr(o.toC(), cs); ret < 0 { + return nil, MakeGitError(ret) } return o, nil @@ -123,27 +123,36 @@ func ShortenOids(ids []*Oid, minlen int) (int, error) { buf[40] = 0 ret = C.git_oid_shorten_add(shorten, (*C.char)(unsafe.Pointer(&buf[0]))) if ret < 0 { - return int(ret), LastError() + return int(ret), MakeGitError(ret) } } return int(ret), nil } type GitError struct { - Message string - Code int + Message string + Class int + ErrorCode int } func (e GitError) Error() string { return e.Message } -func LastError() error { +func IsNotExist(err error) bool { + return err.(*GitError).ErrorCode == C.GIT_ENOTFOUND +} + +func IsExist(err error) bool { + return err.(*GitError).ErrorCode == C.GIT_EEXISTS +} + +func MakeGitError(errorCode C.int) error { err := C.giterr_last() if err == nil { - return &GitError{"No message", 0} + return &GitError{"No message", C.GITERR_INVALID, C.GIT_ERROR} } - return &GitError{C.GoString(err.message), int(err.klass)} + return &GitError{C.GoString(err.message), int(err.klass), int(errorCode)} } func cbool(b bool) C.int { @@ -175,7 +184,7 @@ func Discover(start string, across_fs bool, ceiling_dirs []string) (string, erro ret := C.git_repository_discover(&buf, cstart, cbool(across_fs), ceildirs) if ret < 0 { - return "", LastError() + return "", MakeGitError(ret) } return C.GoString(buf.ptr), nil diff --git a/index.go b/index.go index bc11025..cbb28c4 100644 --- a/index.go +++ b/index.go @@ -42,7 +42,7 @@ func (v *Index) AddByPath(path string) error { ret := C.git_index_add_bypath(v.ptr, cstr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -56,7 +56,7 @@ func (v *Index) WriteTree() (*Oid, error) { ret := C.git_index_write_tree(oid.toC(), v.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return oid, nil diff --git a/odb.go b/odb.go index 953791c..3daf3a4 100644 --- a/odb.go +++ b/odb.go @@ -32,7 +32,7 @@ func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) { ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(hdr.Data), C.size_t(hdr.Len), C.git_otype(otype)) if ret < 0 { - err = LastError() + err = MakeGitError(ret) } return @@ -46,7 +46,7 @@ func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) { ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC()) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(obj, (*OdbObject).Free) diff --git a/packbuilder.go b/packbuilder.go index 333f183..70c4530 100644 --- a/packbuilder.go +++ b/packbuilder.go @@ -28,7 +28,7 @@ func (repo *Repository) NewPackbuilder() (*Packbuilder, error) { ret := C.git_packbuilder_new(&builder.ptr, repo.ptr) if ret != 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(builder, (*Packbuilder).Free) return builder, nil @@ -48,7 +48,7 @@ func (pb *Packbuilder) Insert(id *Oid, name string) error { ret := C.git_packbuilder_insert(pb.ptr, id.toC(), cname) if ret != 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -59,7 +59,7 @@ func (pb *Packbuilder) InsertCommit(id *Oid) error { ret := C.git_packbuilder_insert_commit(pb.ptr, id.toC()) if ret != 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -70,7 +70,7 @@ func (pb *Packbuilder) InsertTree(id *Oid) error { ret := C.git_packbuilder_insert_tree(pb.ptr, id.toC()) if ret != 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -88,7 +88,7 @@ func (pb *Packbuilder) WriteToFile(name string, mode os.FileMode) error { ret := C.git_packbuilder_write(pb.ptr, cname, C.uint(mode.Perm()), nil, nil) if ret != 0 { - return LastError() + return MakeGitError(ret) } return nil } diff --git a/reference.go b/reference.go index a2f1636..39d328e 100644 --- a/reference.go +++ b/reference.go @@ -45,7 +45,7 @@ func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string) ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, csig, cmsg) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newReferenceFromC(ptr), nil @@ -65,7 +65,7 @@ func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Referen ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), csig, cmsg) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newReferenceFromC(ptr), nil @@ -79,7 +79,7 @@ func (v *Reference) Resolve() (*Reference, error) { ret := C.git_reference_resolve(&ptr, v.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newReferenceFromC(ptr), nil @@ -102,7 +102,7 @@ func (v *Reference) Rename(name string, force bool, sig *Signature, msg string) ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force), csig, cmsg) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newReferenceFromC(ptr), nil @@ -128,7 +128,7 @@ func (v *Reference) Delete() error { ret := C.git_reference_delete(v.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -173,7 +173,7 @@ func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) { ret := C.git_reference_iterator_new(&ptr, repo.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } iter := &ReferenceIterator{repo: repo, ptr: ptr} @@ -194,7 +194,7 @@ func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterato ret := C.git_reference_iterator_glob_new(&ptr, repo.ptr, cstr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } iter := &ReferenceIterator{repo: repo, ptr: ptr} @@ -215,7 +215,7 @@ func (v *ReferenceIterator) NextName() (string, error) { return "", ErrIterOver } if ret < 0 { - return "", LastError() + return "", MakeGitError(ret) } return C.GoString(ptr), nil diff --git a/repository.go b/repository.go index 1d58d7e..e78422e 100644 --- a/repository.go +++ b/repository.go @@ -26,7 +26,7 @@ func OpenRepository(path string) (*Repository, error) { ret := C.git_repository_open(&repo.ptr, cpath) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(repo, (*Repository).Free) @@ -44,7 +44,7 @@ func InitRepository(path string, isbare bool) (*Repository, error) { ret := C.git_repository_init(&repo.ptr, cpath, ucbool(isbare)) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(repo, (*Repository).Free) @@ -64,7 +64,7 @@ func (v *Repository) Config() (*Config, error) { ret := C.git_repository_config(&config.ptr, v.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(config, (*Config).Free) @@ -79,7 +79,7 @@ func (v *Repository) Index() (*Index, error) { ret := C.git_repository_index(&ptr, v.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newIndexFromC(ptr), nil @@ -93,7 +93,7 @@ func (v *Repository) lookupType(id *Oid, t ObjectType) (Object, error) { ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t)) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return allocObject(ptr), nil @@ -140,7 +140,7 @@ func (v *Repository) LookupReference(name string) (*Reference, error) { ecode := C.git_reference_lookup(&ptr, v.ptr, cname) if ecode < 0 { - return nil, LastError() + return nil, MakeGitError(ecode) } return newReferenceFromC(ptr), nil @@ -163,7 +163,7 @@ func (v *Repository) CreateReference(name string, id *Oid, force bool, sig *Sign ecode := C.git_reference_create(&ptr, v.ptr, cname, id.toC(), cbool(force), csig, cmsg) if ecode < 0 { - return nil, LastError() + return nil, MakeGitError(ecode) } return newReferenceFromC(ptr), nil @@ -189,7 +189,7 @@ func (v *Repository) CreateSymbolicReference(name, target string, force bool, si ecode := C.git_reference_symbolic_create(&ptr, v.ptr, cname, ctarget, cbool(force), csig, cmsg) if ecode < 0 { - return nil, LastError() + return nil, MakeGitError(ecode) } return newReferenceFromC(ptr), nil @@ -203,7 +203,7 @@ func (v *Repository) Walk() (*RevWalk, error) { ecode := C.git_revwalk_new(&walk.ptr, v.ptr) if ecode < 0 { - return nil, LastError() + return nil, MakeGitError(ecode) } walk.repo = v @@ -250,7 +250,7 @@ func (v *Repository) CreateCommit( nil, cmsg, tree.ptr, C.size_t(nparents), parentsarg) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return oid, nil @@ -268,7 +268,7 @@ func (v *Repository) Odb() (odb *Odb, err error) { defer runtime.UnlockOSThread() if ret := C.git_repository_odb(&odb.ptr, v.ptr); ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(odb, (*Odb).Free) @@ -294,9 +294,10 @@ func (repo *Repository) SetWorkdir(workdir string, updateGitlink bool) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - if C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)) < 0 { - return LastError() + if ret := C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)); ret < 0 { + return MakeGitError(ret) } + return nil } @@ -307,7 +308,7 @@ func (v *Repository) TreeBuilder() (*TreeBuilder, error) { defer runtime.UnlockOSThread() if ret := C.git_treebuilder_create(&bld.ptr, nil); ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(bld, (*TreeBuilder).Free) @@ -326,7 +327,7 @@ func (v *Repository) RevparseSingle(spec string) (Object, error) { ecode := C.git_revparse_single(&ptr, v.ptr, cspec) if ecode < 0 { - return nil, LastError() + return nil, MakeGitError(ecode) } return allocObject(ptr), nil diff --git a/submodule.go b/submodule.go index 9abf333..8390e36 100644 --- a/submodule.go +++ b/submodule.go @@ -81,7 +81,7 @@ func (repo *Repository) LookupSubmodule(name string) (*Submodule, error) { ret := C.git_submodule_lookup(&sub.ptr, repo.ptr, cname) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return sub, nil @@ -102,7 +102,7 @@ func (repo *Repository) ForeachSubmodule(cbk SubmoduleCbk) error { ret := C._go_git_visit_submodule(repo.ptr, unsafe.Pointer(&cbk)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -120,7 +120,7 @@ func (repo *Repository) AddSubmodule(url, path string, use_git_link bool) (*Subm ret := C.git_submodule_add_setup(&sub.ptr, repo.ptr, curl, cpath, cbool(use_git_link)) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return sub, nil } @@ -131,7 +131,7 @@ func (sub *Submodule) FinalizeAdd() error { ret := C.git_submodule_add_finalize(sub.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -142,7 +142,7 @@ func (sub *Submodule) AddToIndex(write_index bool) error { ret := C.git_submodule_add_to_index(sub.ptr, cbool(write_index)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -153,7 +153,7 @@ func (sub *Submodule) Save() error { ret := C.git_submodule_save(sub.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -188,7 +188,7 @@ func (sub *Submodule) SetUrl(url string) error { ret := C.git_submodule_set_url(sub.ptr, curl) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -247,7 +247,7 @@ func (sub *Submodule) SetFetchRecurseSubmodules(recurse SubmoduleRecurse) error ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, C.git_submodule_recurse_t(recurse)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -258,7 +258,7 @@ func (sub *Submodule) Init(overwrite bool) error { ret := C.git_submodule_init(sub.ptr, cbool(overwrite)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -269,7 +269,7 @@ func (sub *Submodule) Sync() error { ret := C.git_submodule_sync(sub.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -282,7 +282,7 @@ func (sub *Submodule) Open() (*Repository, error) { ret := C.git_submodule_open(&repo.ptr, sub.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return repo, nil } @@ -293,7 +293,7 @@ func (sub *Submodule) Reload() error { ret := C.git_submodule_reload(sub.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } @@ -304,7 +304,7 @@ func (repo *Repository) ReloadAllSubmodules() error { ret := C.git_submodule_reload_all(repo.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil } diff --git a/tree.go b/tree.go index 8c74e5d..4efb589 100644 --- a/tree.go +++ b/tree.go @@ -109,7 +109,7 @@ func (t Tree) Walk(callback TreeWalkCallback) error { ) if err < 0 { - return LastError() + return MakeGitError(err) } return nil @@ -134,7 +134,7 @@ func (v *TreeBuilder) Insert(filename string, id *Oid, filemode int) (error) { err := C.git_treebuilder_insert(nil, v.ptr, cfilename, id.toC(), C.git_filemode_t(filemode)) if err < 0 { - return LastError() + return MakeGitError(err) } return nil @@ -149,7 +149,7 @@ func (v *TreeBuilder) Write() (*Oid, error) { err := C.git_treebuilder_write(oid.toC(), v.repo.ptr, v.ptr) if err < 0 { - return nil, LastError() + return nil, MakeGitError(err) } return oid, nil diff --git a/walk.go b/walk.go index 619188d..cdc1a20 100644 --- a/walk.go +++ b/walk.go @@ -40,7 +40,7 @@ func (v *RevWalk) PushHead() (err error) { ecode := C.git_revwalk_push_head(v.ptr) if ecode < 0 { - err = LastError() + err = MakeGitError(ecode) } return @@ -55,7 +55,7 @@ func (v *RevWalk) Next(id *Oid) (err error) { case ret == ITEROVER: err = io.EOF case ret < 0: - err = LastError() + err = MakeGitError(ret) } return From 00ea11691b574b8372cb216427d98038e107e358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 26 Feb 2014 16:14:31 +0100 Subject: [PATCH 31/66] Convert the rest of the errors --- config.go | 30 +++++++++++++++--------------- index.go | 2 +- odb.go | 12 ++++++------ reference.go | 2 +- submodule.go | 2 +- tree.go | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/config.go b/config.go index 2234a43..6b1f093 100644 --- a/config.go +++ b/config.go @@ -61,7 +61,7 @@ func NewConfig() (*Config, error) { defer runtime.UnlockOSThread() if ret := C.git_config_new(&config.ptr); ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return config, nil @@ -78,7 +78,7 @@ func (c *Config) AddFile(path string, level ConfigLevel, force bool) error { ret := C.git_config_add_file_ondisk(c.ptr, cpath, C.git_config_level_t(level), cbool(force)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -142,7 +142,7 @@ func (c *Config) LookupBool(name string) (bool, error) { ret := C.git_config_get_bool(&out, c.ptr, cname) if ret < 0 { - return false, LastError() + return false, MakeGitError(ret) } return out != 0, nil @@ -167,7 +167,7 @@ func (c *Config) NewMultivarIterator(name, regexp string) (*ConfigIterator, erro ret := C.git_config_multivar_iterator_new(&iter.ptr, c.ptr, cname, cregexp) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(iter, (*ConfigIterator).Free) @@ -184,7 +184,7 @@ func (c *Config) NewIterator() (*ConfigIterator, error) { ret := C.git_config_iterator_new(&iter.ptr, c.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return iter, nil @@ -202,7 +202,7 @@ func (c *Config) NewIteratorGlob(regexp string) (*ConfigIterator, error) { ret := C.git_config_iterator_glob_new(&iter.ptr, c.ptr, cregexp) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return iter, nil @@ -237,7 +237,7 @@ func (c *Config) SetInt32(name string, value int32) (err error) { ret := C.git_config_set_int32(c.ptr, cname, C.int32_t(value)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -252,7 +252,7 @@ func (c *Config) SetInt64(name string, value int64) (err error) { ret := C.git_config_set_int64(c.ptr, cname, C.int64_t(value)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -267,7 +267,7 @@ func (c *Config) SetBool(name string, value bool) (err error) { ret := C.git_config_set_bool(c.ptr, cname, cbool(value)) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -288,7 +288,7 @@ func (c *Config) SetMultivar(name, regexp, value string) (err error) { ret := C.git_config_set_multivar(c.ptr, cname, cregexp, cvalue) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -304,7 +304,7 @@ func (c *Config) Delete(name string) error { ret := C.git_config_delete_entry(c.ptr, cname) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -319,7 +319,7 @@ func (c *Config) OpenLevel(parent *Config, level ConfigLevel) (*Config, error) { ret := C.git_config_open_level(&config.ptr, parent.ptr, C.git_config_level_t(level)) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return config, nil @@ -336,7 +336,7 @@ func OpenOndisk(parent *Config, path string) (*Config, error) { defer runtime.UnlockOSThread() if ret := C.git_config_open_ondisk(&config.ptr, cpath); ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return config, nil @@ -348,7 +348,7 @@ func (c *Config) Refresh() error { defer runtime.UnlockOSThread() if ret := C.git_config_refresh(c.ptr); ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -364,7 +364,7 @@ func (iter *ConfigIterator) Next() (*ConfigEntry, error) { ret := C.git_config_next(¢ry, iter.ptr) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newConfigEntryFromC(centry), nil diff --git a/index.go b/index.go index cbb28c4..6da3c98 100644 --- a/index.go +++ b/index.go @@ -68,7 +68,7 @@ func (v *Index) Write() (error) { ret := C.git_index_write(v.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil diff --git a/odb.go b/odb.go index 3daf3a4..daf63dd 100644 --- a/odb.go +++ b/odb.go @@ -90,7 +90,7 @@ func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) { ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype)); if ret < 0 { - err = LastError() + err = MakeGitError(ret) } return } @@ -101,7 +101,7 @@ func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) { stream := new(OdbReadStream) ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC()) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(stream, (*OdbReadStream).Free) @@ -115,7 +115,7 @@ func (v *Odb) NewWriteStream(size int, otype ObjectType) (*OdbWriteStream, error stream := new(OdbWriteStream) ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.size_t(size), C.git_otype(otype)) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } runtime.SetFinalizer(stream, (*OdbWriteStream).Free) @@ -164,7 +164,7 @@ func (stream *OdbReadStream) Read(data []byte) (int, error) { size := C.size_t(header.Cap) ret := C.git_odb_stream_read(stream.ptr, ptr, size) if ret < 0 { - return 0, LastError() + return 0, MakeGitError(ret) } header.Len = int(ret) @@ -196,7 +196,7 @@ func (stream *OdbWriteStream) Write(data []byte) (int, error) { ret := C.git_odb_stream_write(stream.ptr, ptr, size) if ret < 0 { - return 0, LastError() + return 0, MakeGitError(ret) } return len(data), nil @@ -207,7 +207,7 @@ func (stream *OdbWriteStream) Write(data []byte) (int, error) { func (stream *OdbWriteStream) Close() error { ret := C.git_odb_stream_finalize_write(stream.Id.toC(), stream.ptr) if ret < 0 { - return LastError() + return MakeGitError(ret) } return nil diff --git a/reference.go b/reference.go index 39d328e..45a3b22 100644 --- a/reference.go +++ b/reference.go @@ -247,7 +247,7 @@ func (v *ReferenceIterator) Next() (*Reference, error) { return nil, ErrIterOver } if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newReferenceFromC(ptr), nil diff --git a/submodule.go b/submodule.go index 8390e36..dcc4723 100644 --- a/submodule.go +++ b/submodule.go @@ -247,7 +247,7 @@ func (sub *Submodule) SetFetchRecurseSubmodules(recurse SubmoduleRecurse) error ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, C.git_submodule_recurse_t(recurse)) if ret < 0 { - return MakeGitError(ret) + return MakeGitError(C.int(ret)) } return nil } diff --git a/tree.go b/tree.go index 4efb589..b3340d6 100644 --- a/tree.go +++ b/tree.go @@ -67,7 +67,7 @@ func (t Tree) EntryByPath(path string) (*TreeEntry, error) { ret := C.git_tree_entry_bypath(&entry, t.ptr, cpath) if ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newTreeEntry(entry), nil From a728f70358ab58364c643d04c94a66b3ec2cd947 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 26 Feb 2014 07:33:50 -0800 Subject: [PATCH 32/66] cleanup add-branch --- branch.go | 68 +++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/branch.go b/branch.go index d30748f..ba82f93 100644 --- a/branch.go +++ b/branch.go @@ -14,26 +14,33 @@ import ( type BranchType uint const ( - BRANCH_LOCAL BranchType = C.GIT_BRANCH_LOCAL - BRANCH_REMOTE = C.GIT_BRANCH_REMOTE + BranchLocal BranchType = C.GIT_BRANCH_LOCAL + BranchRemote = C.GIT_BRANCH_REMOTE ) const ( - REFS_DIR = "refs/" - REFS_HEADS_DIR = REFS_DIR + "heads/" - REFS_TAGS_DIR = REFS_DIR + "tags/" - REFS_REMOTES_DIR = REFS_DIR + "remotes/" + RefsDir = "refs/" + RefsHeadsDir = RefsDir + "heads/" + RefsTagsDir = RefsDir + "tags/" + RefsRemotesDir = RefsDir + "remotes/" ) type Branch struct { Reference } -func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool) (*Reference, error) { +func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, message string) (*Reference, error) { ref := new(Reference) cBranchName := C.CString(branchName) cForce := cbool(force) - err := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce) + + cSignature := signature.toC() + defer C.git_signature_free(cSignature) + + cMessage := C.CString(message) + defer C.free(unsafe.Pointer(cMessage)) + + err := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce, cSignature, cMessage) if err < 0 { return nil, LastError() } @@ -47,12 +54,18 @@ func (b *Branch) BranchDelete() error { return nil } -func (b *Branch) Move(newBranchName string, force bool) (*Branch, error) { +func (b *Branch) Move(newBranchName string, force bool, signature *Signature, message string) (*Branch, error) { newBranch := new(Branch) cNewBranchName := C.CString(newBranchName) cForce := cbool(force) - err := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce) + cSignature := signature.toC() + defer C.git_signature_free(cSignature) + + cMessage := C.CString(message) + defer C.free(unsafe.Pointer(cMessage)) + + err := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cMessage) if err < 0 { return nil, LastError() } @@ -98,22 +111,14 @@ func (b *Branch) Name() (string, error) { func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { cName := C.CString(canonicalBranchName) - // Obtain the length of the name - ret := C.git_branch_remote_name(nil, 0, repo.ptr, cName) - if ret < 0 { + nameBuf := C.git_buf{} + + if C.git_branch_remote_name(&nameBuf, repo.ptr, cName) < 0 { return "", LastError() } + C.git_buf_free(&nameBuf) - cBuf := (*C.char)(C.malloc(C.size_t(ret))) - defer C.free(unsafe.Pointer(cBuf)) - - // Actually obtain the name - ret = C.git_branch_remote_name(cBuf, C.size_t(ret), repo.ptr, cName) - if ret < 0 { - return "", LastError() - } - - return C.GoString(cBuf), nil + return C.GoStringN(nameBuf.ptr, C.int(nameBuf.size)), nil } func (b *Branch) SetUpstream(upstreamName string) error { @@ -138,19 +143,12 @@ func (b *Branch) Upstream() (*Branch, error) { func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) { cName := C.CString(canonicalBranchName) - // Obtain the length of the name - ret := C.git_branch_upstream_name(nil, 0, repo.ptr, cName) - if ret < 0 { + nameBuf := C.git_buf{} + + if C.git_branch_upstream_name(&nameBuf, repo.ptr, cName) < 0 { return "", LastError() } + C.git_buf_free(&nameBuf) - cBuf := (*C.char)(C.malloc(C.size_t(ret))) - defer C.free(unsafe.Pointer(cBuf)) - - // Actually obtain the name - ret = C.git_branch_upstream_name(cBuf, C.size_t(ret), repo.ptr, cName) - if ret < 0 { - return "", LastError() - } - return C.GoString(cBuf), nil + return C.GoStringN(nameBuf.ptr, C.int(nameBuf.size)), nil } From fe509411a5e8bd45a1c5607d1cc212d8ebf45541 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 26 Feb 2014 08:45:38 -0800 Subject: [PATCH 33/66] Add thread locking --- branch.go | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/branch.go b/branch.go index ba82f93..77dbbb8 100644 --- a/branch.go +++ b/branch.go @@ -8,6 +8,7 @@ package git import "C" import ( + "runtime" "unsafe" ) @@ -30,6 +31,7 @@ type Branch struct { } func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, message string) (*Reference, error) { + ref := new(Reference) cBranchName := C.CString(branchName) cForce := cbool(force) @@ -40,6 +42,9 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo cMessage := C.CString(message) defer C.free(unsafe.Pointer(cMessage)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + err := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce, cSignature, cMessage) if err < 0 { return nil, LastError() @@ -47,7 +52,11 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo return ref, nil } -func (b *Branch) BranchDelete() error { +func (b *Branch) Delete() error { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if err := C.git_branch_delete(b.ptr); err < 0 { return LastError() } @@ -65,6 +74,9 @@ func (b *Branch) Move(newBranchName string, force bool, signature *Signature, me cMessage := C.CString(message) defer C.free(unsafe.Pointer(cMessage)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + err := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cMessage) if err < 0 { return nil, LastError() @@ -73,6 +85,10 @@ func (b *Branch) Move(newBranchName string, force bool, signature *Signature, me } func (b *Branch) IsHead() (bool, error) { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + isHead := C.git_branch_is_head(b.ptr) switch isHead { case 1: @@ -89,6 +105,9 @@ func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Branch, branch := new(Branch) cName := C.CString(branchName) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + err := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(bt)) if err < 0 { return nil, LastError() @@ -100,6 +119,9 @@ func (b *Branch) Name() (string, error) { var cName *C.char defer C.free(unsafe.Pointer(cName)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + err := C.git_branch_name(&cName, b.ptr) if err < 0 { return "", LastError() @@ -113,6 +135,9 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { nameBuf := C.git_buf{} + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if C.git_branch_remote_name(&nameBuf, repo.ptr, cName) < 0 { return "", LastError() } @@ -124,6 +149,9 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { func (b *Branch) SetUpstream(upstreamName string) error { cName := C.CString(upstreamName) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + err := C.git_branch_set_upstream(b.ptr, cName) if err < 0 { return LastError() @@ -133,6 +161,10 @@ func (b *Branch) SetUpstream(upstreamName string) error { func (b *Branch) Upstream() (*Branch, error) { upstream := new(Branch) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + err := C.git_branch_upstream(&upstream.ptr, b.ptr) if err < 0 { return nil, LastError() @@ -145,6 +177,9 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) nameBuf := C.git_buf{} + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if C.git_branch_upstream_name(&nameBuf, repo.ptr, cName) < 0 { return "", LastError() } From a5df6111003cb032911a793f186aefb8f27243ef Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 26 Feb 2014 08:50:47 -0800 Subject: [PATCH 34/66] LastError -> MakeGitError --- branch.go | 58 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/branch.go b/branch.go index 77dbbb8..68e1b93 100644 --- a/branch.go +++ b/branch.go @@ -45,9 +45,9 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce, cSignature, cMessage) - if err < 0 { - return nil, LastError() + ret := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce, cSignature, cMessage) + if ret < 0 { + return nil, MakeGitError(ret) } return ref, nil } @@ -56,9 +56,9 @@ func (b *Branch) Delete() error { runtime.LockOSThread() defer runtime.UnlockOSThread() - - if err := C.git_branch_delete(b.ptr); err < 0 { - return LastError() + ret := C.git_branch_delete(b.ptr) + if ret < 0 { + return MakeGitError(ret) } return nil } @@ -77,9 +77,9 @@ func (b *Branch) Move(newBranchName string, force bool, signature *Signature, me runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cMessage) - if err < 0 { - return nil, LastError() + ret := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cMessage) + if ret < 0 { + return nil, MakeGitError(ret) } return newBranch, nil } @@ -89,14 +89,14 @@ func (b *Branch) IsHead() (bool, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - isHead := C.git_branch_is_head(b.ptr) - switch isHead { + ret := C.git_branch_is_head(b.ptr) + switch ret { case 1: return true, nil case 0: return false, nil default: - return false, LastError() + return false, MakeGitError(ret) } } @@ -108,9 +108,9 @@ func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Branch, runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(bt)) - if err < 0 { - return nil, LastError() + ret := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(bt)) + if ret < 0 { + return nil, MakeGitError(ret) } return branch, nil } @@ -122,9 +122,9 @@ func (b *Branch) Name() (string, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C.git_branch_name(&cName, b.ptr) - if err < 0 { - return "", LastError() + ret := C.git_branch_name(&cName, b.ptr) + if ret < 0 { + return "", MakeGitError(ret) } return C.GoString(cName), nil @@ -138,8 +138,9 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - if C.git_branch_remote_name(&nameBuf, repo.ptr, cName) < 0 { - return "", LastError() + ret := C.git_branch_remote_name(&nameBuf, repo.ptr, cName) + if ret < 0 { + return "", MakeGitError(ret) } C.git_buf_free(&nameBuf) @@ -152,9 +153,9 @@ func (b *Branch) SetUpstream(upstreamName string) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C.git_branch_set_upstream(b.ptr, cName) - if err < 0 { - return LastError() + ret := C.git_branch_set_upstream(b.ptr, cName) + if ret < 0 { + return MakeGitError(ret) } return nil } @@ -165,9 +166,9 @@ func (b *Branch) Upstream() (*Branch, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C.git_branch_upstream(&upstream.ptr, b.ptr) - if err < 0 { - return nil, LastError() + ret := C.git_branch_upstream(&upstream.ptr, b.ptr) + if ret < 0 { + return nil, MakeGitError(ret) } return upstream, nil } @@ -180,8 +181,9 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) runtime.LockOSThread() defer runtime.UnlockOSThread() - if C.git_branch_upstream_name(&nameBuf, repo.ptr, cName) < 0 { - return "", LastError() + ret := C.git_branch_upstream_name(&nameBuf, repo.ptr, cName) + if ret < 0 { + return "", MakeGitError(ret) } C.git_buf_free(&nameBuf) From 374e2112dfc298fa5ecb0805624d75b3500cc345 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 27 Feb 2014 16:36:44 -0800 Subject: [PATCH 35/66] add push, refine remotes --- git_test.go | 15 ++++- push.go | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++ push_test.go | 56 ++++++++++++++++ remote.go | 99 ++++++++++++++-------------- wrapper.c | 12 ++++ 5 files changed, 310 insertions(+), 53 deletions(-) create mode 100644 push.go create mode 100644 push_test.go diff --git a/git_test.go b/git_test.go index 52aea1d..fff3c6c 100644 --- a/git_test.go +++ b/git_test.go @@ -1,8 +1,8 @@ package git import ( - "testing" "io/ioutil" + "testing" "time" ) @@ -14,7 +14,17 @@ func createTestRepo(t *testing.T) *Repository { checkFatal(t, err) tmpfile := "README" - err = ioutil.WriteFile(path + "/" + tmpfile, []byte("foo\n"), 0644) + err = ioutil.WriteFile(path+"/"+tmpfile, []byte("foo\n"), 0644) + checkFatal(t, err) + + return repo +} + +func createBareTestRepo(t *testing.T) *Repository { + // figure out where we can create the test repo + path, err := ioutil.TempDir("", "git2go") + checkFatal(t, err) + repo, err := InitRepository(path, true) checkFatal(t, err) return repo @@ -44,4 +54,3 @@ func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) { return commitId, treeId } - diff --git a/push.go b/push.go new file mode 100644 index 0000000..0694fe3 --- /dev/null +++ b/push.go @@ -0,0 +1,181 @@ +package git + +/* +#include +#include + +int _go_git_push_status_foreach(git_push *push, void *data); +int _go_git_push_set_callbacks(git_push *push, void *packbuilder_progress_data, void *transfer_progress_data); + +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type Push struct { + ptr *C.git_push + + packbuilderProgress *PackbuilderProgressCallback + transferProgress *PushTransferProgressCallback +} + +func newPushFromC(cpush *C.git_push) *Push { + p := &Push{ptr: cpush} + runtime.SetFinalizer(p, (*Push).Free) + return p +} + +func (p *Push) Free() { + runtime.SetFinalizer(p, nil) + C.git_push_free(p.ptr) +} + +func (remote *Remote) NewPush() (*Push, error) { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var cpush *C.git_push + ret := C.git_push_new(&cpush, remote.ptr) + if ret < 0 { + return nil, MakeGitError(ret) + } + return newPushFromC(cpush), nil +} + +func (p *Push) Finish() error { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_push_finish(p.ptr) + if ret < 0 { + return MakeGitError(ret) + } + return nil +} + +func (p *Push) UnpackOk() bool { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_push_unpack_ok(p.ptr) + if ret == 0 { + return false + } else { + return true + } + +} + +func (p *Push) UpdateTips(sig *Signature, msg string) error { + + var csig *C.git_signature = nil + if sig != nil { + csig = sig.toC() + defer C.free(unsafe.Pointer(csig)) + } + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_push_update_tips(p.ptr, csig, cmsg) + if ret < 0 { + return MakeGitError(ret) + } + return nil +} + +func (p *Push) AddRefspec(refspec string) error { + + crefspec := C.CString(refspec) + defer C.free(unsafe.Pointer(crefspec)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_push_add_refspec(p.ptr, crefspec) + if ret < 0 { + return MakeGitError(ret) + } + return nil +} + +type PushOptions struct { + Version uint + PbParallelism uint +} + +func (p *Push) SetOptions(opts PushOptions) error { + copts := C.git_push_options{version: C.uint(opts.Version), pb_parallelism: C.uint(opts.PbParallelism)} + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_push_set_options(p.ptr, &copts) + if ret < 0 { + return MakeGitError(ret) + } + return nil +} + +type StatusForeachFunc func(ref string, msg string) int + +//export statusForeach +func statusForeach(_ref *C.char, _msg *C.char, _data unsafe.Pointer) C.int { + ref := C.GoString(_ref) + msg := C.GoString(_msg) + + cb := (*StatusForeachFunc)(_data) + + return C.int((*cb)(ref, msg)) +} + +func (p *Push) StatusForeach(callback StatusForeachFunc) error { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C._go_git_push_status_foreach(p.ptr, unsafe.Pointer(&callback)) + if ret < 0 { + return MakeGitError(ret) + } + return nil + +} + +type PushCallbacks struct { + PackbuilderProgress *PackbuilderProgressCallback + TransferProgress *PushTransferProgressCallback +} + +type PackbuilderProgressCallback func(stage int, current uint, total uint) int +type PushTransferProgressCallback func(current uint, total uint, bytes uint) int + +//export packbuilderProgress +func packbuilderProgress(stage C.int, current C.uint, total C.uint, data unsafe.Pointer) C.int { + return C.int((*(*PackbuilderProgressCallback)(data))(int(stage), uint(current), uint(total))) +} + +//export pushTransferProgress +func pushTransferProgress(current C.uint, total C.uint, bytes C.size_t, data unsafe.Pointer) C.int { + return C.int((*(*PushTransferProgressCallback)(data))(uint(current), uint(total), uint(bytes))) +} + +func (p *Push) SetCallbacks(callbacks PushCallbacks) { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // save callbacks so they don't get GC'd + p.packbuilderProgress = callbacks.PackbuilderProgress + p.transferProgress = callbacks.TransferProgress + + C._go_git_push_set_callbacks(p.ptr, unsafe.Pointer(p.packbuilderProgress), unsafe.Pointer(p.transferProgress)) +} diff --git a/push_test.go b/push_test.go new file mode 100644 index 0000000..dfd4af7 --- /dev/null +++ b/push_test.go @@ -0,0 +1,56 @@ +package git + +import ( + "log" + "testing" + "time" +) + +func Test_Push_ToRemote(t *testing.T) { + repo := createBareTestRepo(t) + repo2 := createTestRepo(t) + + remote, err := repo2.CreateRemote("test_push", repo.Path()) + checkFatal(t, err) + + index, err := repo2.Index() + checkFatal(t, err) + + index.AddByPath("README") + + err = index.Write() + checkFatal(t, err) + + newTreeId, err := index.WriteTree() + checkFatal(t, err) + + tree, err := repo2.LookupTree(newTreeId) + checkFatal(t, err) + + sig := &Signature{Name: "Rand Om Hacker", Email: "random@hacker.com", When: time.Now()} + // this should cause master branch to be created if it does not already exist + _, err = repo2.CreateCommit("HEAD", sig, sig, "message", tree) + checkFatal(t, err) + + push, err := remote.NewPush() + checkFatal(t, err) + + err = push.AddRefspec("refs/heads/master") + checkFatal(t, err) + + err = push.Finish() + checkFatal(t, err) + + err = push.StatusForeach(func(ref string, msg string) int { + log.Printf("%s -> %s", ref, msg) + return 0 + }) + checkFatal(t, err) + + if !push.UnpackOk() { + t.Fatalf("unable to unpack") + } + + defer remote.Free() + defer repo.Free() +} diff --git a/remote.go b/remote.go index 38c1d47..ab2e174 100644 --- a/remote.go +++ b/remote.go @@ -40,27 +40,7 @@ type RemoteCallbacks struct { UpdateTipsCallback } -type Remote interface { - Save() error - Owner() Repository - Name() string - Url() string - PushUrl() string - - SetUrl(url string) error - SetPushUrl(url string) error - - AddFetch(refspec string) error - GetFetchRefspecs() ([]string, error) - SetFetchRefspecs(refspecs []string) error - AddPush(refspec string) error - GetPushRefspecs() ([]string, error) - SetPushRefspecs(refspecs []string) error - ClearRefspecs() - RefspecCount() uint -} - -type gitRemote struct { +type Remote struct { ptr *C.git_remote } @@ -161,13 +141,13 @@ func RemoteIsValidName(name string) bool { return false } -func freeRemote(o *gitRemote) { - C.git_remote_free(o.ptr) +func (r *Remote) Free() { + runtime.SetFinalizer(r, nil) + C.git_remote_free(r.ptr) } -func CreateRemote(repo *Repository, name string, url string) (Remote, error) { - remote := &gitRemote{} - runtime.SetFinalizer(remote, freeRemote) +func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) { + remote := &Remote{} cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -181,12 +161,12 @@ func CreateRemote(repo *Repository, name string, url string) (Remote, error) { if ret < 0 { return nil, MakeGitError(ret) } + runtime.SetFinalizer(remote, (*Remote).Free) return remote, nil } -func CreateRemoteWithFetchspec(repo *Repository, name string, url string, fetch string) (Remote, error) { - remote := &gitRemote{} - runtime.SetFinalizer(remote, freeRemote) +func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) { + remote := &Remote{} cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -202,12 +182,12 @@ func CreateRemoteWithFetchspec(repo *Repository, name string, url string, fetch if ret < 0 { return nil, MakeGitError(ret) } + runtime.SetFinalizer(remote, (*Remote).Free) return remote, nil } -func CreateRemoteInMemory(repo *Repository, fetch string, url string) (Remote, error) { - remote := &gitRemote{} - runtime.SetFinalizer(remote, freeRemote) +func (repo *Repository) CreateRemoteInMemory(fetch string, url string) (*Remote, error) { + remote := &Remote{} curl := C.CString(url) defer C.free(unsafe.Pointer(curl)) @@ -221,12 +201,12 @@ func CreateRemoteInMemory(repo *Repository, fetch string, url string) (Remote, e if ret < 0 { return nil, MakeGitError(ret) } + runtime.SetFinalizer(remote, (*Remote).Free) return remote, nil } -func LoadRemote(repo *Repository, name string) (Remote, error) { - remote := &gitRemote{} - runtime.SetFinalizer(remote, freeRemote) +func (repo *Repository) LoadRemote(name string) (*Remote, error) { + remote := &Remote{} cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) @@ -238,10 +218,11 @@ func LoadRemote(repo *Repository, name string) (Remote, error) { if ret < 0 { return nil, MakeGitError(ret) } + runtime.SetFinalizer(remote, (*Remote).Free) return remote, nil } -func (o *gitRemote) Save() error { +func (o *Remote) Save() error { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -253,23 +234,23 @@ func (o *gitRemote) Save() error { return nil } -func (o *gitRemote) Owner() Repository { +func (o *Remote) Owner() Repository { return Repository{C.git_remote_owner(o.ptr)} } -func (o *gitRemote) Name() string { +func (o *Remote) Name() string { return C.GoString(C.git_remote_name(o.ptr)) } -func (o *gitRemote) Url() string { +func (o *Remote) Url() string { return C.GoString(C.git_remote_url(o.ptr)) } -func (o *gitRemote) PushUrl() string { +func (o *Remote) PushUrl() string { return C.GoString(C.git_remote_pushurl(o.ptr)) } -func (o *gitRemote) SetUrl(url string) error { +func (o *Remote) SetUrl(url string) error { curl := C.CString(url) defer C.free(unsafe.Pointer(curl)) @@ -283,7 +264,7 @@ func (o *gitRemote) SetUrl(url string) error { return nil } -func (o *gitRemote) SetPushUrl(url string) error { +func (o *Remote) SetPushUrl(url string) error { curl := C.CString(url) defer C.free(unsafe.Pointer(curl)) @@ -297,7 +278,7 @@ func (o *gitRemote) SetPushUrl(url string) error { return nil } -func (o *gitRemote) AddFetch(refspec string) error { +func (o *Remote) AddFetch(refspec string) error { crefspec := C.CString(refspec) defer C.free(unsafe.Pointer(crefspec)) @@ -311,7 +292,7 @@ func (o *gitRemote) AddFetch(refspec string) error { return nil } -func (o *gitRemote) GetFetchRefspecs() ([]string, error) { +func (o *Remote) GetFetchRefspecs() ([]string, error) { crefspecs := C.git_strarray{} runtime.LockOSThread() @@ -330,7 +311,7 @@ func (o *gitRemote) GetFetchRefspecs() ([]string, error) { return refspecs, nil } -func (o *gitRemote) SetFetchRefspecs(refspecs []string) error { +func (o *Remote) SetFetchRefspecs(refspecs []string) error { crefspecs := C.git_strarray{} crefspecs.count = C.size_t(len(refspecs)) crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count)))) @@ -349,7 +330,7 @@ func (o *gitRemote) SetFetchRefspecs(refspecs []string) error { return nil } -func (o *gitRemote) AddPush(refspec string) error { +func (o *Remote) AddPush(refspec string) error { crefspec := C.CString(refspec) defer C.free(unsafe.Pointer(crefspec)) @@ -363,7 +344,7 @@ func (o *gitRemote) AddPush(refspec string) error { return nil } -func (o *gitRemote) GetPushRefspecs() ([]string, error) { +func (o *Remote) GetPushRefspecs() ([]string, error) { crefspecs := C.git_strarray{} runtime.LockOSThread() @@ -382,7 +363,7 @@ func (o *gitRemote) GetPushRefspecs() ([]string, error) { return refspecs, nil } -func (o *gitRemote) SetPushRefspecs(refspecs []string) error { +func (o *Remote) SetPushRefspecs(refspecs []string) error { crefspecs := C.git_strarray{} crefspecs.count = C.size_t(len(refspecs)) crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count)))) @@ -401,10 +382,28 @@ func (o *gitRemote) SetPushRefspecs(refspecs []string) error { return nil } -func (o *gitRemote) ClearRefspecs() { +func (o *Remote) ClearRefspecs() { C.git_remote_clear_refspecs(o.ptr) } -func (o *gitRemote) RefspecCount() uint { +func (o *Remote) RefspecCount() uint { return uint(C.git_remote_refspec_count(o.ptr)) } + +func (o *Remote) Fetch(sig *Signature, msg string) error { + + var csig *C.git_signature = nil + if sig != nil { + csig = sig.toC() + defer C.free(unsafe.Pointer(csig)) + } + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + ret := C.git_remote_fetch(o.ptr, csig, cmsg) + if ret < 0 { + return MakeGitError(ret) + } + return nil +} diff --git a/wrapper.c b/wrapper.c index 7519a96..9e193ca 100644 --- a/wrapper.c +++ b/wrapper.c @@ -51,4 +51,16 @@ char *_go_git_get_strarray_n(git_strarray *array, size_t n) { return array->strings[n]; } +typedef int (*status_foreach_cb)(const char *ref, const char *msg, void *data); + +int _go_git_push_status_foreach(git_push *push, void *data) +{ + return git_push_status_foreach(push, (status_foreach_cb)statusForeach, data); +} + +int _go_git_push_set_callbacks(git_push *push, void *packbuilder_progress_data, void *transfer_progress_data) +{ + return git_push_set_callbacks(push, packbuilderProgress, packbuilder_progress_data, pushTransferProgress, transfer_progress_data); +} + /* EOF */ From 639b66345c2f00f15deb366cf58b22f0dbedf879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 28 Feb 2014 14:11:21 +0100 Subject: [PATCH 36/66] Fix an old error function call that snuck in --- repository.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/repository.go b/repository.go index bf6aee5..6b7345d 100644 --- a/repository.go +++ b/repository.go @@ -353,7 +353,7 @@ func (v *Repository) EnsureLog(name string) error { defer runtime.UnlockOSThread() if ret := C.git_reference_ensure_log(v.ptr, cname); ret < 0 { - return LastError() + return MakeGitError(ret) } return nil @@ -370,7 +370,7 @@ func (v *Repository) HasLog(name string) (bool, error) { ret := C.git_reference_has_log(v.ptr, cname) if ret < 0 { - return false, LastError() + return false, MakeGitError(ret) } return ret == 1, nil @@ -386,7 +386,7 @@ func (v *Repository) DwimReference(name string) (*Reference, error) { var ptr *C.git_reference if ret := C.git_reference_dwim(&ptr, v.ptr, cname); ret < 0 { - return nil, LastError() + return nil, MakeGitError(ret) } return newReferenceFromC(ptr), nil From f5f8e13744f40300864956fdceb3849c724b9bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 28 Feb 2014 14:26:03 +0100 Subject: [PATCH 37/66] Add a travis script Add a build script and ask Travis to run it. It downloads the tip of libgit2's dev branch and tests against that. --- .travis.yml | 12 ++++++++++++ script/build-libgit2.sh | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .travis.yml create mode 100755 script/build-libgit2.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..86f8265 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: go + +go: + - 1.0 + - 1.1 + - tip + +env: + - PKG_CONFIG_PATH=libgit2/install/lib/pkgconfig LD_LIBRARY_PATH=libgit2/install/lib + +install: + - script/build-libgit2.sh diff --git a/script/build-libgit2.sh b/script/build-libgit2.sh new file mode 100755 index 0000000..aa43df5 --- /dev/null +++ b/script/build-libgit2.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -ex + +git clone --depth 1 --single-branch git://github.com/libgit2/libgit2 libgit2 + +cd libgit2 +cmake -DTHREADSAFE=ON \ + -DBUILD_CLAR=OFF \ + -DCMAKE_INSTALL_PREFIX=$PWD/install \ + . + +make install + +# Let the Go build system know where to find libgit2 +export LD_LIBRARY_PATH="$TMPDIR/libgit2/install/lib" +export PKG_CONFIG_PATH="$TMPDIR/libgit2/install/lib/pkgconfig" From 2c56324ca5e2513b386a7b1f94b3b62881183769 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 28 Feb 2014 10:46:57 -0800 Subject: [PATCH 38/66] fix bad git_buf handling --- branch.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/branch.go b/branch.go index 68e1b93..9f8c22b 100644 --- a/branch.go +++ b/branch.go @@ -142,9 +142,9 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { if ret < 0 { return "", MakeGitError(ret) } - C.git_buf_free(&nameBuf) + defer C.git_buf_free(&nameBuf) - return C.GoStringN(nameBuf.ptr, C.int(nameBuf.size)), nil + return C.GoString(nameBuf.ptr), nil } func (b *Branch) SetUpstream(upstreamName string) error { @@ -185,7 +185,7 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) if ret < 0 { return "", MakeGitError(ret) } - C.git_buf_free(&nameBuf) + defer C.git_buf_free(&nameBuf) - return C.GoStringN(nameBuf.ptr, C.int(nameBuf.size)), nil + return C.GoString(nameBuf.ptr), nil } From b404c8b86250b5abdbb02714cfdc08254c67df49 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 28 Feb 2014 10:47:56 -0800 Subject: [PATCH 39/66] Remove unused consts --- branch.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/branch.go b/branch.go index 9f8c22b..eb22fde 100644 --- a/branch.go +++ b/branch.go @@ -19,13 +19,6 @@ const ( BranchRemote = C.GIT_BRANCH_REMOTE ) -const ( - RefsDir = "refs/" - RefsHeadsDir = RefsDir + "heads/" - RefsTagsDir = RefsDir + "tags/" - RefsRemotesDir = RefsDir + "remotes/" -) - type Branch struct { Reference } From d6332f9526b48e5145db4ee32d8976cdd0f5972c Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 28 Feb 2014 10:54:16 -0800 Subject: [PATCH 40/66] fix msg handling to treat empty str as nil --- branch.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/branch.go b/branch.go index eb22fde..777231c 100644 --- a/branch.go +++ b/branch.go @@ -23,7 +23,7 @@ type Branch struct { Reference } -func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, message string) (*Reference, error) { +func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, msg string) (*Reference, error) { ref := new(Reference) cBranchName := C.CString(branchName) @@ -32,13 +32,18 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo cSignature := signature.toC() defer C.git_signature_free(cSignature) - cMessage := C.CString(message) - defer C.free(unsafe.Pointer(cMessage)) + 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(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce, cSignature, cMessage) + ret := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.ptr, cForce, cSignature, cmsg) if ret < 0 { return nil, MakeGitError(ret) } @@ -56,7 +61,7 @@ func (b *Branch) Delete() error { return nil } -func (b *Branch) Move(newBranchName string, force bool, signature *Signature, message string) (*Branch, error) { +func (b *Branch) Move(newBranchName string, force bool, signature *Signature, msg string) (*Branch, error) { newBranch := new(Branch) cNewBranchName := C.CString(newBranchName) cForce := cbool(force) @@ -64,13 +69,18 @@ func (b *Branch) Move(newBranchName string, force bool, signature *Signature, me cSignature := signature.toC() defer C.git_signature_free(cSignature) - cMessage := C.CString(message) - defer C.free(unsafe.Pointer(cMessage)) + 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(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cMessage) + ret := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cmsg) if ret < 0 { return nil, MakeGitError(ret) } From 9fb7a746e0103ceff2fd8eb9845e782711a87535 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 28 Feb 2014 10:58:53 -0800 Subject: [PATCH 41/66] fix handling of msg to treat empty str as nil --- push.go | 9 +++++++-- remote.go | 10 +++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/push.go b/push.go index 0694fe3..d1742e3 100644 --- a/push.go +++ b/push.go @@ -79,8 +79,13 @@ func (p *Push) UpdateTips(sig *Signature, msg string) error { defer C.free(unsafe.Pointer(csig)) } - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/remote.go b/remote.go index ab2e174..900a314 100644 --- a/remote.go +++ b/remote.go @@ -398,9 +398,13 @@ func (o *Remote) Fetch(sig *Signature, msg string) error { defer C.free(unsafe.Pointer(csig)) } - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) - + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } ret := C.git_remote_fetch(o.ptr, csig, cmsg) if ret < 0 { return MakeGitError(ret) From 127643eb543cbeac88466956a6394505abc1176e Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 28 Feb 2014 11:08:15 -0800 Subject: [PATCH 42/66] move return outside of switch for go 1.0 / travis --- branch.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/branch.go b/branch.go index 777231c..aee23e4 100644 --- a/branch.go +++ b/branch.go @@ -98,9 +98,8 @@ func (b *Branch) IsHead() (bool, error) { return true, nil case 0: return false, nil - default: - return false, MakeGitError(ret) } + return false, MakeGitError(ret) } From 5e163fa2e8281642dbb9dbf6229a9a20387130d2 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 7 Mar 2014 16:43:20 -0800 Subject: [PATCH 43/66] add blob chunk creation, creation of tree builders for specific trees, minor API cleanup --- blob.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++++-- repository.go | 24 +++++++++++++++---- tree.go | 38 +++++++++++++++++++++--------- walk.go | 21 ++++++++++++----- wrapper.c | 13 +++++++++++ 5 files changed, 137 insertions(+), 24 deletions(-) diff --git a/blob.go b/blob.go index b638c4f..ced2cb1 100644 --- a/blob.go +++ b/blob.go @@ -3,9 +3,18 @@ package git /* #include #include +#include + +extern int _go_git_blob_create_fromchunks(git_oid *id, + git_repository *repo, + const char *hintpath, + void *payload); + */ import "C" import ( + "io" + "runtime" "unsafe" ) @@ -13,13 +22,65 @@ type Blob struct { gitObject } -func (v Blob) Size() int64 { +func (v *Blob) Size() int64 { return int64(C.git_blob_rawsize(v.ptr)) } -func (v Blob) Contents() []byte { +func (v *Blob) Contents() []byte { size := C.int(C.git_blob_rawsize(v.ptr)) buffer := unsafe.Pointer(C.git_blob_rawcontent(v.ptr)) return C.GoBytes(buffer, size) } +func (repo *Repository) CreateBlobFromBuffer(data []byte) (*Oid, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + oid := C.git_oid{} + ecode := C.git_blob_create_frombuffer(&oid, repo.ptr, unsafe.Pointer(&data[0]), C.size_t(len(data))) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + return newOidFromC(&oid), nil +} + +type BlobChunkCallback func(maxLen int) ([]byte, error) + +type BlobCallbackData struct { + Callback BlobChunkCallback + Error error +} + +//export blobChunkCb +func blobChunkCb(buffer *C.char, maxLen C.size_t, payload unsafe.Pointer) int { + data := (*BlobCallbackData)(payload) + goBuf, err := data.Callback(int(maxLen)) + if err == io.EOF { + return 1 + } else if err != nil { + data.Error = err + return -1 + } + C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf), C.size_t(len(goBuf))) + return 0 +} + +func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var chintPath *C.char = nil + if len(hintPath) > 0 { + C.CString(hintPath) + defer C.free(unsafe.Pointer(chintPath)) + } + oid := C.git_oid{} + payload := &BlobCallbackData{Callback: callback} + ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, unsafe.Pointer(payload)) + if payload.Error != nil { + return nil, payload.Error + } + if ecode < 0 { + return nil, MakeGitError(ecode) + } + return newOidFromC(&oid), nil +} diff --git a/repository.go b/repository.go index 6b7345d..d6eadc8 100644 --- a/repository.go +++ b/repository.go @@ -206,19 +206,18 @@ func (v *Repository) CreateSymbolicReference(name, target string, force bool, si } func (v *Repository) Walk() (*RevWalk, error) { - walk := new(RevWalk) + + var walkPtr *C.git_revwalk runtime.LockOSThread() defer runtime.UnlockOSThread() - ecode := C.git_revwalk_new(&walk.ptr, v.ptr) + ecode := C.git_revwalk_new(&walkPtr, v.ptr) if ecode < 0 { return nil, MakeGitError(ecode) } - walk.repo = v - runtime.SetFinalizer(walk, freeRevWalk) - return walk, nil + return revWalkFromC(v, walkPtr), nil } func (v *Repository) CreateCommit( @@ -326,6 +325,21 @@ func (v *Repository) TreeBuilder() (*TreeBuilder, error) { return bld, nil } +func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) { + bld := new(TreeBuilder) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if ret := C.git_treebuilder_create(&bld.ptr, tree.ptr); ret < 0 { + return nil, MakeGitError(ret) + } + runtime.SetFinalizer(bld, (*TreeBuilder).Free) + + bld.repo = v + return bld, nil +} + func (v *Repository) RevparseSingle(spec string) (Object, error) { cspec := C.CString(spec) defer C.free(unsafe.Pointer(cspec)) diff --git a/tree.go b/tree.go index b3340d6..7070ac7 100644 --- a/tree.go +++ b/tree.go @@ -14,13 +14,14 @@ import ( ) type Filemode int + const ( - FilemodeNew Filemode = C.GIT_FILEMODE_NEW - FilemodeTree = C.GIT_FILEMODE_TREE - FilemodeBlob = C.GIT_FILEMODE_BLOB - FilemodeBlobExecutable = C.GIT_FILEMODE_BLOB_EXECUTABLE - FilemodeLink = C.GIT_FILEMODE_LINK - FilemodeCommit = C.GIT_FILEMODE_COMMIT + FilemodeNew Filemode = C.GIT_FILEMODE_NEW + FilemodeTree = C.GIT_FILEMODE_TREE + FilemodeBlob = C.GIT_FILEMODE_BLOB + FilemodeBlobExecutable = C.GIT_FILEMODE_BLOB_EXECUTABLE + FilemodeLink = C.GIT_FILEMODE_LINK + FilemodeCommit = C.GIT_FILEMODE_COMMIT ) type Tree struct { @@ -28,9 +29,9 @@ type Tree struct { } type TreeEntry struct { - Name string - Id *Oid - Type ObjectType + Name string + Id *Oid + Type ObjectType Filemode int } @@ -116,7 +117,7 @@ func (t Tree) Walk(callback TreeWalkCallback) error { } type TreeBuilder struct { - ptr *C.git_treebuilder + ptr *C.git_treebuilder repo *Repository } @@ -125,7 +126,7 @@ func (v *TreeBuilder) Free() { C.git_treebuilder_free(v.ptr) } -func (v *TreeBuilder) Insert(filename string, id *Oid, filemode int) (error) { +func (v *TreeBuilder) Insert(filename string, id *Oid, filemode int) error { cfilename := C.CString(filename) defer C.free(unsafe.Pointer(cfilename)) @@ -140,6 +141,21 @@ func (v *TreeBuilder) Insert(filename string, id *Oid, filemode int) (error) { return nil } +func (v *TreeBuilder) Remove(filename string) error { + cfilename := C.CString(filename) + defer C.free(unsafe.Pointer(cfilename)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + err := C.git_treebuilder_remove(v.ptr, cfilename) + if err < 0 { + return MakeGitError(err) + } + + return nil +} + func (v *TreeBuilder) Write() (*Oid, error) { oid := new(Oid) diff --git a/walk.go b/walk.go index cdc1a20..71df7bb 100644 --- a/walk.go +++ b/walk.go @@ -14,11 +14,12 @@ import ( // RevWalk type SortType uint + const ( - SortNone SortType = C.GIT_SORT_NONE - SortTopological = C.GIT_SORT_TOPOLOGICAL - SortTime = C.GIT_SORT_TIME - SortReverse = C.GIT_SORT_REVERSE + SortNone SortType = C.GIT_SORT_NONE + SortTopological = C.GIT_SORT_TOPOLOGICAL + SortTime = C.GIT_SORT_TIME + SortReverse = C.GIT_SORT_REVERSE ) type RevWalk struct { @@ -26,6 +27,12 @@ type RevWalk struct { repo *Repository } +func revWalkFromC(repo *Repository, c *C.git_revwalk) *RevWalk { + v := &RevWalk{ptr: c, repo: repo} + runtime.SetFinalizer(v, (*RevWalk).Free) + return v +} + func (v *RevWalk) Reset() { C.git_revwalk_reset(v.ptr) } @@ -92,6 +99,8 @@ func (v *RevWalk) Sorting(sm SortType) { C.git_revwalk_sorting(v.ptr, C.uint(sm)) } -func freeRevWalk(walk *RevWalk) { - C.git_revwalk_free(walk.ptr) +func (v *RevWalk) Free() { + + runtime.SetFinalizer(v, nil) + C.git_revwalk_free(v.ptr) } diff --git a/wrapper.c b/wrapper.c index 2af3974..4ce4c5c 100644 --- a/wrapper.c +++ b/wrapper.c @@ -24,4 +24,17 @@ int _go_git_odb_foreach(git_odb *db, void *payload) { return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload); } + +int _go_blob_chunk_cb(char *buffer, size_t maxLen, void *payload) +{ + return blobChunkCb(buffer, maxLen, payload); +} + +int _go_git_blob_create_fromchunks(git_oid *id, + git_repository *repo, + const char *hintpath, + void *payload) +{ + return git_blob_create_fromchunks(id, repo, hintpath, _go_blob_chunk_cb, payload); +} /* EOF */ From 42fce02197789a1577ff7130f7f46ce47e584aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 11 Mar 2014 03:09:48 +0100 Subject: [PATCH 44/66] Adjust to checkout_opts -> checkout_options --- checkout.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/checkout.go b/checkout.go index d3cd47b..5becd0e 100644 --- a/checkout.go +++ b/checkout.go @@ -2,8 +2,8 @@ package git /* #include -git_checkout_opts git_checkout_opts_init() { - git_checkout_opts ret = GIT_CHECKOUT_OPTS_INIT; +git_checkout_options git_checkout_opts_init() { + git_checkout_options ret = GIT_CHECKOUT_OPTIONS_INIT; return ret; } */ @@ -43,7 +43,7 @@ type CheckoutOpts struct { } // Convert the CheckoutOpts struct to the corresponding C-struct -func populateCheckoutOpts(ptr *C.git_checkout_opts, opts *CheckoutOpts) { +func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) { *ptr = C.git_checkout_opts_init() if opts == nil { return @@ -57,7 +57,7 @@ func populateCheckoutOpts(ptr *C.git_checkout_opts, opts *CheckoutOpts) { // Updates files in the index and the working tree to match the content of // the commit pointed at by HEAD. func (v *Repository) Checkout(opts *CheckoutOpts) error { - var copts C.git_checkout_opts + var copts C.git_checkout_options populateCheckoutOpts(&copts, opts) runtime.LockOSThread() @@ -73,7 +73,7 @@ func (v *Repository) Checkout(opts *CheckoutOpts) error { // Updates files in the working tree to match the content of the index. func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error { - var copts C.git_checkout_opts + var copts C.git_checkout_options populateCheckoutOpts(&copts, opts) runtime.LockOSThread() From b5b0f3f50e151ef67f8cd7b10044c81920093a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 11 Mar 2014 03:14:36 +0100 Subject: [PATCH 45/66] Remove custom checkout opts init function --- checkout.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/checkout.go b/checkout.go index 5becd0e..0f112a7 100644 --- a/checkout.go +++ b/checkout.go @@ -2,10 +2,6 @@ package git /* #include -git_checkout_options git_checkout_opts_init() { - git_checkout_options ret = GIT_CHECKOUT_OPTIONS_INIT; - return ret; -} */ import "C" import ( @@ -44,7 +40,7 @@ type CheckoutOpts struct { // Convert the CheckoutOpts struct to the corresponding C-struct func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) { - *ptr = C.git_checkout_opts_init() + C.git_checkout_init_opts(ptr, 1) if opts == nil { return } From b09c6d8bbe874d6a08e0c91ad3f11bceb74414b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 11 Mar 2014 03:27:35 +0100 Subject: [PATCH 46/66] Move checkout functions options more in line with the library Afjust Checkout -> CheckoutHead and pass nil if the options structure is nil so as not to overide the library's decisions. --- checkout.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/checkout.go b/checkout.go index 0f112a7..5753b09 100644 --- a/checkout.go +++ b/checkout.go @@ -38,28 +38,34 @@ type CheckoutOpts struct { FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY } -// Convert the CheckoutOpts struct to the corresponding C-struct -func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) { - C.git_checkout_init_opts(ptr, 1) +// Convert the CheckoutOpts struct to the corresponding +// C-struct. Returns a pointer to ptr, or nil if opts is nil, in order +// to help with what to pass. +func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) *C.git_checkout_options { if opts == nil { - return + return nil } + + C.git_checkout_init_opts(ptr, 1) ptr.checkout_strategy = C.uint(opts.Strategy) ptr.disable_filters = cbool(opts.DisableFilters) ptr.dir_mode = C.uint(opts.DirMode.Perm()) ptr.file_mode = C.uint(opts.FileMode.Perm()) + + return ptr } // Updates files in the index and the working tree to match the content of -// the commit pointed at by HEAD. -func (v *Repository) Checkout(opts *CheckoutOpts) error { +// the commit pointed at by HEAD. opts may be nil. +func (v *Repository) CheckoutHead(opts *CheckoutOpts) error { var copts C.git_checkout_options - populateCheckoutOpts(&copts, opts) + + ptr := populateCheckoutOpts(&copts, opts) runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_checkout_head(v.ptr, &copts) + ret := C.git_checkout_head(v.ptr, ptr) if ret < 0 { return MakeGitError(ret) } @@ -67,15 +73,16 @@ func (v *Repository) Checkout(opts *CheckoutOpts) error { return nil } -// Updates files in the working tree to match the content of the index. +// Updates files in the working tree to match the content of the given +// index. opts may be nil. func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error { var copts C.git_checkout_options - populateCheckoutOpts(&copts, opts) + ptr := populateCheckoutOpts(&copts, opts) runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_checkout_index(v.ptr, index.ptr, &copts) + ret := C.git_checkout_index(v.ptr, index.ptr, ptr) if ret < 0 { return MakeGitError(ret) } From 263884a908873803cb8a37f80ba89e7b98001f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 11 Mar 2014 03:30:56 +0100 Subject: [PATCH 47/66] CheckoutIndex: allow for index to be nil Allow for the index to be nil and pass that to the library to use the repository's index. --- checkout.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/checkout.go b/checkout.go index 5753b09..5b72b9a 100644 --- a/checkout.go +++ b/checkout.go @@ -74,15 +74,21 @@ func (v *Repository) CheckoutHead(opts *CheckoutOpts) error { } // Updates files in the working tree to match the content of the given -// index. opts may be nil. +// index. If index is nil, the repository's index will be used. opts +// may be nil. func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error { var copts C.git_checkout_options ptr := populateCheckoutOpts(&copts, opts) + var iptr *C.git_index = nil + if index != nil { + iptr = index.ptr + } + runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_checkout_index(v.ptr, index.ptr, ptr) + ret := C.git_checkout_index(v.ptr, iptr, ptr) if ret < 0 { return MakeGitError(ret) } From d560b9e9bd7162334f7122dadd02cd0a075e22ab Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 13:19:12 -0700 Subject: [PATCH 48/66] cleanup clone code --- clone.go | 9 ++---- transport.go => credentials.go | 33 +++++++++------------ push.go | 3 -- remote.go | 52 +++++++++++++--------------------- wrapper.c | 5 ---- 5 files changed, 37 insertions(+), 65 deletions(-) rename transport.go => credentials.go (75%) diff --git a/clone.go b/clone.go index 630c343..51dbd65 100644 --- a/clone.go +++ b/clone.go @@ -4,11 +4,6 @@ package git #include #include -static git_clone_options git_clone_options_init() { - git_clone_options ret = GIT_CLONE_OPTIONS_INIT; - return ret; -} - */ import "C" import ( @@ -60,7 +55,9 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) } func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { - *ptr = C.git_clone_options_init() + ptr = &C.git_clone_options{} + C.git_clone_init_options(ptr, 1) + if opts == nil { return } diff --git a/transport.go b/credentials.go similarity index 75% rename from transport.go rename to credentials.go index e97a70c..c5ed055 100644 --- a/transport.go +++ b/credentials.go @@ -8,39 +8,35 @@ import "C" import "unsafe" type CredType uint + const ( CredTypeUserpassPlaintext CredType = C.GIT_CREDTYPE_USERPASS_PLAINTEXT - CredTypeSshKey = C.GIT_CREDTYPE_SSH_KEY - CredTypeSshCustom = C.GIT_CREDTYPE_SSH_CUSTOM - CredTypeDefault = C.GIT_CREDTYPE_DEFAULT + CredTypeSshKey = C.GIT_CREDTYPE_SSH_KEY + CredTypeSshCustom = C.GIT_CREDTYPE_SSH_CUSTOM + CredTypeDefault = C.GIT_CREDTYPE_DEFAULT ) -type Cred interface { - HasUsername() bool - Type() CredType -} - -type gitCred struct { +type Cred struct { ptr *C.git_cred } -func (o gitCred) HasUsername() bool { +func (o *Cred) HasUsername() bool { if C.git_cred_has_username(o.ptr) == 1 { return true } return false } -func (o gitCred) Type() CredType { - return (CredType)(o.ptr.credtype); +func (o *Cred) Type() CredType { + return (CredType)(o.ptr.credtype) } -func credFromC(ptr *C.git_cred) Cred { - return gitCred{ptr} +func credFromC(ptr *C.git_cred) *Cred { + return &Cred{ptr} } func NewCredUserpassPlaintext(username string, password string) (int, Cred) { - cred := gitCred{} + cred := Cred{} cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) cpassword := C.CString(password) @@ -50,7 +46,7 @@ func NewCredUserpassPlaintext(username string, password string) (int, Cred) { } func NewCredSshKey(username string, publickey string, privatekey string, passphrase string) (int, Cred) { - cred := gitCred{} + cred := Cred{} cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) cpublickey := C.CString(publickey) @@ -64,7 +60,7 @@ func NewCredSshKey(username string, publickey string, privatekey string, passphr } func NewCredSshKeyFromAgent(username string) (int, Cred) { - cred := gitCred{} + cred := Cred{} cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername) @@ -72,8 +68,7 @@ func NewCredSshKeyFromAgent(username string) (int, Cred) { } func NewCredDefault() (int, Cred) { - cred := gitCred{} + cred := Cred{} ret := C.git_cred_default_new(&cred.ptr) return int(ret), cred } - diff --git a/push.go b/push.go index d1742e3..8b205c7 100644 --- a/push.go +++ b/push.go @@ -59,9 +59,6 @@ func (p *Push) Finish() error { func (p *Push) UnpackOk() bool { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - ret := C.git_push_unpack_ok(p.ptr) if ret == 0 { return false diff --git a/remote.go b/remote.go index 900a314..3621b5f 100644 --- a/remote.go +++ b/remote.go @@ -5,7 +5,6 @@ package git #include extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); -extern git_remote_callbacks _go_git_remote_callbacks_init(); extern void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n); extern char *_go_git_get_strarray_n(git_strarray *array, size_t n); @@ -15,7 +14,22 @@ import "unsafe" import "runtime" type TransferProgress struct { - ptr *C.git_transfer_progress + TotalObjects uint + IndexedObjects uint + ReceivedObjects uint + LocalObjects uint + TotalDeltas uint + ReceivedBytes uint +} + +func newTransferProgressFromC(c *C.git_transfer_progress) TransferProgress { + return TransferProgress{ + TotalObjects: uint(c.total_objects), + IndexedObjects: uint(c.indexed_objects), + ReceivedObjects: uint(c.received_objects), + LocalObjects: uint(c.local_objects), + TotalDeltas: uint(c.total_deltas), + ReceivedBytes: uint(c.received_bytes)} } type RemoteCompletion uint @@ -28,7 +42,7 @@ const ( type ProgressCallback func(str string) int type CompletionCallback func(RemoteCompletion) int -type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (int, Cred) +type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (int, *Cred) type TransferProgressCallback func(stats TransferProgress) int type UpdateTipsCallback func(refname string, a *Oid, b *Oid) int @@ -45,7 +59,7 @@ type Remote struct { } func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { - *ptr = C._go_git_remote_callbacks_init() + C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION) if callbacks == nil { return } @@ -81,9 +95,7 @@ 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)) - if gcred, ok := cred.(gitCred); ok { - *_cred = gcred.ptr - } + *_cred = cred.ptr return ret } @@ -93,7 +105,7 @@ func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointe if callbacks.TransferProgressCallback == nil { return 0 } - return callbacks.TransferProgressCallback(TransferProgress{stats}) + return callbacks.TransferProgressCallback(newTransferProgressFromC(stats)) } //export updateTipsCallback @@ -108,30 +120,6 @@ func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data uns return callbacks.UpdateTipsCallback(refname, a, b) } -func (o TransferProgress) TotalObjects() uint { - return uint(o.ptr.total_objects) -} - -func (o TransferProgress) IndexedObjects() uint { - return uint(o.ptr.indexed_objects) -} - -func (o TransferProgress) ReceivedObjects() uint { - return uint(o.ptr.received_objects) -} - -func (o TransferProgress) LocalObjects() uint { - return uint(o.ptr.local_objects) -} - -func (o TransferProgress) TotalDeltas() uint { - return uint(o.ptr.total_deltas) -} - -func (o TransferProgress) ReceivedBytes() uint { - return uint(o.ptr.received_bytes) -} - func RemoteIsValidName(name string) bool { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) diff --git a/wrapper.c b/wrapper.c index 8e337df..bc69cd5 100644 --- a/wrapper.c +++ b/wrapper.c @@ -38,11 +38,6 @@ void _go_git_setup_callbacks(git_remote_callbacks *callbacks) { callbacks->update_tips = (update_tips_cb)updateTipsCallback; } -git_remote_callbacks _go_git_remote_callbacks_init() { - git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; - return ret; -} - void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n) { array->strings[n] = str; } From 2f531968667f96fd573590f2609589cbdb14a480 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 13:22:00 -0700 Subject: [PATCH 49/66] clean up clone code --- clone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clone.go b/clone.go index 51dbd65..c2abbe5 100644 --- a/clone.go +++ b/clone.go @@ -56,7 +56,7 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { ptr = &C.git_clone_options{} - C.git_clone_init_options(ptr, 1) + C.git_clone_init_options(ptr, C.GIT_CLONE_OPTIONS_VERSION) if opts == nil { return From 0a172478dcba23f73f7f1991c6b39c62ee23f172 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 13:45:27 -0700 Subject: [PATCH 50/66] fix return for old go versions / travis --- push.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/push.go b/push.go index 8b205c7..5fb7f07 100644 --- a/push.go +++ b/push.go @@ -62,9 +62,8 @@ func (p *Push) UnpackOk() bool { ret := C.git_push_unpack_ok(p.ptr) if ret == 0 { return false - } else { - return true } + return true } From 51aa76d6f7170bba60ab2252b74a3cab0276996f Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 16:25:22 -0700 Subject: [PATCH 51/66] remove strarray wrappers --- remote.go | 48 +++++++++++++++++++++++++++++------------------- wrapper.c | 8 -------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/remote.go b/remote.go index 3621b5f..da688e7 100644 --- a/remote.go +++ b/remote.go @@ -5,8 +5,6 @@ package git #include extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); -extern void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n); -extern char *_go_git_get_strarray_n(git_strarray *array, size_t n); */ import "C" @@ -280,6 +278,31 @@ func (o *Remote) AddFetch(refspec string) error { return nil } +func sptr(p uintptr) *C.char { + return *(**C.char)(unsafe.Pointer(p)) +} + +func makeStringsFromCStrings(x **C.char, l int) []string { + s := make([]string, l) + i := 0 + for p := uintptr(unsafe.Pointer(x)); i < l; p += unsafe.Sizeof(uintptr(0)) { + s[i] = C.GoString(sptr(p)) + i++ + } + return s +} + +func makeCStringsFromStrings(s []string) **C.char { + l := len(s) + x := (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(l)))) + i := 0 + for p := uintptr(unsafe.Pointer(x)); i < l; p += unsafe.Sizeof(uintptr(0)) { + *(**C.char)(unsafe.Pointer(p)) = C.CString(s[i]) + i++ + } + return x +} + func (o *Remote) GetFetchRefspecs() ([]string, error) { crefspecs := C.git_strarray{} @@ -291,21 +314,15 @@ func (o *Remote) GetFetchRefspecs() ([]string, error) { return nil, MakeGitError(ret) } defer C.git_strarray_free(&crefspecs) - refspecs := make([]string, crefspecs.count) - for i := 0; i < int(crefspecs.count); i++ { - refspecs[i] = C.GoString(C._go_git_get_strarray_n(&crefspecs, C.size_t(i))) - } + refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count)) return refspecs, nil } func (o *Remote) SetFetchRefspecs(refspecs []string) error { crefspecs := C.git_strarray{} crefspecs.count = C.size_t(len(refspecs)) - crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count)))) - for i, refspec := range refspecs { - C._go_git_set_strarray_n(&crefspecs, C.CString(refspec), C.size_t(i)) - } + crefspecs.strings = makeCStringsFromStrings(refspecs) defer C.git_strarray_free(&crefspecs) runtime.LockOSThread() @@ -343,21 +360,14 @@ func (o *Remote) GetPushRefspecs() ([]string, error) { return nil, MakeGitError(ret) } defer C.git_strarray_free(&crefspecs) - refspecs := make([]string, crefspecs.count) - - for i := 0; i < int(crefspecs.count); i++ { - refspecs[i] = C.GoString(C._go_git_get_strarray_n(&crefspecs, C.size_t(i))) - } + refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count)) return refspecs, nil } func (o *Remote) SetPushRefspecs(refspecs []string) error { crefspecs := C.git_strarray{} crefspecs.count = C.size_t(len(refspecs)) - crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count)))) - for i, refspec := range refspecs { - C._go_git_set_strarray_n(&crefspecs, C.CString(refspec), C.size_t(i)) - } + crefspecs.strings = makeCStringsFromStrings(refspecs) defer C.git_strarray_free(&crefspecs) runtime.LockOSThread() diff --git a/wrapper.c b/wrapper.c index bc69cd5..0fa6c48 100644 --- a/wrapper.c +++ b/wrapper.c @@ -38,14 +38,6 @@ void _go_git_setup_callbacks(git_remote_callbacks *callbacks) { callbacks->update_tips = (update_tips_cb)updateTipsCallback; } -void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n) { - array->strings[n] = str; -} - -char *_go_git_get_strarray_n(git_strarray *array, size_t n) { - return array->strings[n]; -} - typedef int (*status_foreach_cb)(const char *ref, const char *msg, void *data); int _go_git_push_status_foreach(git_push *push, void *data) From 663c2a69c9ad2f88a6c2a06d7fea82a60392f2fe Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Sun, 16 Mar 2014 22:09:12 -0700 Subject: [PATCH 52/66] fix chunk create logic --- blob.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blob.go b/blob.go index ced2cb1..4cee876 100644 --- a/blob.go +++ b/blob.go @@ -55,13 +55,13 @@ func blobChunkCb(buffer *C.char, maxLen C.size_t, payload unsafe.Pointer) int { data := (*BlobCallbackData)(payload) goBuf, err := data.Callback(int(maxLen)) if err == io.EOF { - return 1 + return 0 } else if err != nil { data.Error = err return -1 } - C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf), C.size_t(len(goBuf))) - return 0 + C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf[0]), C.size_t(len(goBuf))) + return len(goBuf) } func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) { From d1e7ee53d53d050d5d5be475f98f51e28a88840c Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 18 Mar 2014 18:23:33 -0700 Subject: [PATCH 53/66] fix clone options init --- clone.go | 1 - 1 file changed, 1 deletion(-) diff --git a/clone.go b/clone.go index c2abbe5..1bc3261 100644 --- a/clone.go +++ b/clone.go @@ -55,7 +55,6 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) } func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { - ptr = &C.git_clone_options{} C.git_clone_init_options(ptr, C.GIT_CLONE_OPTIONS_VERSION) if opts == nil { From 3d7f737481e02fd8fb787916ade475b3dd6dc78d Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 18 Mar 2014 18:24:31 -0700 Subject: [PATCH 54/66] add simple clone test --- clone_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 clone_test.go diff --git a/clone_test.go b/clone_test.go new file mode 100644 index 0000000..27e824b --- /dev/null +++ b/clone_test.go @@ -0,0 +1,19 @@ +package git + +import ( + "io/ioutil" + "testing" +) + +func Test_Clone(t *testing.T) { + + repo := createTestRepo(t) + seedTestRepo(t, repo) + + path, err := ioutil.TempDir("", "git2go") + checkFatal(t, err) + + _, err = Clone(repo.Path(), path, &CloneOptions{Bare: true}) + + checkFatal(t, err) +} From f1f0fa7335f6ec3285eae32f84d143edffd73ef5 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 18 Mar 2014 19:38:02 -0700 Subject: [PATCH 55/66] fix naming on test --- clone_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clone_test.go b/clone_test.go index 27e824b..6145228 100644 --- a/clone_test.go +++ b/clone_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func Test_Clone(t *testing.T) { +func TestClone(t *testing.T) { repo := createTestRepo(t) seedTestRepo(t, repo) From b6703d47671b3a736e8b93ff0447da45e688865c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 18 Mar 2014 04:54:40 +0100 Subject: [PATCH 56/66] Oid: make the type directly [20]byte There is no need for a struct with a single field. An Oid is 20 bytes which hold the binary representation of the hash, so let's use that directly. Go lets us have methods on this new type just the same. --- git.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/git.go b/git.go index db9522b..8f543b5 100644 --- a/git.go +++ b/git.go @@ -29,9 +29,7 @@ func init() { } // Oid -type Oid struct { - bytes [20]byte -} +type Oid [20]byte func newOidFromC(coid *C.git_oid) *Oid { if coid == nil { @@ -39,18 +37,18 @@ func newOidFromC(coid *C.git_oid) *Oid { } oid := new(Oid) - copy(oid.bytes[0:20], C.GoBytes(unsafe.Pointer(coid), 20)) + copy(oid[0:20], C.GoBytes(unsafe.Pointer(coid), 20)) return oid } func NewOid(b []byte) *Oid { oid := new(Oid) - copy(oid.bytes[0:20], b[0:20]) + copy(oid[0:20], b[0:20]) return oid } func (oid *Oid) toC() *C.git_oid { - return (*C.git_oid)(unsafe.Pointer(&oid.bytes)) + return (*C.git_oid)(unsafe.Pointer(oid)) } func NewOidFromString(s string) (*Oid, error) { @@ -75,25 +73,25 @@ func (oid *Oid) String() string { } func (oid *Oid) Bytes() []byte { - return oid.bytes[0:] + return oid[0:] } func (oid *Oid) Cmp(oid2 *Oid) int { - return bytes.Compare(oid.bytes[:], oid2.bytes[:]) + return bytes.Compare(oid[:], oid2[:]) } func (oid *Oid) Copy() *Oid { ret := new(Oid) - copy(ret.bytes[:], oid.bytes[:]) + copy(ret[:], oid[:]) return ret } func (oid *Oid) Equal(oid2 *Oid) bool { - return bytes.Equal(oid.bytes[:], oid2.bytes[:]) + return bytes.Equal(oid[:], oid2[:]) } func (oid *Oid) IsZero() bool { - for _, a := range oid.bytes { + for _, a := range oid { if a != '0' { return false } @@ -102,7 +100,7 @@ func (oid *Oid) IsZero() bool { } func (oid *Oid) NCmp(oid2 *Oid, n uint) int { - return bytes.Compare(oid.bytes[:n], oid2.bytes[:n]) + return bytes.Compare(oid[:n], oid2[:n]) } func ShortenOids(ids []*Oid, minlen int) (int, error) { From c9c7c1e77942f88955af0dc3bdfb58d5e7d7f121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 18 Mar 2014 05:04:26 +0100 Subject: [PATCH 57/66] Oid: make NewOid take a string This is the most common way of having an id that's not in Oid form, so let's make it the "default" and rename to NewOidFromBytes() the one that takes []byte. --- git.go | 4 ++-- odb_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git.go b/git.go index 8f543b5..f3fb7e1 100644 --- a/git.go +++ b/git.go @@ -41,7 +41,7 @@ func newOidFromC(coid *C.git_oid) *Oid { return oid } -func NewOid(b []byte) *Oid { +func NewOidFromBytes(b []byte) *Oid { oid := new(Oid) copy(oid[0:20], b[0:20]) return oid @@ -51,7 +51,7 @@ func (oid *Oid) toC() *C.git_oid { return (*C.git_oid)(unsafe.Pointer(oid)) } -func NewOidFromString(s string) (*Oid, error) { +func NewOid(s string) (*Oid, error) { o := new(Oid) cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) diff --git a/odb_test.go b/odb_test.go index a4f8943..17b3ad2 100644 --- a/odb_test.go +++ b/odb_test.go @@ -27,7 +27,7 @@ func TestOdbStream(t *testing.T) { error = stream.Close() checkFatal(t, error) - expectedId, error := NewOidFromString("30f51a3fba5274d53522d0f19748456974647b4f") + expectedId, error := NewOid("30f51a3fba5274d53522d0f19748456974647b4f") checkFatal(t, error) if stream.Id.Cmp(expectedId) != 0 { t.Fatal("Wrong data written") @@ -59,4 +59,4 @@ Initial commit.`; if oid.Cmp(coid) != 0 { t.Fatal("Hash and write Oids are different") } -} \ No newline at end of file +} From c243c31f7d428680579a1dd20273cd3888c730e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 19 Mar 2014 03:11:41 +0100 Subject: [PATCH 58/66] Oid: remove Bytes() This is not needed. We can do id[:] to get a slice. --- git.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/git.go b/git.go index f3fb7e1..9e1d3e7 100644 --- a/git.go +++ b/git.go @@ -28,7 +28,7 @@ func init() { C.git_threads_init() } -// Oid +// Oid represents the id for a Git object. type Oid [20]byte func newOidFromC(coid *C.git_oid) *Oid { @@ -72,10 +72,6 @@ func (oid *Oid) String() string { return string(buf) } -func (oid *Oid) Bytes() []byte { - return oid[0:] -} - func (oid *Oid) Cmp(oid2 *Oid) int { return bytes.Compare(oid[:], oid2[:]) } From 0bb73e43a8f26be8608cdd304d73cacb05753417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 19 Mar 2014 03:39:34 +0100 Subject: [PATCH 59/66] Oid: use Go's conversion functions Go already has all the necessary pieces for encoding and decoding hex strings. Using them let's us avoid going into C land. Benchmarks show this takes about half the time as using libgit2's functions. --- git.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/git.go b/git.go index 9e1d3e7..e5fe812 100644 --- a/git.go +++ b/git.go @@ -8,6 +8,7 @@ package git import "C" import ( "bytes" + "encoding/hex" "errors" "runtime" "strings" @@ -52,24 +53,23 @@ func (oid *Oid) toC() *C.git_oid { } func NewOid(s string) (*Oid, error) { - o := new(Oid) - cs := C.CString(s) - defer C.free(unsafe.Pointer(cs)) - - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - if ret := C.git_oid_fromstr(o.toC(), cs); ret < 0 { - return nil, MakeGitError(ret) + if len(s) > C.GIT_OID_HEXSZ { + return nil, errors.New("string is too long for oid") } + o := new(Oid) + + slice, error := hex.DecodeString(s) + if error != nil { + return nil, error + } + + copy(o[:], slice[:20]) return o, nil } func (oid *Oid) String() string { - buf := make([]byte, 40) - C.git_oid_fmt((*C.char)(unsafe.Pointer(&buf[0])), oid.toC()) - return string(buf) + return hex.EncodeToString(oid[:]) } func (oid *Oid) Cmp(oid2 *Oid) int { From b82a72a9ce4701a4560288c4ebf1511ffb415b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 19 Mar 2014 03:51:59 +0100 Subject: [PATCH 60/66] Oid: fix IsZero() We need to compare against the number zero, not its ASCII value. --- git.go | 2 +- git_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/git.go b/git.go index e5fe812..b20f993 100644 --- a/git.go +++ b/git.go @@ -88,7 +88,7 @@ func (oid *Oid) Equal(oid2 *Oid) bool { func (oid *Oid) IsZero() bool { for _, a := range oid { - if a != '0' { + if a != 0 { return false } } diff --git a/git_test.go b/git_test.go index fff3c6c..6542ca0 100644 --- a/git_test.go +++ b/git_test.go @@ -54,3 +54,11 @@ func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) { return commitId, treeId } + +func TestOidZero(t *testing.T) { + var zeroId Oid + + if !zeroId.IsZero() { + t.Error("Zero Oid is not zero") + } +} From ad128bdefb58927762798a5b708a63bff43b627e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 19 Mar 2014 07:54:52 +0100 Subject: [PATCH 61/66] Remote: don't mix allocators We cannot ask libgit2 to free the memory we have allocated ourselves, as it cannot know how to do it. Let's free the strarray ourselves. --- remote.go | 17 +++++++++++++++-- remote_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 remote_test.go diff --git a/remote.go b/remote.go index da688e7..3e01ce1 100644 --- a/remote.go +++ b/remote.go @@ -303,6 +303,19 @@ func makeCStringsFromStrings(s []string) **C.char { return x } +func freeStrarray(arr *C.git_strarray) { + count := int(arr.count) + size := unsafe.Sizeof(unsafe.Pointer(nil)) + + i := 0 + for p := uintptr(unsafe.Pointer(arr.strings)); i < count; p += size { + C.free(unsafe.Pointer(sptr(p))) + i++ + } + + C.free(unsafe.Pointer(arr.strings)) +} + func (o *Remote) GetFetchRefspecs() ([]string, error) { crefspecs := C.git_strarray{} @@ -323,7 +336,7 @@ func (o *Remote) SetFetchRefspecs(refspecs []string) error { crefspecs := C.git_strarray{} crefspecs.count = C.size_t(len(refspecs)) crefspecs.strings = makeCStringsFromStrings(refspecs) - defer C.git_strarray_free(&crefspecs) + defer freeStrarray(&crefspecs) runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -368,7 +381,7 @@ func (o *Remote) SetPushRefspecs(refspecs []string) error { crefspecs := C.git_strarray{} crefspecs.count = C.size_t(len(refspecs)) crefspecs.strings = makeCStringsFromStrings(refspecs) - defer C.git_strarray_free(&crefspecs) + defer freeStrarray(&crefspecs) runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/remote_test.go b/remote_test.go new file mode 100644 index 0000000..16675fc --- /dev/null +++ b/remote_test.go @@ -0,0 +1,27 @@ +package git + +import ( + "os" + "testing" +) + +func TestRefspecs(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + remote, err := repo.CreateRemoteInMemory("refs/heads/*:refs/heads/*", "git://foo/bar") + 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.GetFetchRefspecs() + checkFatal(t, err) + + compareStringList(t, expected, actual) +} From 3ae9813fca2837601e5a7c801972396a59e1eb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 19 Mar 2014 08:03:21 +0100 Subject: [PATCH 62/66] Clean up after the tests --- clone_test.go | 4 ++++ push_test.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/clone_test.go b/clone_test.go index 6145228..97366bf 100644 --- a/clone_test.go +++ b/clone_test.go @@ -2,18 +2,22 @@ package git import ( "io/ioutil" + "os" "testing" ) func TestClone(t *testing.T) { repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + seedTestRepo(t, repo) path, err := ioutil.TempDir("", "git2go") checkFatal(t, err) _, err = Clone(repo.Path(), path, &CloneOptions{Bare: true}) + defer os.RemoveAll(path) checkFatal(t, err) } diff --git a/push_test.go b/push_test.go index dfd4af7..c1e6a22 100644 --- a/push_test.go +++ b/push_test.go @@ -2,13 +2,16 @@ package git import ( "log" + "os" "testing" "time" ) func Test_Push_ToRemote(t *testing.T) { repo := createBareTestRepo(t) + defer os.RemoveAll(repo.Path()) repo2 := createTestRepo(t) + defer os.RemoveAll(repo2.Workdir()) remote, err := repo2.CreateRemote("test_push", repo.Path()) checkFatal(t, err) From 574f0dd12da2eae6f26ae35f197b2ec7a9328249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 20 Mar 2014 03:29:54 +0100 Subject: [PATCH 63/66] Remote: remove Get prefix from refspecs Idiomatic Go is to omit the Get from the getter methods. --- remote.go | 4 ++-- remote_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/remote.go b/remote.go index 3e01ce1..d556f99 100644 --- a/remote.go +++ b/remote.go @@ -316,7 +316,7 @@ func freeStrarray(arr *C.git_strarray) { C.free(unsafe.Pointer(arr.strings)) } -func (o *Remote) GetFetchRefspecs() ([]string, error) { +func (o *Remote) FetchRefspecs() ([]string, error) { crefspecs := C.git_strarray{} runtime.LockOSThread() @@ -362,7 +362,7 @@ func (o *Remote) AddPush(refspec string) error { return nil } -func (o *Remote) GetPushRefspecs() ([]string, error) { +func (o *Remote) PushRefspecs() ([]string, error) { crefspecs := C.git_strarray{} runtime.LockOSThread() diff --git a/remote_test.go b/remote_test.go index 16675fc..04b3a57 100644 --- a/remote_test.go +++ b/remote_test.go @@ -20,7 +20,7 @@ func TestRefspecs(t *testing.T) { err = remote.SetFetchRefspecs(expected) checkFatal(t, err) - actual, err := remote.GetFetchRefspecs() + actual, err := remote.FetchRefspecs() checkFatal(t, err) compareStringList(t, expected, actual) From 99d7f66477aa09915821659087da8b91e593f4eb Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 02:06:56 -0700 Subject: [PATCH 64/66] add remote list --- remote.go | 12 ++++++++++++ remote_test.go | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/remote.go b/remote.go index d556f99..d675ab8 100644 --- a/remote.go +++ b/remote.go @@ -132,6 +132,18 @@ func (r *Remote) Free() { C.git_remote_free(r.ptr) } +func (repo *Repository) ListRemotes() ([]string, error) { + var r C.git_strarray + ecode := C.git_remote_list(&r, repo.ptr) + if ecode < 0 { + return make([]string, 0), MakeGitError(ecode) + } + defer C.git_strarray_free(&r) + + remotes := makeStringsFromCStrings(r.strings, int(r.count)) + return remotes, nil +} + func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) { remote := &Remote{} diff --git a/remote_test.go b/remote_test.go index 04b3a57..90e24ae 100644 --- a/remote_test.go +++ b/remote_test.go @@ -8,6 +8,7 @@ import ( func TestRefspecs(t *testing.T) { repo := createTestRepo(t) defer os.RemoveAll(repo.Workdir()) + defer repo.Free() remote, err := repo.CreateRemoteInMemory("refs/heads/*:refs/heads/*", "git://foo/bar") checkFatal(t, err) @@ -25,3 +26,22 @@ func TestRefspecs(t *testing.T) { compareStringList(t, expected, actual) } + +func TestListRemotes(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + defer repo.Free() + + _, err := repo.CreateRemote("test", "git://foo/bar") + + checkFatal(t, err) + + expected := []string{ + "test", + } + + actual, err := repo.ListRemotes() + checkFatal(t, err) + + compareStringList(t, expected, actual) +} From 5d8db7f9362a314cf56747cf23605aec8640e92e Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 20:24:29 -0700 Subject: [PATCH 65/66] return nil instead of empty array on error --- remote.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote.go b/remote.go index d675ab8..66097b8 100644 --- a/remote.go +++ b/remote.go @@ -136,7 +136,7 @@ func (repo *Repository) ListRemotes() ([]string, error) { var r C.git_strarray ecode := C.git_remote_list(&r, repo.ptr) if ecode < 0 { - return make([]string, 0), MakeGitError(ecode) + return nil, MakeGitError(ecode) } defer C.git_strarray_free(&r) From 1f3f8adda8d6df5053faa63487e70cb3f29f2673 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 20:49:05 -0700 Subject: [PATCH 66/66] Add index WriteTreeTo + test --- index.go | 18 ++++++++++++++++-- index_test.go | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/index.go b/index.go index 6da3c98..7336249 100644 --- a/index.go +++ b/index.go @@ -23,7 +23,7 @@ type IndexEntry struct { Uid uint Gid uint Size uint - Id *Oid + Id *Oid Path string } @@ -48,6 +48,20 @@ func (v *Index) AddByPath(path string) error { return nil } +func (v *Index) WriteTreeTo(repo *Repository) (*Oid, error) { + oid := new(Oid) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_index_write_tree_to(oid.toC(), v.ptr, repo.ptr) + if ret < 0 { + return nil, MakeGitError(ret) + } + + return oid, nil +} + func (v *Index) WriteTree() (*Oid, error) { oid := new(Oid) @@ -62,7 +76,7 @@ func (v *Index) WriteTree() (*Oid, error) { return oid, nil } -func (v *Index) Write() (error) { +func (v *Index) Write() error { runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/index_test.go b/index_test.go index 9828d0f..5920b93 100644 --- a/index_test.go +++ b/index_test.go @@ -22,6 +22,25 @@ func TestCreateRepoAndStage(t *testing.T) { } } +func TestIndexWriteTreeTo(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + repo2 := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + idx, err := repo.Index() + checkFatal(t, err) + err = idx.AddByPath("README") + checkFatal(t, err) + treeId, err := idx.WriteTreeTo(repo2) + checkFatal(t, err) + + if treeId.String() != "b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e" { + t.Fatalf("%v", treeId.String()) + } +} + func checkFatal(t *testing.T, err error) { if err == nil { return