1package cache
2
3import (
4 "fmt"
5 "io"
6 "strings"
7
8 "github.com/MichaelMure/git-bug/bug"
9 "github.com/MichaelMure/git-bug/bug/operations"
10 "github.com/MichaelMure/git-bug/repository"
11 "github.com/MichaelMure/git-bug/util"
12)
13
14type RepoCacher interface {
15 Repository() repository.Repo
16 ResolveBug(id string) (BugCacher, error)
17 ResolveBugPrefix(prefix string) (BugCacher, error)
18 AllBugIds() ([]string, error)
19 ClearAllBugs()
20
21 // Mutations
22 NewBug(title string, message string) (BugCacher, error)
23 NewBugWithFiles(title string, message string, files []util.Hash) (BugCacher, error)
24 Fetch(remote string) (string, error)
25 MergeAll(remote string) <-chan bug.MergeResult
26 Pull(remote string, out io.Writer) error
27 Push(remote string) (string, error)
28}
29
30type RepoCache struct {
31 repo repository.Repo
32 bugs map[string]BugCacher
33}
34
35func NewRepoCache(r repository.Repo) RepoCacher {
36 return &RepoCache{
37 repo: r,
38 bugs: make(map[string]BugCacher),
39 }
40}
41
42func (c *RepoCache) Repository() repository.Repo {
43 return c.repo
44}
45
46func (c *RepoCache) ResolveBug(id string) (BugCacher, error) {
47 cached, ok := c.bugs[id]
48 if ok {
49 return cached, nil
50 }
51
52 b, err := bug.ReadLocalBug(c.repo, id)
53 if err != nil {
54 return nil, err
55 }
56
57 cached = NewBugCache(c.repo, b)
58 c.bugs[id] = cached
59
60 return cached, nil
61}
62
63func (c *RepoCache) ResolveBugPrefix(prefix string) (BugCacher, error) {
64 // preallocate but empty
65 matching := make([]string, 0, 5)
66
67 for id := range c.bugs {
68 if strings.HasPrefix(id, prefix) {
69 matching = append(matching, id)
70 }
71 }
72
73 // TODO: should check matching bug in the repo as well
74
75 if len(matching) > 1 {
76 return nil, fmt.Errorf("Multiple matching bug found:\n%s", strings.Join(matching, "\n"))
77 }
78
79 if len(matching) == 1 {
80 b := c.bugs[matching[0]]
81 return b, nil
82 }
83
84 b, err := bug.FindLocalBug(c.repo, prefix)
85
86 if err != nil {
87 return nil, err
88 }
89
90 cached := NewBugCache(c.repo, b)
91 c.bugs[b.Id()] = cached
92
93 return cached, nil
94}
95
96func (c *RepoCache) AllBugIds() ([]string, error) {
97 return bug.ListLocalIds(c.repo)
98}
99
100func (c *RepoCache) ClearAllBugs() {
101 c.bugs = make(map[string]BugCacher)
102}
103
104func (c *RepoCache) NewBug(title string, message string) (BugCacher, error) {
105 return c.NewBugWithFiles(title, message, nil)
106}
107
108func (c *RepoCache) NewBugWithFiles(title string, message string, files []util.Hash) (BugCacher, error) {
109 author, err := bug.GetUser(c.repo)
110 if err != nil {
111 return nil, err
112 }
113
114 b, err := operations.CreateWithFiles(author, title, message, files)
115 if err != nil {
116 return nil, err
117 }
118
119 err = b.Commit(c.repo)
120 if err != nil {
121 return nil, err
122 }
123
124 cached := NewBugCache(c.repo, b)
125 c.bugs[b.Id()] = cached
126
127 return cached, nil
128}
129
130func (c *RepoCache) Fetch(remote string) (string, error) {
131 return bug.Fetch(c.repo, remote)
132}
133
134func (c *RepoCache) MergeAll(remote string) <-chan bug.MergeResult {
135 return bug.MergeAll(c.repo, remote)
136}
137
138func (c *RepoCache) Pull(remote string, out io.Writer) error {
139 return bug.Pull(c.repo, out, remote)
140}
141
142func (c *RepoCache) Push(remote string) (string, error) {
143 return bug.Push(c.repo, remote)
144}