diff options
Diffstat (limited to 'remote.go')
| -rw-r--r-- | remote.go | 114 |
1 files changed, 106 insertions, 8 deletions
@@ -15,6 +15,7 @@ import ( "reflect" "runtime" "strings" + "sync" "unsafe" ) @@ -174,6 +175,64 @@ type Remote struct { repo *Repository } +type remotePointerList struct { + sync.RWMutex + // stores the Go pointers + pointers map[*C.git_remote]*Remote +} + +func newRemotePointerList() *remotePointerList { + return &remotePointerList{ + pointers: make(map[*C.git_remote]*Remote), + } +} + +// track adds the given pointer to the list of pointers to track and +// returns a pointer value which can be passed to C as an opaque +// pointer. +func (v *remotePointerList) track(remote *Remote) { + v.Lock() + v.pointers[remote.ptr] = remote + v.Unlock() + + runtime.SetFinalizer(remote, (*Remote).Free) +} + +// untrack stops tracking the git_remote pointer. +func (v *remotePointerList) untrack(remote *Remote) { + v.Lock() + delete(v.pointers, remote.ptr) + v.Unlock() +} + +// clear stops tracking all the git_remote pointers. +func (v *remotePointerList) clear() { + v.Lock() + var remotes []*Remote + for remotePtr, remote := range v.pointers { + remotes = append(remotes, remote) + delete(v.pointers, remotePtr) + } + v.Unlock() + + for _, remote := range remotes { + remote.free() + } +} + +// get retrieves the pointer from the given *git_remote. +func (v *remotePointerList) get(ptr *C.git_remote) (*Remote, bool) { + v.RLock() + defer v.RUnlock() + + r, ok := v.pointers[ptr] + if !ok { + return nil, false + } + + return r, true +} + type CertificateKind uint const ( @@ -509,17 +568,42 @@ func RemoteIsValidName(name string) bool { return C.git_remote_is_valid_name(cname) == 1 } -// Free releases the resources of the Remote. -func (r *Remote) Free() { +// free releases the resources of the Remote. +func (r *Remote) free() { runtime.SetFinalizer(r, nil) C.git_remote_free(r.ptr) r.ptr = nil r.repo = nil } +// Free releases the resources of the Remote. +func (r *Remote) Free() { + r.repo.Remotes.untrackRemote(r) + r.free() +} + type RemoteCollection struct { doNotCompare repo *Repository + + sync.RWMutex + remotes map[*C.git_remote]*Remote +} + +func (c *RemoteCollection) trackRemote(r *Remote) { + c.Lock() + c.remotes[r.ptr] = r + c.Unlock() + + remotePointers.track(r) +} + +func (c *RemoteCollection) untrackRemote(r *Remote) { + c.Lock() + delete(c.remotes, r.ptr) + c.Unlock() + + remotePointers.untrack(r) } func (c *RemoteCollection) List() ([]string, error) { @@ -554,7 +638,7 @@ func (c *RemoteCollection) Create(name string, url string) (*Remote, error) { if ret < 0 { return nil, MakeGitError(ret) } - runtime.SetFinalizer(remote, (*Remote).Free) + c.trackRemote(remote) return remote, nil } @@ -570,13 +654,13 @@ func (c *RemoteCollection) CreateWithOptions(url string, option *RemoteCreateOpt copts := populateRemoteCreateOptions(&C.git_remote_create_options{}, option, c.repo) defer freeRemoteCreateOptions(copts) + ret := C.git_remote_create_with_opts(&remote.ptr, curl, copts) runtime.KeepAlive(c.repo) if ret < 0 { return nil, MakeGitError(ret) } - - runtime.SetFinalizer(remote, (*Remote).Free) + c.trackRemote(remote) return remote, nil } @@ -612,7 +696,7 @@ func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch st if ret < 0 { return nil, MakeGitError(ret) } - runtime.SetFinalizer(remote, (*Remote).Free) + c.trackRemote(remote) return remote, nil } @@ -629,7 +713,7 @@ func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) { if ret < 0 { return nil, MakeGitError(ret) } - runtime.SetFinalizer(remote, (*Remote).Free) + c.trackRemote(remote) return remote, nil } @@ -646,10 +730,24 @@ func (c *RemoteCollection) Lookup(name string) (*Remote, error) { if ret < 0 { return nil, MakeGitError(ret) } - runtime.SetFinalizer(remote, (*Remote).Free) + c.trackRemote(remote) return remote, nil } +func (c *RemoteCollection) Free() { + var remotes []*Remote + c.Lock() + for remotePtr, remote := range c.remotes { + remotes = append(remotes, remote) + delete(c.remotes, remotePtr) + } + c.Unlock() + + for _, remote := range remotes { + remotePointers.untrack(remote) + } +} + func (o *Remote) Name() string { s := C.git_remote_name(o.ptr) runtime.KeepAlive(o) |
