cache.go

  1package cache
  2
  3import (
  4	"fmt"
  5	"strings"
  6
  7	"github.com/MichaelMure/git-bug/bug"
  8	"github.com/MichaelMure/git-bug/repository"
  9)
 10
 11type Cache interface {
 12	RegisterRepository(ref string, repo repository.Repo)
 13	RegisterDefaultRepository(repo repository.Repo)
 14	ResolveRepo(ref string) (CachedRepo, error)
 15	DefaultRepo() (CachedRepo, error)
 16}
 17
 18type CachedRepo interface {
 19	ResolveBug(id string) (CachedBug, error)
 20	ResolveBugPrefix(prefix string) (CachedBug, error)
 21	ClearAllBugs()
 22}
 23
 24type CachedBug interface {
 25	Snapshot() bug.Snapshot
 26	ClearSnapshot()
 27}
 28
 29// Cache ------------------------
 30
 31type DefaultCache struct {
 32	repos map[string]CachedRepo
 33}
 34
 35func NewDefaultCache() Cache {
 36	return &DefaultCache{
 37		repos: make(map[string]CachedRepo),
 38	}
 39}
 40
 41func (c *DefaultCache) RegisterRepository(ref string, repo repository.Repo) {
 42	c.repos[ref] = NewCachedRepo(repo)
 43}
 44
 45func (c *DefaultCache) RegisterDefaultRepository(repo repository.Repo) {
 46	c.repos[""] = NewCachedRepo(repo)
 47}
 48
 49func (c *DefaultCache) DefaultRepo() (CachedRepo, error) {
 50	if len(c.repos) != 1 {
 51		return nil, fmt.Errorf("repository is not unique")
 52	}
 53
 54	for _, r := range c.repos {
 55		return r, nil
 56	}
 57
 58	panic("unreachable")
 59}
 60
 61func (c *DefaultCache) ResolveRepo(ref string) (CachedRepo, error) {
 62	r, ok := c.repos[ref]
 63	if !ok {
 64		return nil, fmt.Errorf("unknown repo")
 65	}
 66	return r, nil
 67}
 68
 69// Repo ------------------------
 70
 71type CachedRepoImpl struct {
 72	repo repository.Repo
 73	bugs map[string]CachedBug
 74}
 75
 76func NewCachedRepo(r repository.Repo) CachedRepo {
 77	return &CachedRepoImpl{
 78		repo: r,
 79		bugs: make(map[string]CachedBug),
 80	}
 81}
 82
 83func (c CachedRepoImpl) ResolveBug(id string) (CachedBug, error) {
 84	cached, ok := c.bugs[id]
 85	if ok {
 86		return cached, nil
 87	}
 88
 89	b, err := bug.ReadLocalBug(c.repo, id)
 90	if err != nil {
 91		return nil, err
 92	}
 93
 94	cached = NewCachedBug(b)
 95	c.bugs[id] = cached
 96
 97	return cached, nil
 98}
 99
100func (c CachedRepoImpl) ResolveBugPrefix(prefix string) (CachedBug, error) {
101	// preallocate but empty
102	matching := make([]string, 0, 5)
103
104	for id := range c.bugs {
105		if strings.HasPrefix(id, prefix) {
106			matching = append(matching, id)
107		}
108	}
109
110	// TODO: should check matching bug in the repo as well
111
112	if len(matching) > 1 {
113		return nil, fmt.Errorf("Multiple matching bug found:\n%s", strings.Join(matching, "\n"))
114	}
115
116	if len(matching) == 1 {
117		b := c.bugs[matching[0]]
118		return b, nil
119	}
120
121	b, err := bug.FindLocalBug(c.repo, prefix)
122
123	if err != nil {
124		return nil, err
125	}
126
127	cached := NewCachedBug(b)
128	c.bugs[b.Id()] = cached
129
130	return cached, nil
131}
132
133func (c CachedRepoImpl) ClearAllBugs() {
134	c.bugs = make(map[string]CachedBug)
135}
136
137// Bug ------------------------
138
139type CachedBugImpl struct {
140	bug  *bug.Bug
141	snap *bug.Snapshot
142}
143
144func NewCachedBug(b *bug.Bug) CachedBug {
145	return &CachedBugImpl{
146		bug: b,
147	}
148}
149
150func (c CachedBugImpl) Snapshot() bug.Snapshot {
151	if c.snap == nil {
152		snap := c.bug.Compile()
153		c.snap = &snap
154	}
155	return *c.snap
156}
157
158func (c CachedBugImpl) ClearSnapshot() {
159	c.snap = nil
160}