132 lines
3.6 KiB
Go
132 lines
3.6 KiB
Go
|
package commitgraph
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"time"
|
||
|
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/format/commitgraph"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/storer"
|
||
|
)
|
||
|
|
||
|
// graphCommitNode is a reduced representation of Commit as presented in the commit
|
||
|
// graph file (commitgraph.Node). It is merely useful as an optimization for walking
|
||
|
// the commit graphs.
|
||
|
//
|
||
|
// graphCommitNode implements the CommitNode interface.
|
||
|
type graphCommitNode struct {
|
||
|
// Hash for the Commit object
|
||
|
hash plumbing.Hash
|
||
|
// Index of the node in the commit graph file
|
||
|
index int
|
||
|
|
||
|
commitData *commitgraph.CommitData
|
||
|
gci *graphCommitNodeIndex
|
||
|
}
|
||
|
|
||
|
// graphCommitNodeIndex is an index that can load CommitNode objects from both the commit
|
||
|
// graph files and the object store.
|
||
|
//
|
||
|
// graphCommitNodeIndex implements the CommitNodeIndex interface
|
||
|
type graphCommitNodeIndex struct {
|
||
|
commitGraph commitgraph.Index
|
||
|
s storer.EncodedObjectStorer
|
||
|
}
|
||
|
|
||
|
// NewGraphCommitNodeIndex returns CommitNodeIndex implementation that uses commit-graph
|
||
|
// files as backing storage and falls back to object storage when necessary
|
||
|
func NewGraphCommitNodeIndex(commitGraph commitgraph.Index, s storer.EncodedObjectStorer) CommitNodeIndex {
|
||
|
return &graphCommitNodeIndex{commitGraph, s}
|
||
|
}
|
||
|
|
||
|
func (gci *graphCommitNodeIndex) Get(hash plumbing.Hash) (CommitNode, error) {
|
||
|
// Check the commit graph first
|
||
|
parentIndex, err := gci.commitGraph.GetIndexByHash(hash)
|
||
|
if err == nil {
|
||
|
parent, err := gci.commitGraph.GetCommitDataByIndex(parentIndex)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &graphCommitNode{
|
||
|
hash: hash,
|
||
|
index: parentIndex,
|
||
|
commitData: parent,
|
||
|
gci: gci,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// Fallback to loading full commit object
|
||
|
commit, err := object.GetCommit(gci.s, hash)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &objectCommitNode{
|
||
|
nodeIndex: gci,
|
||
|
commit: commit,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) ID() plumbing.Hash {
|
||
|
return c.hash
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) Tree() (*object.Tree, error) {
|
||
|
return object.GetTree(c.gci.s, c.commitData.TreeHash)
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) CommitTime() time.Time {
|
||
|
return c.commitData.When
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) NumParents() int {
|
||
|
return len(c.commitData.ParentIndexes)
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) ParentNodes() CommitNodeIter {
|
||
|
return newParentgraphCommitNodeIter(c)
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) ParentNode(i int) (CommitNode, error) {
|
||
|
if i < 0 || i >= len(c.commitData.ParentIndexes) {
|
||
|
return nil, object.ErrParentNotFound
|
||
|
}
|
||
|
|
||
|
parent, err := c.gci.commitGraph.GetCommitDataByIndex(c.commitData.ParentIndexes[i])
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &graphCommitNode{
|
||
|
hash: c.commitData.ParentHashes[i],
|
||
|
index: c.commitData.ParentIndexes[i],
|
||
|
commitData: parent,
|
||
|
gci: c.gci,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) ParentHashes() []plumbing.Hash {
|
||
|
return c.commitData.ParentHashes
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) Generation() uint64 {
|
||
|
// If the commit-graph file was generated with older Git version that
|
||
|
// set the generation to zero for every commit the generation assumption
|
||
|
// is still valid. It is just less useful.
|
||
|
return uint64(c.commitData.Generation)
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) Commit() (*object.Commit, error) {
|
||
|
return object.GetCommit(c.gci.s, c.hash)
|
||
|
}
|
||
|
|
||
|
func (c *graphCommitNode) String() string {
|
||
|
return fmt.Sprintf(
|
||
|
"%s %s\nDate: %s",
|
||
|
plumbing.CommitObject, c.ID(),
|
||
|
c.CommitTime().Format(object.DateFormat),
|
||
|
)
|
||
|
}
|