fork of go-git with some jj specific features
at main 3.5 kB view raw
1package transactional 2 3import ( 4 "github.com/go-git/go-git/v5/plumbing" 5 "github.com/go-git/go-git/v5/plumbing/storer" 6 "github.com/go-git/go-git/v5/storage" 7) 8 9// ReferenceStorage implements the storer.ReferenceStorage for the transactional package. 10type ReferenceStorage struct { 11 storer.ReferenceStorer 12 temporal storer.ReferenceStorer 13 14 // deleted, remaining references at this maps are going to be deleted when 15 // commit is requested, the entries are added when RemoveReference is called 16 // and deleted if SetReference is called. 17 deleted map[plumbing.ReferenceName]struct{} 18} 19 20// NewReferenceStorage returns a new ReferenceStorer based on a base storer and 21// a temporal storer. 22func NewReferenceStorage(base, temporal storer.ReferenceStorer) *ReferenceStorage { 23 return &ReferenceStorage{ 24 ReferenceStorer: base, 25 temporal: temporal, 26 27 deleted: make(map[plumbing.ReferenceName]struct{}), 28 } 29} 30 31// SetReference honors the storer.ReferenceStorer interface. 32func (r *ReferenceStorage) SetReference(ref *plumbing.Reference) error { 33 delete(r.deleted, ref.Name()) 34 return r.temporal.SetReference(ref) 35} 36 37// SetReference honors the storer.ReferenceStorer interface. 38func (r *ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error { 39 if old == nil { 40 return r.SetReference(ref) 41 } 42 43 tmp, err := r.temporal.Reference(old.Name()) 44 if err == plumbing.ErrReferenceNotFound { 45 tmp, err = r.ReferenceStorer.Reference(old.Name()) 46 } 47 48 if err != nil { 49 return err 50 } 51 52 if tmp.Hash() != old.Hash() { 53 return storage.ErrReferenceHasChanged 54 } 55 56 return r.SetReference(ref) 57} 58 59// Reference honors the storer.ReferenceStorer interface. 60func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) { 61 if _, deleted := r.deleted[n]; deleted { 62 return nil, plumbing.ErrReferenceNotFound 63 } 64 65 ref, err := r.temporal.Reference(n) 66 if err == plumbing.ErrReferenceNotFound { 67 return r.ReferenceStorer.Reference(n) 68 } 69 70 return ref, err 71} 72 73// IterReferences honors the storer.ReferenceStorer interface. 74func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) { 75 baseIter, err := r.ReferenceStorer.IterReferences() 76 if err != nil { 77 return nil, err 78 } 79 80 temporalIter, err := r.temporal.IterReferences() 81 if err != nil { 82 return nil, err 83 } 84 85 return storer.NewMultiReferenceIter([]storer.ReferenceIter{ 86 baseIter, 87 temporalIter, 88 }), nil 89} 90 91// CountLooseRefs honors the storer.ReferenceStorer interface. 92func (r ReferenceStorage) CountLooseRefs() (int, error) { 93 tc, err := r.temporal.CountLooseRefs() 94 if err != nil { 95 return -1, err 96 } 97 98 bc, err := r.ReferenceStorer.CountLooseRefs() 99 if err != nil { 100 return -1, err 101 } 102 103 return tc + bc, nil 104} 105 106// PackRefs honors the storer.ReferenceStorer interface. 107func (r ReferenceStorage) PackRefs() error { 108 return nil 109} 110 111// RemoveReference honors the storer.ReferenceStorer interface. 112func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error { 113 r.deleted[n] = struct{}{} 114 return r.temporal.RemoveReference(n) 115} 116 117// Commit it copies the reference information of the temporal storage into the 118// base storage. 119func (r ReferenceStorage) Commit() error { 120 for name := range r.deleted { 121 if err := r.ReferenceStorer.RemoveReference(name); err != nil { 122 return err 123 } 124 } 125 126 iter, err := r.temporal.IterReferences() 127 if err != nil { 128 return err 129 } 130 131 return iter.ForEach(func(ref *plumbing.Reference) error { 132 return r.ReferenceStorer.SetReference(ref) 133 }) 134}