aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cache/bug_cache.go6
-rw-r--r--cache/bug_subcache.go96
-rw-r--r--cache/cached.go5
-rw-r--r--cache/identity_cache.go10
-rw-r--r--cache/identity_subcache.go33
-rw-r--r--cache/repo_cache.go86
-rw-r--r--cache/repo_cache_common.go64
-rw-r--r--cache/subcache.go80
-rw-r--r--commands/execenv/env.go21
-rw-r--r--entity/resolver.go8
10 files changed, 204 insertions, 205 deletions
diff --git a/cache/bug_cache.go b/cache/bug_cache.go
index 0fd52ff1..7b3fa114 100644
--- a/cache/bug_cache.go
+++ b/cache/bug_cache.go
@@ -22,12 +22,12 @@ type BugCache struct {
CachedEntityBase[*bug.Snapshot, bug.Operation]
}
-func NewBugCache(subcache *RepoCacheBug, getUserIdentity func() (identity.Interface, error), b *bug.Bug) *BugCache {
+func NewBugCache(b *bug.Bug, repo repository.ClockedRepo, getUserIdentity getUserIdentityFunc, entityUpdated func(id entity.Id) error) *BugCache {
return &BugCache{
CachedEntityBase: CachedEntityBase[*bug.Snapshot, bug.Operation]{
- entityUpdated: subcache.entityUpdated,
+ repo: repo,
+ entityUpdated: entityUpdated,
getUserIdentity: getUserIdentity,
- repo: subcache.repo,
entity: &bug.WithSnapshot{Bug: b},
},
}
diff --git a/cache/bug_subcache.go b/cache/bug_subcache.go
index c8901754..f0a8889b 100644
--- a/cache/bug_subcache.go
+++ b/cache/bug_subcache.go
@@ -2,13 +2,8 @@ package cache
import (
"errors"
- "fmt"
"sort"
- "strings"
"time"
- "unicode/utf8"
-
- "github.com/blevesearch/bleve"
"github.com/MichaelMure/git-bug/entities/bug"
"github.com/MichaelMure/git-bug/entities/identity"
@@ -18,7 +13,39 @@ import (
)
type RepoCacheBug struct {
- *SubCache[*BugExcerpt, *BugCache, bug.Interface]
+ *SubCache[*bug.Bug, *BugExcerpt, *BugCache]
+}
+
+func NewRepoCacheBug(repo repository.ClockedRepo,
+ resolvers func() entity.Resolvers,
+ getUserIdentity getUserIdentityFunc) *RepoCacheBug {
+
+ makeCached := func(b *bug.Bug, entityUpdated func(id entity.Id) error) *BugCache {
+ return NewBugCache(b, repo, getUserIdentity, entityUpdated)
+ }
+
+ makeExcerpt := func(b *bug.Bug) *BugExcerpt {
+ return NewBugExcerpt(b, b.Compile())
+ }
+
+ makeIndex := func(b *BugCache) []string {
+ snap := b.Snapshot()
+ var res []string
+ for _, comment := range snap.Comments {
+ res = append(res, comment.Message)
+ }
+ res = append(res, snap.Title)
+ return res
+ }
+
+ sc := NewSubCache[*bug.Bug, *BugExcerpt, *BugCache](
+ repo, resolvers, getUserIdentity,
+ makeCached, makeExcerpt, makeIndex,
+ "bug", "bugs",
+ formatVersion, defaultMaxLoadedBugs,
+ )
+
+ return &RepoCacheBug{SubCache: sc}
}
// ResolveBugCreateMetadata retrieve a bug that has the exact given metadata on
@@ -94,29 +121,19 @@ func (c *RepoCacheBug) QueryBugs(q *query.Query) ([]entity.Id, error) {
if q.Search != nil {
foundBySearch = map[entity.Id]*BugExcerpt{}
- terms := make([]string, len(q.Search))
- copy(terms, q.Search)
- for i, search := range q.Search {
- if strings.Contains(search, " ") {
- terms[i] = fmt.Sprintf("\"%s\"", search)
- }
- }
-
- bleveQuery := bleve.NewQueryStringQuery(strings.Join(terms, " "))
- bleveSearch := bleve.NewSearchRequest(bleveQuery)
-
- index, err := c.repo.GetBleveIndex("bug")
+ index, err := c.repo.GetIndex("bug")
if err != nil {
return nil, err
}
- searchResults, err := index.Search(bleveSearch)
+ res, err := index.Search(q.Search)
if err != nil {
return nil, err
}
- for _, hit := range searchResults.Hits {
- foundBySearch[entity.Id(hit.ID)] = c.excerpts[entity.Id(hit.ID)]
+ for _, hit := range res {
+ id := entity.Id(hit)
+ foundBySearch[id] = c.excerpts[id]
}
} else {
foundBySearch = c.excerpts
@@ -232,40 +249,3 @@ func (c *RepoCacheBug) NewRaw(author identity.Interface, unixTime int64, title s
return cached, op, nil
}
-
-func (c *RepoCacheBug) addBugToSearchIndex(snap *bug.Snapshot) error {
- searchableBug := struct {
- Text []string
- }{}
-
- // See https://github.com/blevesearch/bleve/issues/1576
- var sb strings.Builder
- normalize := func(text string) string {
- sb.Reset()
- for _, field := range strings.Fields(text) {
- if utf8.RuneCountInString(field) < 100 {
- sb.WriteString(field)
- sb.WriteRune(' ')
- }
- }
- return sb.String()
- }
-
- for _, comment := range snap.Comments {
- searchableBug.Text = append(searchableBug.Text, normalize(comment.Message))
- }
-
- searchableBug.Text = append(searchableBug.Text, normalize(snap.Title))
-
- index, err := c.repo.GetBleveIndex("bug")
- if err != nil {
- return err
- }
-
- err = index.Index(snap.Id().String(), searchableBug)
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/cache/cached.go b/cache/cached.go
index 75ca58e5..74757356 100644
--- a/cache/cached.go
+++ b/cache/cached.go
@@ -4,7 +4,6 @@ import (
"sync"
"github.com/MichaelMure/git-bug/entities/bug"
- "github.com/MichaelMure/git-bug/entities/identity"
"github.com/MichaelMure/git-bug/entity"
"github.com/MichaelMure/git-bug/entity/dag"
"github.com/MichaelMure/git-bug/repository"
@@ -57,9 +56,9 @@ import (
// }
type CachedEntityBase[SnapT dag.Snapshot, OpT dag.Operation] struct {
- entityUpdated func(id entity.Id) error
- getUserIdentity func() (identity.Interface, error)
repo repository.ClockedRepo
+ entityUpdated func(id entity.Id) error
+ getUserIdentity getUserIdentityFunc
mu sync.RWMutex
entity dag.Interface[SnapT, OpT]
diff --git a/cache/identity_cache.go b/cache/identity_cache.go
index a6c929ad..00f5ae95 100644
--- a/cache/identity_cache.go
+++ b/cache/identity_cache.go
@@ -10,17 +10,17 @@ var _ identity.Interface = &IdentityCache{}
// IdentityCache is a wrapper around an Identity for caching.
type IdentityCache struct {
- entityUpdated func(id entity.Id) error
repo repository.ClockedRepo
+ entityUpdated func(id entity.Id) error
*identity.Identity
}
-func NewIdentityCache(subcache *RepoCacheIdentity, id *identity.Identity) *IdentityCache {
+func NewIdentityCache(i *identity.Identity, repo repository.ClockedRepo, entityUpdated func(id entity.Id) error) *IdentityCache {
return &IdentityCache{
- entityUpdated: subcache.entityUpdated,
- repo: subcache.repo,
- Identity: id,
+ repo: repo,
+ entityUpdated: entityUpdated,
+ Identity: i,
}
}
diff --git a/cache/identity_subcache.go b/cache/identity_subcache.go
index a3b5a0f8..b175d731 100644
--- a/cache/identity_subcache.go
+++ b/cache/identity_subcache.go
@@ -4,10 +4,39 @@ import (
"fmt"
"github.com/MichaelMure/git-bug/entities/identity"
+ "github.com/MichaelMure/git-bug/entity"
+ "github.com/MichaelMure/git-bug/repository"
)
type RepoCacheIdentity struct {
- SubCache[*IdentityExcerpt, *IdentityCache, identity.Interface]
+ *SubCache[*identity.Identity, *IdentityExcerpt, *IdentityCache]
+}
+
+func NewRepoCacheIdentity(repo repository.ClockedRepo,
+ resolvers func() entity.Resolvers,
+ getUserIdentity getUserIdentityFunc) *RepoCacheIdentity {
+
+ makeCached := func(i *identity.Identity, entityUpdated func(id entity.Id) error) *IdentityCache {
+ return NewIdentityCache(i, repo, entityUpdated)
+ }
+
+ makeExcerpt := func(i *identity.Identity) *IdentityExcerpt {
+ return NewIdentityExcerpt(i)
+ }
+
+ makeIndex := func(i *IdentityCache) []string {
+ // no indexing
+ return nil
+ }
+
+ sc := NewSubCache[*identity.Identity, *IdentityExcerpt, *IdentityCache](
+ repo, resolvers, getUserIdentity,
+ makeCached, makeExcerpt, makeIndex,
+ "identity", "identities",
+ formatVersion, defaultMaxLoadedBugs,
+ )
+
+ return &RepoCacheIdentity{SubCache: sc}
}
// ResolveIdentityImmutableMetadata retrieve an Identity that has the exact given metadata on
@@ -65,7 +94,7 @@ func (c *RepoCacheIdentity) finishIdentity(i *identity.Identity, metadata map[st
return nil, fmt.Errorf("identity %s already exist in the cache", i.Id())
}
- cached := NewIdentityCache(c, i)
+ cached := NewIdentityCache(i, c.repo, c.entityUpdated)
c.cached[i.Id()] = cached
c.mu.Unlock()
diff --git a/cache/repo_cache.go b/cache/repo_cache.go
index 982804b5..b2facac3 100644
--- a/cache/repo_cache.go
+++ b/cache/repo_cache.go
@@ -8,8 +8,6 @@ import (
"strconv"
"sync"
- "github.com/MichaelMure/git-bug/entities/bug"
- "github.com/MichaelMure/git-bug/entities/identity"
"github.com/MichaelMure/git-bug/entity"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/util/multierr"
@@ -67,6 +65,7 @@ type RepoCache struct {
subcaches []cacheMgmt
// the user identity's id, if known
+ muUserIdentity sync.RWMutex
userIdentityId entity.Id
}
@@ -80,17 +79,15 @@ func NewNamedRepoCache(r repository.ClockedRepo, name string) (*RepoCache, chan
name: name,
}
- bugs := NewSubCache[*BugExcerpt, *BugCache, bug.Interface](r,
- c.getResolvers, c.GetUserIdentity,
- "bug", "bugs",
- formatVersion, defaultMaxLoadedBugs)
+ c.identities = NewRepoCacheIdentity(r, c.getResolvers, c.GetUserIdentity)
+ c.subcaches = append(c.subcaches, c.identities)
- c.subcaches = append(c.subcaches, bugs)
- c.bugs = &RepoCacheBug{SubCache: *bugs}
+ c.bugs = NewRepoCacheBug(r, c.getResolvers, c.GetUserIdentity)
+ c.subcaches = append(c.subcaches, c.bugs)
c.resolvers = entity.Resolvers{
- &IdentityCache{}: entity.ResolverFunc((func(id entity.Id) (entity.Interface, error)(c.identities.Resolve)),
- &BugCache{}: c.bugs,
+ &IdentityCache{}: entity.ResolverFunc[*IdentityCache](c.identities.Resolve),
+ &BugCache{}: entity.ResolverFunc[*BugCache](c.bugs.Resolve),
}
err := c.lock()
@@ -104,12 +101,9 @@ func NewNamedRepoCache(r repository.ClockedRepo, name string) (*RepoCache, chan
}
// Cache is either missing, broken or outdated. Rebuilding.
- err = c.buildCache()
- if err != nil {
- return nil, err
- }
+ events := c.buildCache()
- return c, c.write()
+ return c, events, nil
}
// Bugs gives access to the Bug entities
@@ -198,8 +192,8 @@ const (
type BuildEvent struct {
Typename string
- Event BuildEventType
- Err error
+ Event BuildEventType
+ Err error
}
func (c *RepoCache) buildCache() chan BuildEvent {
@@ -222,14 +216,23 @@ func (c *RepoCache) buildCache() chan BuildEvent {
if err != nil {
out <- BuildEvent{
Typename: subcache.Typename(),
- Err: err,
+ Err: err,
+ }
+ return
+ }
+
+ err = subcache.Write()
+ if err != nil {
+ out <- BuildEvent{
+ Typename: subcache.Typename(),
+ Err: err,
}
return
}
out <- BuildEvent{
Typename: subcache.Typename(),
- Event: BuildEventFinished,
+ Event: BuildEventFinished,
}
}(subcache)
}
@@ -237,51 +240,6 @@ func (c *RepoCache) buildCache() chan BuildEvent {
}()
return out
-
- _, _ = fmt.Fprintf(os.Stderr, "Building identity cache... ")
-
- c.identitiesExcerpts = make(map[entity.Id]*IdentityExcerpt)
-
- allIdentities := identity.ReadAllLocal(c.repo)
-
- for i := range allIdentities {
- if i.Err != nil {
- return i.Err
- }
-
- c.identitiesExcerpts[i.Identity.Id()] = NewIdentityExcerpt(i.Identity)
- }
-
- _, _ = fmt.Fprintln(os.Stderr, "Done.")
-
- _, _ = fmt.Fprintf(os.Stderr, "Building bug cache... ")
-
- c.bugExcerpts = make(map[entity.Id]*BugExcerpt)
-
- allBugs := bug.ReadAllWithResolver(c.repo, c.resolvers)
-
- // wipe the index just to be sure
- err := c.repo.ClearBleveIndex("bug")
- if err != nil {
- return err
- }
-
- for b := range allBugs {
- if b.Err != nil {
- return b.Err
- }
-
- snap := b.Bug.Compile()
- c.bugExcerpts[b.Bug.Id()] = NewBugExcerpt(b.Bug, snap)
-
- if err := c.addBugToSearchIndex(snap); err != nil {
- return err
- }
- }
-
- _, _ = fmt.Fprintln(os.Stderr, "Done.")
-
- return nil
}
// repoIsAvailable check is the given repository is locked by a Cache.
diff --git a/cache/repo_cache_common.go b/cache/repo_cache_common.go
index 18ba52f3..1aed04b2 100644
--- a/cache/repo_cache_common.go
+++ b/cache/repo_cache_common.go
@@ -1,8 +1,6 @@
package cache
import (
- "fmt"
-
"github.com/go-git/go-billy/v5"
"github.com/pkg/errors"
@@ -186,64 +184,64 @@ func (c *RepoCache) Pull(remote string) error {
}
func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
- err := identity.SetUserIdentity(c.repo, i.Identity)
- if err != nil {
- return err
- }
-
- c.muIdentity.RLock()
- defer c.muIdentity.RUnlock()
+ c.muUserIdentity.RLock()
+ defer c.muUserIdentity.RUnlock()
// Make sure that everything is fine
- if _, ok := c.identities[i.Id()]; !ok {
+ if _, err := c.identities.Resolve(i.Id()); err != nil {
panic("SetUserIdentity while the identity is not from the cache, something is wrong")
}
+ err := identity.SetUserIdentity(c.repo, i.Identity)
+ if err != nil {
+ return err
+ }
+
c.userIdentityId = i.Id()
return nil
}
func (c *RepoCache) GetUserIdentity() (*IdentityCache, error) {
+ c.muUserIdentity.RLock()
if c.userIdentityId != "" {
- i, ok := c.identities[c.userIdentityId]
- if ok {
- return i, nil
- }
+ defer c.muUserIdentity.RUnlock()
+ return c.identities.Resolve(c.userIdentityId)
}
+ c.muUserIdentity.RUnlock()
- c.muIdentity.Lock()
- defer c.muIdentity.Unlock()
+ c.muUserIdentity.Lock()
+ defer c.muUserIdentity.Unlock()
- i, err := identity.GetUserIdentity(c.repo)
+ i, err := identity.GetUserIdentityId(c.repo)
if err != nil {
return nil, err
}
- cached := NewIdentityCache(c, i)
- c.identities[i.Id()] = cached
- c.userIdentityId = i.Id()
+ c.userIdentityId = i
- return cached, nil
+ return c.identities.Resolve(i)
}
func (c *RepoCache) GetUserIdentityExcerpt() (*IdentityExcerpt, error) {
- if c.userIdentityId == "" {
- id, err := identity.GetUserIdentityId(c.repo)
- if err != nil {
- return nil, err
- }
- c.userIdentityId = id
+ c.muUserIdentity.RLock()
+ if c.userIdentityId != "" {
+ defer c.muUserIdentity.RUnlock()
+ return c.identities.ResolveExcerpt(c.userIdentityId)
}
+ c.muUserIdentity.RUnlock()
- c.muIdentity.RLock()
- defer c.muIdentity.RUnlock()
+ c.muUserIdentity.Lock()
+ defer c.muUserIdentity.Unlock()
- excerpt, ok := c.identitiesExcerpts[c.userIdentityId]
- if !ok {
- return nil, fmt.Errorf("cache: missing identity excerpt %v", c.userIdentityId)
+ i, err := identity.GetUserIdentityId(c.repo)
+ if err != nil {
+ return nil, err
}
- return excerpt, nil
+
+ c.userIdentityId = i
+
+ return c.identities.ResolveExcerpt(i)
}
func (c *RepoCache) IsUserIdentitySet() (bool, error) {
diff --git a/cache/subcache.go b/cache/subcache.go
index 285d4fe7..1737da43 100644
--- a/cache/subcache.go
+++ b/cache/subcache.go
@@ -19,20 +19,21 @@ type Excerpt interface {
}
type CacheEntity interface {
+ Id() entity.Id
NeedCommit() bool
}
type getUserIdentityFunc func() (*IdentityCache, error)
-type SubCache[ExcerptT Excerpt, CacheT CacheEntity, EntityT entity.Interface] struct {
+type SubCache[EntityT entity.Interface, ExcerptT Excerpt, CacheT CacheEntity] struct {
repo repository.ClockedRepo
resolvers func() entity.Resolvers
getUserIdentity getUserIdentityFunc
readWithResolver func(repository.ClockedRepo, entity.Resolvers, entity.Id) (EntityT, error)
- makeCached func(*SubCache[ExcerptT, CacheT, EntityT], getUserIdentityFunc, EntityT) CacheT
- makeExcerpt func() Excerpt
- indexingCallback func(CacheT) error
+ makeCached func(entity EntityT, entityUpdated func(id entity.Id) error) CacheT
+ makeExcerpt func(EntityT) ExcerptT
+ makeIndex func(CacheT) []string
typename string
namespace string
@@ -45,13 +46,15 @@ type SubCache[ExcerptT Excerpt, CacheT CacheEntity, EntityT entity.Interface] st
lru *lruIdCache
}
-func NewSubCache[ExcerptT Excerpt, CacheT CacheEntity, EntityT entity.Interface](
+func NewSubCache[EntityT entity.Interface, ExcerptT Excerpt, CacheT CacheEntity](
repo repository.ClockedRepo,
- resolvers func() entity.Resolvers,
- getUserIdentity getUserIdentityFunc,
+ resolvers func() entity.Resolvers, getUserIdentity getUserIdentityFunc,
+ makeCached func(entity EntityT, entityUpdated func(id entity.Id) error) CacheT,
+ makeExcerpt func(EntityT) ExcerptT,
+ makeIndex func(CacheT) []string,
typename, namespace string,
- version uint, maxLoaded int) *SubCache[ExcerptT, CacheT, EntityT] {
- return &SubCache[ExcerptT, CacheT, EntityT]{
+ version uint, maxLoaded int) *SubCache[EntityT, ExcerptT, CacheT] {
+ return &SubCache[EntityT, ExcerptT, CacheT]{
repo: repo,
resolvers: resolvers,
getUserIdentity: getUserIdentity,
@@ -65,12 +68,12 @@ func NewSubCache[ExcerptT Excerpt, CacheT CacheEntity, EntityT entity.Interface]
}
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Typename() string {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Typename() string {
return sc.typename
}
// Load will try to read from the disk the entity cache file
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Load() error {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Load() error {
sc.mu.Lock()
defer sc.mu.Unlock()
@@ -97,7 +100,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Load() error {
sc.excerpts = aux.Excerpts
- index, err := sc.repo.GetBleveIndex("bug")
+ index, err := sc.repo.GetIndex(sc.typename)
if err != nil {
return err
}
@@ -115,7 +118,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Load() error {
}
// Write will serialize on disk the entity cache file
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Write() error {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Write() error {
sc.mu.RLock()
defer sc.mu.RUnlock()
@@ -149,19 +152,26 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Write() error {
return f.Close()
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Build() error {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Build() error {
sc.excerpts = make(map[entity.Id]ExcerptT)
sc.readWithResolver
allBugs := bug.ReadAllWithResolver(c.repo, c.resolvers)
+ index, err := sc.repo.GetIndex(sc.typename)
+ if err != nil {
+ return err
+ }
+
// wipe the index just to be sure
- err := c.repo.ClearBleveIndex("bug")
+ err = index.Clear()
if err != nil {
return err
}
+ indexer, indexEnd := index.IndexBatch()
+
for b := range allBugs {
if b.Err != nil {
return b.Err
@@ -170,15 +180,21 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Build() error {
snap := b.Bug.Compile()
c.bugExcerpts[b.Bug.Id()] = NewBugExcerpt(b.Bug, snap)
- if err := c.addBugToSearchIndex(snap); err != nil {
+ if err := indexer(snap); err != nil {
return err
}
}
+ err = indexEnd()
+ if err != nil {
+ return err
+ }
+
_, _ = fmt.Fprintln(os.Stderr, "Done.")
+ return nil
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Close() error {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Close() error {
sc.mu.Lock()
defer sc.mu.Unlock()
sc.excerpts = nil
@@ -187,7 +203,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Close() error {
}
// AllIds return all known bug ids
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) AllIds() []entity.Id {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) AllIds() []entity.Id {
sc.mu.RLock()
defer sc.mu.RUnlock()
@@ -203,7 +219,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) AllIds() []entity.Id {
}
// Resolve retrieve an entity matching the exact given id
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Resolve(id entity.Id) (CacheT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Resolve(id entity.Id) (CacheT, error) {
sc.mu.RLock()
cached, ok := sc.cached[id]
if ok {
@@ -213,12 +229,12 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Resolve(id entity.Id) (CacheT, er
}
sc.mu.RUnlock()
- b, err := sc.readWithResolver(sc.repo, sc.resolvers(), id)
+ e, err := sc.readWithResolver(sc.repo, sc.resolvers(), id)
if err != nil {
return *new(CacheT), err
}
- cached = sc.makeCached(sc, sc.getUserIdentity, b)
+ cached = sc.makeCached(e, sc.entityUpdated)
sc.mu.Lock()
sc.cached[id] = cached
@@ -232,13 +248,13 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Resolve(id entity.Id) (CacheT, er
// ResolvePrefix retrieve an entity matching an id prefix. It fails if multiple
// entity match.
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolvePrefix(prefix string) (CacheT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) ResolvePrefix(prefix string) (CacheT, error) {
return sc.ResolveMatcher(func(excerpt ExcerptT) bool {
return excerpt.Id().HasPrefix(prefix)
})
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveMatcher(f func(ExcerptT) bool) (CacheT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) ResolveMatcher(f func(ExcerptT) bool) (CacheT, error) {
id, err := sc.resolveMatcher(f)
if err != nil {
return *new(CacheT), err
@@ -247,7 +263,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveMatcher(f func(ExcerptT) b
}
// ResolveExcerpt retrieve an Excerpt matching the exact given id
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveExcerpt(id entity.Id) (ExcerptT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) ResolveExcerpt(id entity.Id) (ExcerptT, error) {
sc.mu.RLock()
defer sc.mu.RUnlock()
@@ -261,13 +277,13 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveExcerpt(id entity.Id) (Exc
// ResolveExcerptPrefix retrieve an Excerpt matching an id prefix. It fails if multiple
// entity match.
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveExcerptPrefix(prefix string) (ExcerptT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) ResolveExcerptPrefix(prefix string) (ExcerptT, error) {
return sc.ResolveExcerptMatcher(func(excerpt ExcerptT) bool {
return excerpt.Id().HasPrefix(prefix)
})
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveExcerptMatcher(f func(ExcerptT) bool) (ExcerptT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) ResolveExcerptMatcher(f func(ExcerptT) bool) (ExcerptT, error) {
id, err := sc.resolveMatcher(f)
if err != nil {
return *new(ExcerptT), err
@@ -275,7 +291,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) ResolveExcerptMatcher(f func(Exce
return sc.ResolveExcerpt(id)
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) resolveMatcher(f func(ExcerptT) bool) (entity.Id, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) resolveMatcher(f func(ExcerptT) bool) (entity.Id, error) {
sc.mu.RLock()
defer sc.mu.RUnlock()
@@ -301,14 +317,14 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) resolveMatcher(f func(ExcerptT) b
var errNotInCache = errors.New("entity missing from cache")
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) add(e EntityT) (CacheT, error) {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) add(e EntityT) (CacheT, error) {
sc.mu.Lock()
if _, has := sc.cached[e.Id()]; has {
sc.mu.Unlock()
return *new(CacheT), fmt.Errorf("entity %s already exist in the cache", e.Id())
}
- cached := sc.makeCached(sc, sc.getUserIdentity, e)
+ cached := sc.makeCached(e, sc.entityUpdated)
sc.cached[e.Id()] = cached
sc.lru.Add(e.Id())
sc.mu.Unlock()
@@ -324,7 +340,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) add(e EntityT) (CacheT, error) {
return cached, nil
}
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) Remove(prefix string) error {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) Remove(prefix string) error {
e, err := sc.ResolvePrefix(prefix)
if err != nil {
return err
@@ -349,7 +365,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) Remove(prefix string) error {
}
// entityUpdated is a callback to trigger when the excerpt of an entity changed
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) entityUpdated(id entity.Id) error {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) entityUpdated(id entity.Id) error {
sc.mu.Lock()
b, ok := sc.cached[id]
if !ok {
@@ -376,7 +392,7 @@ func (sc *SubCache[ExcerptT, CacheT, EntityT]) entityUpdated(id entity.Id) error
}
// evictIfNeeded will evict an entity from the cache if needed
-func (sc *SubCache[ExcerptT, CacheT, EntityT]) evictIfNeeded() {
+func (sc *SubCache[EntityT, ExcerptT, CacheT]) evictIfNeeded() {
sc.mu.Lock()
defer sc.mu.Unlock()
if sc.lru.Len() <= sc.maxLoaded {
diff --git a/commands/execenv/env.go b/commands/execenv/env.go
index a63f835a..4b353279 100644
--- a/commands/execenv/env.go
+++ b/commands/execenv/env.go
@@ -128,11 +128,30 @@ func LoadBackend(env *Env) func(*cobra.Command, []string) error {
return err
}
- env.Backend, err = cache.NewRepoCache(env.Repo)
+ var events chan cache.BuildEvent
+ env.Backend, events, err = cache.NewRepoCache(env.Repo)
if err != nil {
return err
}
+ if events != nil {
+ _, _ = fmt.Fprintln(os.Stderr, "Building cache... ")
+ }
+
+ for event := range events {
+ if event.Err != nil {
+ _, _ = fmt.Fprintf(os.Stderr, "Cache building error [%s]: %v\n", event.Typename, event.Err)
+ continue
+ }
+
+ switch event.Event {
+ case cache.BuildEventStarted:
+ _, _ = fmt.Fprintf(os.Stderr, "[%s] started\n", event.Typename)
+ case cache.BuildEventFinished:
+ _, _ = fmt.Fprintf(os.Stderr, "[%s] done\n", event.Typename)
+ }
+ }
+
cleaner := func(env *Env) interrupt.CleanerFunc {
return func() error {
if env.Backend != nil {
diff --git a/entity/resolver.go b/entity/resolver.go
index b2f831d7..9cacbf00 100644
--- a/entity/resolver.go
+++ b/entity/resolver.go
@@ -64,18 +64,18 @@ func (c *CachedResolver) Resolve(id Id) (Interface, error) {
return i, nil
}
-var _ Resolver = ResolverFunc(nil)
+var _ Resolver = ResolverFunc[Interface](nil)
// ResolverFunc is a helper to morph a function resolver into a Resolver
-type ResolverFunc func(id Id) (Interface, error)
+type ResolverFunc[T Interface] func(id Id) (T, error)
-func (fn ResolverFunc) Resolve(id Id) (Interface, error) {
+func (fn ResolverFunc[T]) Resolve(id Id) (Interface, error) {
return fn(id)
}
// MakeResolver create a resolver able to return the given entities.
func MakeResolver(entities ...Interface) Resolver {
- return ResolverFunc(func(id Id) (Interface, error) {
+ return ResolverFunc[Interface](func(id Id) (Interface, error) {
for _, entity := range entities {
if entity.Id() == id {
return entity, nil