bug_cache.go

  1package cache
  2
  3import (
  4	"fmt"
  5	"time"
  6
  7	"github.com/MichaelMure/git-bug/entities/bug"
  8	"github.com/MichaelMure/git-bug/entity"
  9	"github.com/MichaelMure/git-bug/entity/dag"
 10	"github.com/MichaelMure/git-bug/repository"
 11)
 12
 13var ErrNoMatchingOp = fmt.Errorf("no matching operation found")
 14
 15var _ bug.Interface = &BugCache{}
 16
 17// BugCache is a wrapper around a Bug. It provides multiple functions:
 18//
 19// 1. Provide a higher level API to use than the raw API from Bug.
 20// 2. Maintain an up-to-date Snapshot available.
 21// 3. Deal with concurrency.
 22type BugCache struct {
 23	CachedEntityBase[*bug.Snapshot, bug.Operation]
 24}
 25
 26func NewBugCache(b *bug.Bug, repo repository.ClockedRepo, getUserIdentity getUserIdentityFunc, entityUpdated func(id entity.Id) error) *BugCache {
 27	return &BugCache{
 28		CachedEntityBase: CachedEntityBase[*bug.Snapshot, bug.Operation]{
 29			repo:            repo,
 30			entityUpdated:   entityUpdated,
 31			getUserIdentity: getUserIdentity,
 32			entity:          &withSnapshot[*bug.Snapshot, bug.Operation]{WithCommit: b},
 33		},
 34	}
 35}
 36
 37func (c *BugCache) AddComment(message string) (entity.CombinedId, *bug.AddCommentOperation, error) {
 38	return c.AddCommentWithFiles(message, nil)
 39}
 40
 41func (c *BugCache) AddCommentWithFiles(message string, files []repository.Hash) (entity.CombinedId, *bug.AddCommentOperation, error) {
 42	author, err := c.getUserIdentity()
 43	if err != nil {
 44		return entity.UnsetCombinedId, nil, err
 45	}
 46
 47	return c.AddCommentRaw(author, time.Now().Unix(), message, files, nil)
 48}
 49
 50func (c *BugCache) AddCommentRaw(author entity.Identity, unixTime int64, message string, files []repository.Hash, metadata map[string]string) (entity.CombinedId, *bug.AddCommentOperation, error) {
 51	c.mu.Lock()
 52	commentId, op, err := bug.AddComment(c.entity, author, unixTime, message, files, metadata)
 53	c.mu.Unlock()
 54	if err != nil {
 55		return entity.UnsetCombinedId, nil, err
 56	}
 57	return commentId, op, c.notifyUpdated()
 58}
 59
 60func (c *BugCache) ChangeLabels(added []string, removed []string) ([]bug.LabelChangeResult, *bug.LabelChangeOperation, error) {
 61	author, err := c.getUserIdentity()
 62	if err != nil {
 63		return nil, nil, err
 64	}
 65
 66	return c.ChangeLabelsRaw(author, time.Now().Unix(), added, removed, nil)
 67}
 68
 69func (c *BugCache) ChangeLabelsRaw(author entity.Identity, unixTime int64, added []string, removed []string, metadata map[string]string) ([]bug.LabelChangeResult, *bug.LabelChangeOperation, error) {
 70	c.mu.Lock()
 71	changes, op, err := bug.ChangeLabels(c.entity, author, unixTime, added, removed, metadata)
 72	c.mu.Unlock()
 73	if err != nil {
 74		return changes, nil, err
 75	}
 76	return changes, op, c.notifyUpdated()
 77}
 78
 79func (c *BugCache) ForceChangeLabels(added []string, removed []string) (*bug.LabelChangeOperation, error) {
 80	author, err := c.getUserIdentity()
 81	if err != nil {
 82		return nil, err
 83	}
 84
 85	return c.ForceChangeLabelsRaw(author, time.Now().Unix(), added, removed, nil)
 86}
 87
 88func (c *BugCache) ForceChangeLabelsRaw(author entity.Identity, unixTime int64, added []string, removed []string, metadata map[string]string) (*bug.LabelChangeOperation, error) {
 89	c.mu.Lock()
 90	op, err := bug.ForceChangeLabels(c.entity, author, unixTime, added, removed, metadata)
 91	c.mu.Unlock()
 92	if err != nil {
 93		return nil, err
 94	}
 95	return op, c.notifyUpdated()
 96}
 97
 98func (c *BugCache) Open() (*bug.SetStatusOperation, error) {
 99	author, err := c.getUserIdentity()
100	if err != nil {
101		return nil, err
102	}
103
104	return c.OpenRaw(author, time.Now().Unix(), nil)
105}
106
107func (c *BugCache) OpenRaw(author entity.Identity, unixTime int64, metadata map[string]string) (*bug.SetStatusOperation, error) {
108	c.mu.Lock()
109	op, err := bug.Open(c.entity, author, unixTime, metadata)
110	c.mu.Unlock()
111	if err != nil {
112		return nil, err
113	}
114	return op, c.notifyUpdated()
115}
116
117func (c *BugCache) Close() (*bug.SetStatusOperation, error) {
118	author, err := c.getUserIdentity()
119	if err != nil {
120		return nil, err
121	}
122
123	return c.CloseRaw(author, time.Now().Unix(), nil)
124}
125
126func (c *BugCache) CloseRaw(author entity.Identity, unixTime int64, metadata map[string]string) (*bug.SetStatusOperation, error) {
127	c.mu.Lock()
128	op, err := bug.Close(c.entity, author, unixTime, metadata)
129	c.mu.Unlock()
130	if err != nil {
131		return nil, err
132	}
133	return op, c.notifyUpdated()
134}
135
136func (c *BugCache) SetTitle(title string) (*bug.SetTitleOperation, error) {
137	author, err := c.getUserIdentity()
138	if err != nil {
139		return nil, err
140	}
141
142	return c.SetTitleRaw(author, time.Now().Unix(), title, nil)
143}
144
145func (c *BugCache) SetTitleRaw(author entity.Identity, unixTime int64, title string, metadata map[string]string) (*bug.SetTitleOperation, error) {
146	c.mu.Lock()
147	op, err := bug.SetTitle(c.entity, author, unixTime, title, metadata)
148	c.mu.Unlock()
149	if err != nil {
150		return nil, err
151	}
152	return op, c.notifyUpdated()
153}
154
155// EditCreateComment is a convenience function to edit the body of a bug (the first comment)
156func (c *BugCache) EditCreateComment(body string) (entity.CombinedId, *bug.EditCommentOperation, error) {
157	author, err := c.getUserIdentity()
158	if err != nil {
159		return entity.UnsetCombinedId, nil, err
160	}
161
162	return c.EditCreateCommentRaw(author, time.Now().Unix(), body, nil)
163}
164
165// EditCreateCommentRaw is a convenience function to edit the body of a bug (the first comment)
166func (c *BugCache) EditCreateCommentRaw(author entity.Identity, unixTime int64, body string, metadata map[string]string) (entity.CombinedId, *bug.EditCommentOperation, error) {
167	c.mu.Lock()
168	commentId, op, err := bug.EditCreateComment(c.entity, author, unixTime, body, nil, metadata)
169	c.mu.Unlock()
170	if err != nil {
171		return entity.UnsetCombinedId, nil, err
172	}
173	return commentId, op, c.notifyUpdated()
174}
175
176func (c *BugCache) EditComment(target entity.CombinedId, message string) (*bug.EditCommentOperation, error) {
177	author, err := c.getUserIdentity()
178	if err != nil {
179		return nil, err
180	}
181
182	return c.EditCommentRaw(author, time.Now().Unix(), target, message, nil)
183}
184
185func (c *BugCache) EditCommentRaw(author entity.Identity, unixTime int64, target entity.CombinedId, message string, metadata map[string]string) (*bug.EditCommentOperation, error) {
186	comment, err := c.Compile().SearchComment(target)
187	if err != nil {
188		return nil, err
189	}
190
191	c.mu.Lock()
192	commentId, op, err := bug.EditComment(c.entity, author, unixTime, comment.TargetId(), message, nil, metadata)
193	c.mu.Unlock()
194	if err != nil {
195		return nil, err
196	}
197	if commentId != target {
198		panic("EditComment returned unexpected comment id")
199	}
200	return op, c.notifyUpdated()
201}
202
203func (c *BugCache) SetMetadata(target entity.Id, newMetadata map[string]string) (*dag.SetMetadataOperation[*bug.Snapshot], error) {
204	author, err := c.getUserIdentity()
205	if err != nil {
206		return nil, err
207	}
208
209	return c.SetMetadataRaw(author, time.Now().Unix(), target, newMetadata)
210}
211
212func (c *BugCache) SetMetadataRaw(author entity.Identity, unixTime int64, target entity.Id, newMetadata map[string]string) (*dag.SetMetadataOperation[*bug.Snapshot], error) {
213	c.mu.Lock()
214	op, err := bug.SetMetadata(c.entity, author, unixTime, target, newMetadata)
215	c.mu.Unlock()
216	if err != nil {
217		return nil, err
218	}
219	return op, c.notifyUpdated()
220}