@@ -14,6 +14,7 @@ import (
1414 "reflect"
1515 "runtime"
1616 "strings"
17+ "sync"
1718 "unsafe"
1819)
1920
@@ -173,6 +174,64 @@ type Remote struct {
173174 repo * Repository
174175}
175176
177+ type remotePointerList struct {
178+ sync.RWMutex
179+ // stores the Go pointers
180+ pointers map [* C.git_remote ]* Remote
181+ }
182+
183+ func newRemotePointerList () * remotePointerList {
184+ return & remotePointerList {
185+ pointers : make (map [* C.git_remote ]* Remote ),
186+ }
187+ }
188+
189+ // track adds the given pointer to the list of pointers to track and
190+ // returns a pointer value which can be passed to C as an opaque
191+ // pointer.
192+ func (v * remotePointerList ) track (remote * Remote ) {
193+ v .Lock ()
194+ v .pointers [remote .ptr ] = remote
195+ v .Unlock ()
196+
197+ runtime .SetFinalizer (remote , (* Remote ).Free )
198+ }
199+
200+ // untrack stops tracking the git_remote pointer.
201+ func (v * remotePointerList ) untrack (remote * Remote ) {
202+ v .Lock ()
203+ delete (v .pointers , remote .ptr )
204+ v .Unlock ()
205+ }
206+
207+ // clear stops tracking all the git_remote pointers.
208+ func (v * remotePointerList ) clear () {
209+ v .Lock ()
210+ var remotes []* Remote
211+ for remotePtr , remote := range v .pointers {
212+ remotes = append (remotes , remote )
213+ delete (v .pointers , remotePtr )
214+ }
215+ v .Unlock ()
216+
217+ for _ , remote := range remotes {
218+ remote .free ()
219+ }
220+ }
221+
222+ // get retrieves the pointer from the given *git_remote.
223+ func (v * remotePointerList ) get (ptr * C.git_remote ) (* Remote , bool ) {
224+ v .RLock ()
225+ defer v .RUnlock ()
226+
227+ r , ok := v .pointers [ptr ]
228+ if ! ok {
229+ return nil , false
230+ }
231+
232+ return r , true
233+ }
234+
176235type CertificateKind uint
177236
178237const (
@@ -507,17 +566,42 @@ func RemoteIsValidName(name string) bool {
507566 return C .git_remote_is_valid_name (cname ) == 1
508567}
509568
510- // Free releases the resources of the Remote.
511- func (r * Remote ) Free () {
569+ // free releases the resources of the Remote.
570+ func (r * Remote ) free () {
512571 runtime .SetFinalizer (r , nil )
513572 C .git_remote_free (r .ptr )
514573 r .ptr = nil
515574 r .repo = nil
516575}
517576
577+ // Free releases the resources of the Remote.
578+ func (r * Remote ) Free () {
579+ r .repo .Remotes .untrackRemote (r )
580+ r .free ()
581+ }
582+
518583type RemoteCollection struct {
519584 doNotCompare
520585 repo * Repository
586+
587+ sync.RWMutex
588+ remotes map [* C.git_remote ]* Remote
589+ }
590+
591+ func (c * RemoteCollection ) trackRemote (r * Remote ) {
592+ c .Lock ()
593+ c .remotes [r .ptr ] = r
594+ c .Unlock ()
595+
596+ remotePointers .track (r )
597+ }
598+
599+ func (c * RemoteCollection ) untrackRemote (r * Remote ) {
600+ c .Lock ()
601+ delete (c .remotes , r .ptr )
602+ c .Unlock ()
603+
604+ remotePointers .untrack (r )
521605}
522606
523607func (c * RemoteCollection ) List () ([]string , error ) {
@@ -552,7 +636,7 @@ func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
552636 if ret < 0 {
553637 return nil , MakeGitError (ret )
554638 }
555- runtime . SetFinalizer (remote , ( * Remote ). Free )
639+ c . trackRemote (remote )
556640 return remote , nil
557641}
558642
@@ -568,13 +652,13 @@ func (c *RemoteCollection) CreateWithOptions(url string, option *RemoteCreateOpt
568652
569653 copts := populateRemoteCreateOptions (& C.git_remote_create_options {}, option , c .repo )
570654 defer freeRemoteCreateOptions (copts )
655+
571656 ret := C .git_remote_create_with_opts (& remote .ptr , curl , copts )
572657 runtime .KeepAlive (c .repo )
573658 if ret < 0 {
574659 return nil , MakeGitError (ret )
575660 }
576-
577- runtime .SetFinalizer (remote , (* Remote ).Free )
661+ c .trackRemote (remote )
578662 return remote , nil
579663}
580664
@@ -610,7 +694,7 @@ func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch st
610694 if ret < 0 {
611695 return nil , MakeGitError (ret )
612696 }
613- runtime . SetFinalizer (remote , ( * Remote ). Free )
697+ c . trackRemote (remote )
614698 return remote , nil
615699}
616700
@@ -627,7 +711,7 @@ func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
627711 if ret < 0 {
628712 return nil , MakeGitError (ret )
629713 }
630- runtime . SetFinalizer (remote , ( * Remote ). Free )
714+ c . trackRemote (remote )
631715 return remote , nil
632716}
633717
@@ -644,10 +728,24 @@ func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
644728 if ret < 0 {
645729 return nil , MakeGitError (ret )
646730 }
647- runtime . SetFinalizer (remote , ( * Remote ). Free )
731+ c . trackRemote (remote )
648732 return remote , nil
649733}
650734
735+ func (c * RemoteCollection ) Free () {
736+ var remotes []* Remote
737+ c .Lock ()
738+ for remotePtr , remote := range c .remotes {
739+ remotes = append (remotes , remote )
740+ delete (c .remotes , remotePtr )
741+ }
742+ c .Unlock ()
743+
744+ for _ , remote := range remotes {
745+ remotePointers .untrack (remote )
746+ }
747+ }
748+
651749func (o * Remote ) Name () string {
652750 s := C .git_remote_name (o .ptr )
653751 runtime .KeepAlive (o )
0 commit comments