1package cache
2
3import (
4 "fmt"
5 "strings"
6 "time"
7
8 "github.com/MichaelMure/git-bug/identity"
9
10 "github.com/MichaelMure/git-bug/bug"
11 "github.com/MichaelMure/git-bug/util/git"
12)
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() string {
35 return c.bug.Id()
36}
37
38func (c *BugCache) HumanId() string {
39 return c.bug.HumanId()
40}
41
42func (c *BugCache) notifyUpdated() error {
43 return c.repoCache.bugUpdated(c.bug.Id())
44}
45
46var ErrNoMatchingOp = fmt.Errorf("no matching operation found")
47
48type ErrMultipleMatchOp struct {
49 Matching []git.Hash
50}
51
52func (e ErrMultipleMatchOp) Error() string {
53 casted := make([]string, len(e.Matching))
54
55 for i := range e.Matching {
56 casted[i] = string(e.Matching[i])
57 }
58
59 return fmt.Sprintf("Multiple matching operation found:\n%s", strings.Join(casted, "\n"))
60}
61
62// ResolveTargetWithMetadata will find an operation that has the matching metadata
63func (c *BugCache) ResolveTargetWithMetadata(key string, value string) (git.Hash, error) {
64 // preallocate but empty
65 matching := make([]git.Hash, 0, 5)
66
67 it := bug.NewOperationIterator(c.bug)
68 for it.Next() {
69 op := it.Value()
70 opValue, ok := op.GetMetadata(key)
71 if ok && value == opValue {
72 h, err := op.Hash()
73 if err != nil {
74 return "", err
75 }
76 matching = append(matching, h)
77 }
78 }
79
80 if len(matching) == 0 {
81 return "", ErrNoMatchingOp
82 }
83
84 if len(matching) > 1 {
85 return "", ErrMultipleMatchOp{Matching: matching}
86 }
87
88 return matching[0], nil
89}
90
91func (c *BugCache) AddComment(message string) error {
92 return c.AddCommentWithFiles(message, nil)
93}
94
95func (c *BugCache) AddCommentWithFiles(message string, files []git.Hash) error {
96 author, err := identity.GetUserIdentity(c.repoCache.repo)
97 if err != nil {
98 return err
99 }
100
101 return c.AddCommentRaw(author, time.Now().Unix(), message, files, nil)
102}
103
104func (c *BugCache) AddCommentRaw(author *identity.Identity, unixTime int64, message string, files []git.Hash, metadata map[string]string) error {
105 op, err := bug.AddCommentWithFiles(c.bug, author, unixTime, message, files)
106 if err != nil {
107 return err
108 }
109
110 for key, value := range metadata {
111 op.SetMetadata(key, value)
112 }
113
114 return c.notifyUpdated()
115}
116
117func (c *BugCache) ChangeLabels(added []string, removed []string) ([]bug.LabelChangeResult, error) {
118 author, err := identity.GetUserIdentity(c.repoCache.repo)
119 if err != nil {
120 return nil, err
121 }
122
123 return c.ChangeLabelsRaw(author, time.Now().Unix(), added, removed, nil)
124}
125
126func (c *BugCache) ChangeLabelsRaw(author *identity.Identity, unixTime int64, added []string, removed []string, metadata map[string]string) ([]bug.LabelChangeResult, error) {
127 changes, op, err := bug.ChangeLabels(c.bug, author, unixTime, added, removed)
128 if err != nil {
129 return changes, err
130 }
131
132 for key, value := range metadata {
133 op.SetMetadata(key, value)
134 }
135
136 err = c.notifyUpdated()
137 if err != nil {
138 return nil, err
139 }
140
141 return changes, nil
142}
143
144func (c *BugCache) Open() error {
145 author, err := identity.GetUserIdentity(c.repoCache.repo)
146 if err != nil {
147 return err
148 }
149
150 return c.OpenRaw(author, time.Now().Unix(), nil)
151}
152
153func (c *BugCache) OpenRaw(author *identity.Identity, unixTime int64, metadata map[string]string) error {
154 op, err := bug.Open(c.bug, author, unixTime)
155 if err != nil {
156 return err
157 }
158
159 for key, value := range metadata {
160 op.SetMetadata(key, value)
161 }
162
163 return c.notifyUpdated()
164}
165
166func (c *BugCache) Close() error {
167 author, err := identity.GetUserIdentity(c.repoCache.repo)
168 if err != nil {
169 return err
170 }
171
172 return c.CloseRaw(author, time.Now().Unix(), nil)
173}
174
175func (c *BugCache) CloseRaw(author *identity.Identity, unixTime int64, metadata map[string]string) error {
176 op, err := bug.Close(c.bug, author, unixTime)
177 if err != nil {
178 return err
179 }
180
181 for key, value := range metadata {
182 op.SetMetadata(key, value)
183 }
184
185 return c.notifyUpdated()
186}
187
188func (c *BugCache) SetTitle(title string) error {
189 author, err := identity.GetUserIdentity(c.repoCache.repo)
190 if err != nil {
191 return err
192 }
193
194 return c.SetTitleRaw(author, time.Now().Unix(), title, nil)
195}
196
197func (c *BugCache) SetTitleRaw(author *identity.Identity, unixTime int64, title string, metadata map[string]string) error {
198 op, err := bug.SetTitle(c.bug, author, unixTime, title)
199 if err != nil {
200 return err
201 }
202
203 for key, value := range metadata {
204 op.SetMetadata(key, value)
205 }
206
207 return c.notifyUpdated()
208}
209
210func (c *BugCache) EditComment(target git.Hash, message string) error {
211 author, err := identity.GetUserIdentity(c.repoCache.repo)
212 if err != nil {
213 return err
214 }
215
216 return c.EditCommentRaw(author, time.Now().Unix(), target, message, nil)
217}
218
219func (c *BugCache) EditCommentRaw(author *identity.Identity, unixTime int64, target git.Hash, message string, metadata map[string]string) error {
220 op, err := bug.EditComment(c.bug, author, unixTime, target, message)
221 if err != nil {
222 return err
223 }
224
225 for key, value := range metadata {
226 op.SetMetadata(key, value)
227 }
228
229 return c.notifyUpdated()
230}
231
232func (c *BugCache) Commit() error {
233 return c.bug.Commit(c.repoCache.repo)
234}
235
236func (c *BugCache) CommitAsNeeded() error {
237 if c.bug.HasPendingOp() {
238 return c.bug.Commit(c.repoCache.repo)
239 }
240 return nil
241}