Skip to content

Commit

Permalink
fix: cache git trees and commits
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed Feb 17, 2022
1 parent 4392caa commit 8fa4404
Showing 1 changed file with 50 additions and 37 deletions.
87 changes: 50 additions & 37 deletions internal/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type Repo struct {
refCommits map[plumbing.Hash]gitypes.Commits
head *plumbing.Reference
refs []*plumbing.Reference
trees map[plumbing.Hash]*object.Tree
commits map[plumbing.Hash]*object.Commit
}

// GetName returns the name of the repository.
Expand All @@ -46,6 +48,7 @@ func (r *Repo) SetHEAD(ref *plumbing.Reference) error {
return nil
}

// GetReferences returns the references for a repository.
func (r *Repo) GetReferences() []*plumbing.Reference {
return r.refs
}
Expand All @@ -62,11 +65,11 @@ func (r *Repo) Tree(ref *plumbing.Reference, path string) (*object.Tree, error)
if err != nil {
return nil, err
}
c, err := r.repository.CommitObject(hash)
c, err := r.commitForHash(hash)
if err != nil {
return nil, err
}
t, err := c.Tree()
t, err := r.treeForHash(c.TreeHash)
if err != nil {
return nil, err
}
Expand All @@ -76,6 +79,32 @@ func (r *Repo) Tree(ref *plumbing.Reference, path string) (*object.Tree, error)
return t.Tree(path)
}

func (r *Repo) treeForHash(treeHash plumbing.Hash) (*object.Tree, error) {
var err error
t, ok := r.trees[treeHash]
if !ok {
t, err = r.repository.TreeObject(treeHash)
if err != nil {
return nil, err
}
r.trees[treeHash] = t
}
return t, nil
}

func (r *Repo) commitForHash(hash plumbing.Hash) (*object.Commit, error) {
var err error
co, ok := r.commits[hash]
if !ok {
co, err = r.repository.CommitObject(hash)
if err != nil {
return nil, err
}
r.commits[hash] = co
}
return co, nil
}

// GetCommits returns the commits for a repository.
func (r *Repo) GetCommits(ref *plumbing.Reference) (gitypes.Commits, error) {
hash, err := r.targetHash(ref)
Expand All @@ -87,23 +116,19 @@ func (r *Repo) GetCommits(ref *plumbing.Reference) (gitypes.Commits, error) {
if ok {
return commits, nil
}
log.Printf("caching commits for %s/%s: %s", r.name, ref.Name(), ref.Hash())
commits = gitypes.Commits{}
co, err := r.repository.CommitObject(hash)
co, err := r.commitForHash(hash)
if err != nil {
return nil, err
}
// traverse the commit tree to get all commits
commits = append(commits, &gitypes.Commit{Commit: co})
for {
co, err = co.Parent(0)
commits = append(commits, co)
for co.NumParents() > 0 {
co, err = r.commitForHash(co.ParentHashes[0])
if err != nil {
if err == object.ErrParentNotFound {
err = nil
}
break
return nil, err
}
commits = append(commits, &gitypes.Commit{Commit: co})
commits = append(commits, co)
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -136,31 +161,6 @@ func (r *Repo) targetHash(ref *plumbing.Reference) (plumbing.Hash, error) {
return hash, nil
}

// loadCommits loads the commits for a repository.
func (r *Repo) loadCommits(ref *plumbing.Reference) (gitypes.Commits, error) {
commits := gitypes.Commits{}
hash, err := r.targetHash(ref)
if err != nil {
return nil, err
}
l, err := r.repository.Log(&git.LogOptions{
Order: git.LogOrderCommitterTime,
From: hash,
})
if err != nil {
return nil, err
}
defer l.Close()
err = l.ForEach(func(c *object.Commit) error {
commits = append(commits, &gitypes.Commit{Commit: c})
return nil
})
if err != nil {
return nil, err
}
return commits, nil
}

// GetReadme returns the readme for a repository.
func (r *Repo) GetReadme() string {
if r.Readme != "" {
Expand Down Expand Up @@ -265,6 +265,8 @@ func (rs *RepoSource) loadRepo(name string, rg *git.Repository) (*Repo, error) {
name: name,
repository: rg,
}
r.commits = make(map[plumbing.Hash]*object.Commit)
r.trees = make(map[plumbing.Hash]*object.Tree)
r.refCommits = make(map[plumbing.Hash]gitypes.Commits)
ref, err := rg.Head()
if err != nil {
Expand All @@ -276,6 +278,17 @@ func (rs *RepoSource) loadRepo(name string, rg *git.Repository) (*Repo, error) {
return nil, err
}
r.Readme = rm
l, err := r.repository.Log(&git.LogOptions{All: true})
if err != nil {
return nil, err
}
err = l.ForEach(func(c *object.Commit) error {
r.commits[c.Hash] = c
return nil
})
if err != nil {
return nil, err
}
refs := make([]*plumbing.Reference, 0)
ri, err := rg.References()
if err != nil {
Expand Down

0 comments on commit 8fa4404

Please sign in to comment.