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