bug_cache.go

  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.GetIdentity(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.GetIdentity(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.GetIdentity(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.GetIdentity(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.GetIdentity(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.GetIdentity(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}