1package cache
2
3import (
4 "fmt"
5 "time"
6
7 "github.com/MichaelMure/git-bug/bug"
8 "github.com/MichaelMure/git-bug/entity"
9 "github.com/MichaelMure/git-bug/util/git"
10)
11
12var ErrNoMatchingOp = fmt.Errorf("no matching operation found")
13
14// BugCache is a wrapper around a Bug. It provide multiple functions:
15//
16// 1. Provide a higher level API to use than the raw API from Bug.
17// 2. Maintain an up to date Snapshot available.
18type BugCache struct {
19 repoCache *RepoCache
20 bug *bug.WithSnapshot
21}
22
23func NewBugCache(repoCache *RepoCache, b *bug.Bug) *BugCache {
24 return &BugCache{
25 repoCache: repoCache,
26 bug: &bug.WithSnapshot{Bug: b},
27 }
28}
29
30func (c *BugCache) Snapshot() *bug.Snapshot {
31 return c.bug.Snapshot()
32}
33
34func (c *BugCache) Id() entity.Id {
35 return c.bug.Id()
36}
37
38func (c *BugCache) notifyUpdated() error {
39 return c.repoCache.bugUpdated(c.bug.Id())
40}
41
42// ResolveOperationWithMetadata will find an operation that has the matching metadata
43func (c *BugCache) ResolveOperationWithMetadata(key string, value string) (entity.Id, error) {
44 // preallocate but empty
45 matching := make([]entity.Id, 0, 5)
46
47 it := bug.NewOperationIterator(c.bug)
48 for it.Next() {
49 op := it.Value()
50 opValue, ok := op.GetMetadata(key)
51 if ok && value == opValue {
52 matching = append(matching, op.Id())
53 }
54 }
55
56 if len(matching) == 0 {
57 return "", ErrNoMatchingOp
58 }
59
60 if len(matching) > 1 {
61 return "", bug.NewErrMultipleMatchOp(matching)
62 }
63
64 return matching[0], nil
65}
66
67func (c *BugCache) AddComment(message string) (*bug.AddCommentOperation, error) {
68 return c.AddCommentWithFiles(message, nil)
69}
70
71func (c *BugCache) OpAddComment(message string) (*bug.AddCommentOperation, error) {
72 return c.Op
73}
74
75func (c *BugCache) AddCommentWithFiles(message string, files []git.Hash) (*bug.AddCommentOperation, error) {
76 author, err := c.repoCache.GetUserIdentity()
77 if err != nil {
78 return nil, err
79 }
80
81 return c.AddCommentRaw(author, time.Now().Unix(), message, files, nil)
82}
83
84func (c *BugCache) OpAddCommentWithFiles(message string, files []git.Hash) (*bug.AddCommentOperation, error) {
85 return c.Op
86}
87
88func (c *BugCache) AddCommentRaw(author *IdentityCache, unixTime int64, message string, files []git.Hash, metadata map[string]string) (*bug.AddCommentOperation, error) {
89 op, err := bug.AddCommentWithFiles(c.bug, author.Identity, unixTime, message, files)
90 if err != nil {
91 return nil, err
92 }
93
94 for key, value := range metadata {
95 op.SetMetadata(key, value)
96 }
97
98 return op, c.notifyUpdated()
99}
100
101func (c *BugCache) OpAddCommentRaw(author *IdentityCache, unixTime int64, message string, files []git.Hash, metadata map[string]string) (*bug.AddCommentOperation, error) {
102 op, err := bug.OpAddCommentWithFiles(author.Identity, unixTime, message, files)
103 if err != nil {
104 return nil, err
105 }
106
107 for key, value := range metadata {
108 op.SetMetadata(key, value)
109 }
110}
111
112func (c *BugCache) ChangeLabels(added []string, removed []string) ([]bug.LabelChangeResult, *bug.LabelChangeOperation, error) {
113 author, err := c.repoCache.GetUserIdentity()
114 if err != nil {
115 return nil, nil, err
116 }
117
118 return c.ChangeLabelsRaw(author, time.Now().Unix(), added, removed, nil)
119}
120
121func (c *BugCache) ChangeLabelsRaw(author *IdentityCache, unixTime int64, added []string, removed []string, metadata map[string]string) ([]bug.LabelChangeResult, *bug.LabelChangeOperation, error) {
122 changes, op, err := bug.ChangeLabels(c.bug, author.Identity, unixTime, added, removed)
123 if err != nil {
124 return changes, nil, err
125 }
126
127 for key, value := range metadata {
128 op.SetMetadata(key, value)
129 }
130
131 err = c.notifyUpdated()
132 if err != nil {
133 return nil, nil, err
134 }
135
136 return changes, op, nil
137}
138
139func (c *BugCache) ForceChangeLabels(added []string, removed []string) (*bug.LabelChangeOperation, error) {
140 author, err := c.repoCache.GetUserIdentity()
141 if err != nil {
142 return nil, err
143 }
144
145 return c.ForceChangeLabelsRaw(author, time.Now().Unix(), added, removed, nil)
146}
147
148func (c *BugCache) ForceChangeLabelsRaw(author *IdentityCache, unixTime int64, added []string, removed []string, metadata map[string]string) (*bug.LabelChangeOperation, error) {
149 op, err := bug.ForceChangeLabels(c.bug, author.Identity, unixTime, added, removed)
150 if err != nil {
151 return nil, err
152 }
153
154 for key, value := range metadata {
155 op.SetMetadata(key, value)
156 }
157
158 err = c.notifyUpdated()
159 if err != nil {
160 return nil, err
161 }
162
163 return op, nil
164}
165
166func (c *BugCache) Open() (*bug.SetStatusOperation, error) {
167 author, err := c.repoCache.GetUserIdentity()
168 if err != nil {
169 return nil, err
170 }
171
172 return c.OpenRaw(author, time.Now().Unix(), nil)
173}
174
175func (c *BugCache) OpenRaw(author *IdentityCache, unixTime int64, metadata map[string]string) (*bug.SetStatusOperation, error) {
176 op, err := bug.Open(c.bug, author.Identity, unixTime)
177 if err != nil {
178 return nil, err
179 }
180
181 for key, value := range metadata {
182 op.SetMetadata(key, value)
183 }
184
185 return op, c.notifyUpdated()
186}
187
188func (c *BugCache) Close() (*bug.SetStatusOperation, error) {
189 author, err := c.repoCache.GetUserIdentity()
190 if err != nil {
191 return nil, err
192 }
193
194 return c.CloseRaw(author, time.Now().Unix(), nil)
195}
196
197func (c *BugCache) CloseRaw(author *IdentityCache, unixTime int64, metadata map[string]string) (*bug.SetStatusOperation, error) {
198 op, err := bug.Close(c.bug, author.Identity, unixTime)
199 if err != nil {
200 return nil, err
201 }
202
203 for key, value := range metadata {
204 op.SetMetadata(key, value)
205 }
206
207 return op, c.notifyUpdated()
208}
209
210func (c *BugCache) SetTitle(title string) (*bug.SetTitleOperation, error) {
211 author, err := c.repoCache.GetUserIdentity()
212 if err != nil {
213 return nil, err
214 }
215
216 return c.SetTitleRaw(author, time.Now().Unix(), title, nil)
217}
218
219func (c *BugCache) SetTitleRaw(author *IdentityCache, unixTime int64, title string, metadata map[string]string) (*bug.SetTitleOperation, error) {
220 op, err := bug.SetTitle(c.bug, author.Identity, unixTime, title)
221 if err != nil {
222 return nil, err
223 }
224
225 for key, value := range metadata {
226 op.SetMetadata(key, value)
227 }
228
229 return op, c.notifyUpdated()
230}
231
232func (c *BugCache) EditComment(target entity.Id, message string) (*bug.EditCommentOperation, error) {
233 author, err := c.repoCache.GetUserIdentity()
234 if err != nil {
235 return nil, err
236 }
237
238 return c.EditCommentRaw(author, time.Now().Unix(), target, message, nil)
239}
240
241func (c *BugCache) EditCommentRaw(author *IdentityCache, unixTime int64, target entity.Id, message string, metadata map[string]string) (*bug.EditCommentOperation, error) {
242 op, err := bug.EditComment(c.bug, author.Identity, unixTime, target, message)
243 if err != nil {
244 return nil, err
245 }
246
247 for key, value := range metadata {
248 op.SetMetadata(key, value)
249 }
250
251 return op, c.notifyUpdated()
252}
253
254func (c *BugCache) SetMetadata(target entity.Id, newMetadata map[string]string) (*bug.SetMetadataOperation, error) {
255 author, err := c.repoCache.GetUserIdentity()
256 if err != nil {
257 return nil, err
258 }
259
260 return c.SetMetadataRaw(author, time.Now().Unix(), target, newMetadata)
261}
262
263func (c *BugCache) SetMetadataRaw(author *IdentityCache, unixTime int64, target entity.Id, newMetadata map[string]string) (*bug.SetMetadataOperation, error) {
264 op, err := bug.SetMetadata(c.bug, author.Identity, unixTime, target, newMetadata)
265 if err != nil {
266 return nil, err
267 }
268
269 return op, c.notifyUpdated()
270}
271
272func (c *BugCache) Commit() error {
273 err := c.bug.Commit(c.repoCache.repo)
274 if err != nil {
275 return err
276 }
277 return c.notifyUpdated()
278}
279
280func (c *BugCache) CommitAsNeeded() error {
281 err := c.bug.CommitAsNeeded(c.repoCache.repo)
282 if err != nil {
283 return err
284 }
285 return c.notifyUpdated()
286}
287
288func (c *BugCache) NeedCommit() bool {
289 return c.bug.NeedCommit()
290}