github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/git/last_commit_cache_gogit.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 //go:build gogit 7 8 package git 9 10 import ( 11 "context" 12 13 "github.com/gitbundle/modules/log" 14 15 "github.com/go-git/go-git/v5/plumbing/object" 16 cgobject "github.com/go-git/go-git/v5/plumbing/object/commitgraph" 17 ) 18 19 // LastCommitCache represents a cache to store last commit 20 type LastCommitCache struct { 21 repoPath string 22 ttl func() int64 23 repo *Repository 24 commitCache map[string]*object.Commit 25 cache Cache 26 } 27 28 // NewLastCommitCache creates a new last commit cache for repo 29 func NewLastCommitCache(repoPath string, gitRepo *Repository, ttl func() int64, cache Cache) *LastCommitCache { 30 if cache == nil { 31 return nil 32 } 33 return &LastCommitCache{ 34 repoPath: repoPath, 35 repo: gitRepo, 36 commitCache: make(map[string]*object.Commit), 37 ttl: ttl, 38 cache: cache, 39 } 40 } 41 42 // Get get the last commit information by commit id and entry path 43 func (c *LastCommitCache) Get(ref, entryPath string) (interface{}, error) { 44 v := c.cache.Get(c.getCacheKey(c.repoPath, ref, entryPath)) 45 if vs, ok := v.(string); ok { 46 log.Debug("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, vs) 47 if commit, ok := c.commitCache[vs]; ok { 48 log.Debug("LastCommitCache hit level 2: [%s:%s:%s]", ref, entryPath, vs) 49 return commit, nil 50 } 51 id, err := c.repo.ConvertToSHA1(vs) 52 if err != nil { 53 return nil, err 54 } 55 commit, err := c.repo.GoGitRepo().CommitObject(id) 56 if err != nil { 57 return nil, err 58 } 59 c.commitCache[vs] = commit 60 return commit, nil 61 } 62 return nil, nil 63 } 64 65 // CacheCommit will cache the commit from the gitRepository 66 func (c *LastCommitCache) CacheCommit(ctx context.Context, commit *Commit) error { 67 commitNodeIndex, _ := commit.repo.CommitNodeIndex() 68 69 index, err := commitNodeIndex.Get(commit.ID) 70 if err != nil { 71 return err 72 } 73 74 return c.recursiveCache(ctx, index, &commit.Tree, "", 1) 75 } 76 77 func (c *LastCommitCache) recursiveCache(ctx context.Context, index cgobject.CommitNode, tree *Tree, treePath string, level int) error { 78 if level == 0 { 79 return nil 80 } 81 82 entries, err := tree.ListEntries() 83 if err != nil { 84 return err 85 } 86 87 entryPaths := make([]string, len(entries)) 88 entryMap := make(map[string]*TreeEntry) 89 for i, entry := range entries { 90 entryPaths[i] = entry.Name() 91 entryMap[entry.Name()] = entry 92 } 93 94 commits, err := GetLastCommitForPaths(ctx, c, index, treePath, entryPaths) 95 if err != nil { 96 return err 97 } 98 99 for entry := range commits { 100 if entryMap[entry].IsDir() { 101 subTree, err := tree.SubTree(entry) 102 if err != nil { 103 return err 104 } 105 if err := c.recursiveCache(ctx, index, subTree, entry, level-1); err != nil { 106 return err 107 } 108 } 109 } 110 111 return nil 112 }