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