aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2019-02-18 14:11:37 +0100
committerMichael Muré <batolettre@gmail.com>2019-03-01 22:40:26 +0100
commit947ea63522610bd16c32cf70812c129eda9bbb02 (patch)
tree76542e4a5ab488dc45477d33c3f4e94b0eb36975
parent976af3a4e8382d03e9f2ccb57e2ed3b783294138 (diff)
downloadgit-bug-947ea63522610bd16c32cf70812c129eda9bbb02.tar.gz
identity: wip caching
-rw-r--r--cache/bug_cache.go12
-rw-r--r--cache/bug_excerpt.go20
-rw-r--r--cache/identity_cache.go6
-rw-r--r--cache/identity_excerpt.go48
-rw-r--r--cache/repo_cache.go88
5 files changed, 133 insertions, 41 deletions
diff --git a/cache/bug_cache.go b/cache/bug_cache.go
index ce46837a..53a96275 100644
--- a/cache/bug_cache.go
+++ b/cache/bug_cache.go
@@ -228,9 +228,17 @@ func (c *BugCache) EditCommentRaw(author *IdentityCache, unixTime int64, target
}
func (c *BugCache) Commit() error {
- return c.bug.Commit(c.repoCache.repo)
+ err := c.bug.Commit(c.repoCache.repo)
+ if err != nil {
+ return err
+ }
+ return c.notifyUpdated()
}
func (c *BugCache) CommitAsNeeded() error {
- return c.bug.CommitAsNeeded(c.repoCache.repo)
+ err := c.bug.CommitAsNeeded(c.repoCache.repo)
+ if err != nil {
+ return err
+ }
+ return c.notifyUpdated()
}
diff --git a/cache/bug_excerpt.go b/cache/bug_excerpt.go
index daf89c4f..d3645322 100644
--- a/cache/bug_excerpt.go
+++ b/cache/bug_excerpt.go
@@ -17,18 +17,13 @@ type BugExcerpt struct {
CreateUnixTime int64
EditUnixTime int64
- Status bug.Status
- Author AuthorExcerpt
- Labels []bug.Label
+ Status bug.Status
+ AuthorId string
+ Labels []bug.Label
CreateMetadata map[string]string
}
-type AuthorExcerpt struct {
- Name string
- Login string
-}
-
func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
return &BugExcerpt{
Id: b.Id(),
@@ -37,12 +32,9 @@ func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
CreateUnixTime: b.FirstOp().GetUnixTime(),
EditUnixTime: snap.LastEditUnix(),
Status: snap.Status,
- Author: AuthorExcerpt{
- Login: snap.Author.Login(),
- Name: snap.Author.Name(),
- },
- Labels: snap.Labels,
- CreateMetadata: b.FirstOp().AllMetadata(),
+ AuthorId: snap.Author.Id(),
+ Labels: snap.Labels,
+ CreateMetadata: b.FirstOp().AllMetadata(),
}
}
diff --git a/cache/identity_cache.go b/cache/identity_cache.go
index 93b2dc4b..c49e9519 100644
--- a/cache/identity_cache.go
+++ b/cache/identity_cache.go
@@ -4,7 +4,7 @@ import (
"github.com/MichaelMure/git-bug/identity"
)
-// IdentityCache is a wrapper around an Identity. It provide multiple functions:
+// IdentityCache is a wrapper around an Identity for caching.
type IdentityCache struct {
*identity.Identity
repoCache *RepoCache
@@ -17,6 +17,10 @@ func NewIdentityCache(repoCache *RepoCache, id *identity.Identity) *IdentityCach
}
}
+func (i *IdentityCache) notifyUpdated() error {
+ return i.repoCache.identityUpdated(i.Identity.Id())
+}
+
func (i *IdentityCache) Commit() error {
return i.Identity.Commit(i.repoCache.repo)
}
diff --git a/cache/identity_excerpt.go b/cache/identity_excerpt.go
new file mode 100644
index 00000000..7bc660b6
--- /dev/null
+++ b/cache/identity_excerpt.go
@@ -0,0 +1,48 @@
+package cache
+
+import (
+ "encoding/gob"
+
+ "github.com/MichaelMure/git-bug/identity"
+)
+
+// IdentityExcerpt hold a subset of the identity values to be able to sort and
+// filter identities efficiently without having to read and compile each raw
+// identity.
+type IdentityExcerpt struct {
+ Id string
+
+ Name string
+ Login string
+}
+
+func NewIdentityExcerpt(i *identity.Identity) *IdentityExcerpt {
+ return &IdentityExcerpt{
+ Id: i.Id(),
+ Name: i.Name(),
+ Login: i.Login(),
+ }
+}
+
+// Package initialisation used to register the type for (de)serialization
+func init() {
+ gob.Register(IdentityExcerpt{})
+}
+
+/*
+ * Sorting
+ */
+
+type IdentityById []*IdentityExcerpt
+
+func (b IdentityById) Len() int {
+ return len(b)
+}
+
+func (b IdentityById) Less(i, j int) bool {
+ return b[i].Id < b[j].Id
+}
+
+func (b IdentityById) Swap(i, j int) {
+ b[i], b[j] = b[j], b[i]
+}
diff --git a/cache/repo_cache.go b/cache/repo_cache.go
index f64a1b76..cec6f8b5 100644
--- a/cache/repo_cache.go
+++ b/cache/repo_cache.go
@@ -20,8 +20,12 @@ import (
"github.com/MichaelMure/git-bug/util/process"
)
-const cacheFile = "cache"
-const formatVersion = 1
+const bugCacheFile = "bug-cache"
+const identityCacheFile = "identity-cache"
+
+// 1: original format
+// 2: added cache for identities with a reference in the bug cache
+const formatVersion = 2
// RepoCache is a cache for a Repository. This cache has multiple functions:
//
@@ -40,12 +44,17 @@ const formatVersion = 1
type RepoCache struct {
// the underlying repo
repo repository.ClockedRepo
+
// excerpt of bugs data for all bugs
- excerpts map[string]*BugExcerpt
+ bugExcerpts map[string]*BugExcerpt
// bug loaded in memory
bugs map[string]*BugCache
+
+ // excerpt of identities data for all identities
+ identitiesExcerpts map[string]*IdentityExcerpt
// identities loaded in memory
identities map[string]*IdentityCache
+
// the user identity's id, if known
userIdentityId string
}
@@ -145,14 +154,27 @@ func (c *RepoCache) bugUpdated(id string) error {
panic("missing bug in the cache")
}
- c.excerpts[id] = NewBugExcerpt(b.bug, b.Snapshot())
+ c.bugExcerpts[id] = NewBugExcerpt(b.bug, b.Snapshot())
+
+ return c.write()
+}
+
+// identityUpdated is a callback to trigger when the excerpt of an identity
+// changed, that is each time an identity is updated
+func (c *RepoCache) identityUpdated(id string) error {
+ i, ok := c.identities[id]
+ if !ok {
+ panic("missing identity in the cache")
+ }
+
+ c.identitiesExcerpts[id] = NewIdentityExcerpt(i.Identity)
return c.write()
}
// load will try to read from the disk the bug cache file
func (c *RepoCache) load() error {
- f, err := os.Open(cacheFilePath(c.repo))
+ f, err := os.Open(bugCacheFilePath(c.repo))
if err != nil {
return err
}
@@ -173,7 +195,7 @@ func (c *RepoCache) load() error {
return fmt.Errorf("unknown cache format version %v", aux.Version)
}
- c.excerpts = aux.Excerpts
+ c.bugExcerpts = aux.Excerpts
return nil
}
@@ -186,7 +208,7 @@ func (c *RepoCache) write() error {
Excerpts map[string]*BugExcerpt
}{
Version: formatVersion,
- Excerpts: c.excerpts,
+ Excerpts: c.bugExcerpts,
}
encoder := gob.NewEncoder(&data)
@@ -196,7 +218,7 @@ func (c *RepoCache) write() error {
return err
}
- f, err := os.Create(cacheFilePath(c.repo))
+ f, err := os.Create(bugCacheFilePath(c.repo))
if err != nil {
return err
}
@@ -209,14 +231,18 @@ func (c *RepoCache) write() error {
return f.Close()
}
-func cacheFilePath(repo repository.Repo) string {
- return path.Join(repo.GetPath(), ".git", "git-bug", cacheFile)
+func bugCacheFilePath(repo repository.Repo) string {
+ return path.Join(repo.GetPath(), ".git", "git-bug", bugCacheFile)
+}
+
+func identityCacheFilePath(repo repository.Repo) string {
+ return path.Join(repo.GetPath(), ".git", "git-bug", bugCacheFile)
}
func (c *RepoCache) buildCache() error {
_, _ = fmt.Fprintf(os.Stderr, "Building bug cache... ")
- c.excerpts = make(map[string]*BugExcerpt)
+ c.bugExcerpts = make(map[string]*BugExcerpt)
allBugs := bug.ReadAllLocalBugs(c.repo)
@@ -226,7 +252,7 @@ func (c *RepoCache) buildCache() error {
}
snap := b.Bug.Compile()
- c.excerpts[b.Bug.Id()] = NewBugExcerpt(b.Bug, &snap)
+ c.bugExcerpts[b.Bug.Id()] = NewBugExcerpt(b.Bug, &snap)
}
_, _ = fmt.Fprintln(os.Stderr, "Done.")
@@ -257,7 +283,7 @@ func (c *RepoCache) ResolveBugPrefix(prefix string) (*BugCache, error) {
// preallocate but empty
matching := make([]string, 0, 5)
- for id := range c.excerpts {
+ for id := range c.bugExcerpts {
if strings.HasPrefix(id, prefix) {
matching = append(matching, id)
}
@@ -281,7 +307,7 @@ func (c *RepoCache) ResolveBugCreateMetadata(key string, value string) (*BugCach
// preallocate but empty
matching := make([]string, 0, 5)
- for id, excerpt := range c.excerpts {
+ for id, excerpt := range c.bugExcerpts {
if excerpt.CreateMetadata[key] == value {
matching = append(matching, id)
}
@@ -306,7 +332,7 @@ func (c *RepoCache) QueryBugs(query *Query) []string {
var filtered []*BugExcerpt
- for _, excerpt := range c.excerpts {
+ for _, excerpt := range c.bugExcerpts {
if query.Match(excerpt) {
filtered = append(filtered, excerpt)
}
@@ -342,10 +368,10 @@ func (c *RepoCache) QueryBugs(query *Query) []string {
// AllBugsIds return all known bug ids
func (c *RepoCache) AllBugsIds() []string {
- result := make([]string, len(c.excerpts))
+ result := make([]string, len(c.bugExcerpts))
i := 0
- for _, excerpt := range c.excerpts {
+ for _, excerpt := range c.bugExcerpts {
result[i] = excerpt.Id
i++
}
@@ -353,11 +379,6 @@ func (c *RepoCache) AllBugsIds() []string {
return result
}
-// ClearAllBugs clear all bugs kept in memory
-func (c *RepoCache) ClearAllBugs() {
- c.bugs = make(map[string]*BugCache)
-}
-
// ValidLabels list valid labels
//
// Note: in the future, a proper label policy could be implemented where valid
@@ -366,7 +387,7 @@ func (c *RepoCache) ClearAllBugs() {
func (c *RepoCache) ValidLabels() []bug.Label {
set := map[bug.Label]interface{}{}
- for _, excerpt := range c.excerpts {
+ for _, excerpt := range c.bugExcerpts {
for _, l := range excerpt.Labels {
set[l] = nil
}
@@ -467,7 +488,7 @@ func (c *RepoCache) MergeAll(remote string) <-chan bug.MergeResult {
case bug.MergeStatusNew, bug.MergeStatusUpdated:
b := result.Bug
snap := b.Compile()
- c.excerpts[id] = NewBugExcerpt(b, &snap)
+ c.bugExcerpts[id] = NewBugExcerpt(b, &snap)
}
}
@@ -615,6 +636,19 @@ func (c *RepoCache) ResolveIdentityImmutableMetadata(key string, value string) (
return c.ResolveIdentity(matching[0])
}
+// AllIdentityIds return all known identity ids
+func (c *RepoCache) AllIdentityIds() []string {
+ result := make([]string, len(c.identitiesExcerpts))
+
+ i := 0
+ for _, excerpt := range c.identitiesExcerpts {
+ result[i] = excerpt.Id
+ i++
+ }
+
+ return result
+}
+
func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
err := identity.SetUserIdentity(c.repo, i.Identity)
if err != nil {
@@ -677,5 +711,11 @@ func (c *RepoCache) NewIdentityRaw(name string, email string, login string, avat
cached := NewIdentityCache(c, i)
c.identities[i.Id()] = cached
+ // force the write of the excerpt
+ err = c.identityUpdated(i.Id())
+ if err != nil {
+ return nil, err
+ }
+
return cached, nil
}